我试图更好地了解fork(),waitpid()和子进程/父进程,但是以下代码遇到一些奇怪的行为:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void){ // Main
int status;
pid_t wPID, cPID;
printf("[%i] Hi I am the parent and I am about to create a child...\n", getpid());
fflush(0);
pid_t childPID = fork();
if (childPID >= 0){
if(childPID == 0){ //child process
cPID = getpid();
printf("[%i] %i\n", getpid(), cPID );
printf("[%i] Hi, I am the child process...\n", getpid() );
sleep(1);
for(int i = 0; i<3; i++){
printf("[%i] %i\n", getpid(), i);
}
exit(0);
}
else{ //parent
printf("[%i] %i\n", getpid(), cPID );
wPID = waitpid(cPID, &status, 0);
printf("[%i] value returned by waitpid: %i\n", getpid(), wPID);
if (WIFEXITED(status))
printf("[%i] child exited, status=%d\n", getpid(), WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("[%i] child killed (signal %d)\n", getpid(), WTERMSIG(status));
else if (WIFSTOPPED(status))
printf("[%i] child stopped (signal %d)\n", getpid(), WSTOPSIG(status));
else /* Non-standard case -- may never happen */
printf("Unexpected status (0x%x)\n", status);
return 0;
}
}
else{
printf("\n Fork failed, quitting!\n");
return 2; // error
}
}
Run Code Online (Sandbox Code Playgroud)
控制台输出:
$ ./waitpidexample [6103]嗨,我是父母,我即将创建一个孩子... 错误:没有子进程 [6103] 1540418008 [6103] waitpid返回的值:-1 [6103]儿童被杀(信号54) [6104] 6285 [6104]嗨,我是孩子进程... [6104] 0 [6104] 1 [6104] 2
我相信我的问题是在waitpid()中使用了cPID变量...
这里会发生某种范围问题,因为它会评估子项/父项中的不同值。
我应该如何获取在waitpid()中使用的正确子进程ID?
为什么在waitpid()之后的代码在子进程中的代码之前执行?
cPID
仅在子进程中更改。当您调用fork时,将创建完整的副本(实际上,实际上是在更改某些内容之前,共享内存)。这意味着当cPID
写入子级(第一个分支)时,父级看不到它。cPID
将父级(第二个分支)中对的引用更改为childPID
(从分配fork()
):
else{ //parent
printf("[%i] %i\n", getpid(), childPID );
wPID = waitpid(childPID, &status, 0);
printf("[%i] value returned by waitpid: %i\n", getpid(), wPID);
if (WIFEXITED(status))
printf("[%i] child exited, status=%d\n", getpid(), WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("[%i] child killed (signal %d)\n", getpid(), WTERMSIG(status));
else if (WIFSTOPPED(status))
printf("[%i] child stopped (signal %d)\n", getpid(), WSTOPSIG(status));
else /* Non-standard case -- may never happen */
printf("Unexpected status (0x%x)\n", status);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
另外,我建议在所有if
语句后都使用大括号
fork()
并没有定义首先运行哪个进程,只是现在有一个子进程(在其中返回0)和一个父进程(在其中返回孩子的PID)。子进程将与父进程相同,但返回值为fork()
。有时,父母先走,有时孩子先走。它是不确定的。