C Waitpid的动作就像在非阻塞模式下一样

C Waitpid的动作就像在非阻塞模式下一样,c,operating-system,system-calls,pid,waitpid,C,Operating System,System Calls,Pid,Waitpid,我在玩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 {

我在玩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(“此处”)
exit(1)
,并按照注释中的建议打印出了waitpid的输出。此处不打印,等待PID打印-1

问题在于竞争条件。在这里的叉子后面:

a = fork();
如果子进程首先运行,则在此处创建进程组
-a

if(a==0){
    setpgid(getpid(),getpid());
然后家长在这里等待:

waitpid(-a,&t2,0);
但是如果父进程首先运行,进程组
-a
还不存在,并且
waitpid()
会因
ECHILD
而失败。第二种情况显然发生在您的系统上


您必须找到某种方法来确保子对象中的
setpgid()
调用在父对象中的
waitpid()
调用之前运行。复杂的方法是信号量,简单的方法是短延迟,
usleep(1)
waitpid()
可能就足够了。

你确定你的exec()调用成功了吗?添加呼叫退出(1);紧接着,如果失败了……首先检查
waitpid
返回的内容。如果返回零,则检查
t2的值以了解子进程的退出代码。别忘了检查
execvp
是否也返回。我试着按照你们的建议做了。控制流不在execvp下方,waitpid返回-1。如果
waitpid()
返回-1,您应该打印出
errno
,查看失败原因(
peror()
strerror()
可用于获取人类可读的错误消息,而不是神秘的数字)