我有如下所示的C源代码。
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
#include<sys/types.h>
int main(void) {
pid_t process_id;
int status;
if (fork() == 0)
{
if (fork() == 0)
{
printf("A");
} else {
process_id = wait(&status);
printf("B");
}
} else {
if (fork() == 0)
{
printf("C");
exit(0);
}
printf("D");
}
printf("0");
return 0;
}
当我在终端中执行它时,在此图像中出现了一些输出:
我实际上很困惑这些输出是如何生成的,例如,如何生成D0A0〜$ B0C。
谁能向我解释这些输出是如何生成的,以及在此代码中退出(0)吗?
通常,如果您有这样的代码
if (fork() == 0) {
printf("I'm a child\n");
} else {
printf("I'm a parent\n");
}
printf("This part is common\n");
然后,将在子进程中执行fork()结果为零的if分支,而在父进程中执行非零分支。之后,将继续在两个进程中执行(仍然异步),因此子级和父级都将在if之后执行代码。我们可以用图形表示它,如下图,显示将在每个分支中执行的代码:
fork()
/ \
------- parent ---------- ---------- child -----------
| |
| |
printf("I'm a parent\n"); printf("I'm a child\n");
printf("This part is common\n"); printf("This part is common\n");
现在,让我们为您的代码制作相同的图。在第一个fork之后,如果满足以下条件,则根据最顶层划分执行:
fork() / \ --------- parent --------- ---------- child ------------- | | | | if (fork() == 0) if (fork() == 0) { { printf("C"); printf("A"); exit(0); } else { } process_id = wait(&status); printf("D"); printf("B"); } // Common code // Common code printf("0"); printf("0"); return 0; return 0;
在父级和子级中执行了下一个派生之后,我们将获得以下树结构:
fork() / \ ---- parent ------ ------ child ------ | | fork() fork() / \ / \ --- parent --- --- child --- --- parent --- --- child ---- | | | | | | | | printf("D"); printf("C"); process_id = wait(&status); printf("A"); exit(0); printf("B"); printf("D"); printf("0"); printf("0"); printf("0"); printf("0"); return 0; return 0; return 0; return 0;
注意,printf(“ D”);在
if(fork()==0){}
之后,这实际上是这两个分支中的通用代码。那时所有4个进程都异步执行。
父/母进程打印“ D”,然后是“ 0”,然后退出
父子进程打印“ C”,然后退出
父级进程等待其子级完成,然后打印“ B”,然后打印“ 0”并退出
子进程打印“ A”,然后“ 0”然后退出
如您所见,这些过程的输出几乎可以任意交织,唯一的保证是在子父过程打印“ B0”之前,子子过程打印“ A0”。在主进程(父父进程)完成后,用于运行程序的Shell将重新获得控件。但是,当控件返回到Shell时,仍然可能有其他进程在运行,因此某些进程的输出可能会在Shell输出其命令提示符后出现。例如,以下事件链是可能的:
parent-parent获取控件。它显示“ D0”并退出,该控件返回到shell。
子父进程获取控件。它开始等待(阻止)子进程。
子进程获得控件。它显示“ A0”并退出。
同时shell进程获取控件并打印命令提示符“〜$”
父级进程得到控制。由于子进程已完成,因此将取消阻止,打印“ B0”并退出。
父子进程获取控件,打印“ C”并退出。
组合输出为“ D0A0〜$ B0C”。它说明了示例的最后一行。