Waitpid 就像在非阻塞模式下一样

Waitpid acting as if in non-blocking mode

我正在使用 C 语言进行系统调用,但我一直在试图理解我编写的这个程序 -

int main(int argc, char* argv[])
{
int a;
char *args[]={"sleep"," 10",NULL}; 

a = fork();
int stat;


if(a==0){
    setpgid(getpid(),getpid());
    printf("%d\n",getpgid(getpid()));
    execvp(args[0],args);}
else
{
    int t2;
    waitpid(-a,&t2,0);
}

printf("Parent pid = %d\n", getpid()); 
printf("Child pid = %d\n", a); 

}

按照我的理解,我把child的pgid设置成了自己的pid。当我使用 -a 作为参数调用 waitpid 时,我基本上是要求它等待(阻塞)直到 pgid=a 中的任何进程完成。然而,程序的输出并不是我所期望的!子进程根本没有被收割。就好像 waitpid 处于非阻塞模式。输出:

Parent pid = 11372
Child pid = 11373
11373

(瞬时输出,不等10秒!)

编辑:我在 execvp 下面添加了 printf("Here")exit(1),并按照评论中的建议打印出 waitpid 的输出。这里没有打印,waitpid 打印 -1

问题是竞争条件。在这里分叉后:

a = fork();

如果 child 运行 首先在此处创建进程组 -a

if(a==0){
    setpgid(getpid(),getpid());

然后 parent 在这里等待:

waitpid(-a,&t2,0);

但是如果 parent 首先到达 运行,则进程组 -a 不会 还存在并且 waitpid() 失败并返回 ECHILD。第二种情况显然发生在您的系统上。

您必须找到一些方法来确保 setpgid() 在 child 运行 之前 waitpid() 在 parent 中调用。复杂的方式是信号量,简单的(hacky)方式是短暂的延迟,waitpid() 之前的 usleep(1) 可能就足够了。