当我绘制图表时,我写道可能的输出可能是3020140,1203040,2013040,1302040或3012040.当我运行它时,输出为201.发生了什么?程序怎么可能永远不会达到3,等待条件会发生什么?我认为等待意味着调用过程不会继续,直到子进程完成,这意味着它总是在输出结束时。
int main() {
if (fork() != 0) {
if (fork() == 0) {
printf("3");
}
else {
pid_t pid ;
int status ;
if ((pid = wait(&status)) > 0) {
printf("4");
}
}
}
else {
if (fork() == 0) {
printf("1");
exit (0);
}
printf("2");
}
printf("0");
return 0;
}
答案 0 :(得分:1)
一个观察结果:print语句中完全缺少换行符意味着只有在进程终止时才刷新输出。这使得查看正在发生的事情变得更加困难。因为当进程退出时将刷新字符,所以一个非零数字及其跟随零通常会一起出现。
表面上看,30应该出现在40之前。但是,先死的孩子可能是控制1和20打印的孩子,在这种情况下,40可以出现在打印30之前。请注意,wait()
函数在返回之前只等待一个孩子死亡,这与shell命令wait
不同,没有参数等待所有孩子死亡。
不保证1的相对排序(后面不会跟0)和20,并且不能保证30,40的排序与1和20相比。如果代码无法打印3,如果在它失败之前的分叉。
当我运行未经修改的代码几次(我称之为程序f7
)时,我得到了输出:
$ ./f7;echo
2040
301$ ./f7;echo
3020140
$ ./f7;echo
203040
1$ ./f7;echo
2030140
$ ./f7;echo
2013040
$
这表明测序相当随意。有时,在一些孩子面前完成了回声。
请注意,第一次运行显示40出现在30或1之前;我甚至不必选择我所展示的那些跑步。该机器恰好是运行Ubuntu 14.04衍生产品的基于英特尔的12核心机器,因此有很多内核可供子进程使用。
我要做的第一件事就是添加许多诊断打印(使用换行符)来识别发生在哪里的事情。这意味着每个输出都包含PID。各种父进程将识别其子女的PID; wait
将报告报告为死亡的PID。在每次打印操作结束时,使用换行符将检测写入标准错误。输出也与最初的标准输出相呼应。我将此代码保存在f11.c
中,因此将其作为./f11
运行:
#include "posixver.h"
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
static void print(const char *number)
{
fprintf(stderr, "[%d:%s]\n", (int)getpid(), number);
printf("%s", number);
}
int main(void)
{
pid_t pid;
fprintf(stderr, "[%d:initial]\n", (int)getpid());
if ((pid = fork()) != 0)
{
fprintf(stderr, "[%d:parent-1;child=%d]\n",
(int)getpid(), (int)pid);
if ((pid = fork()) == 0)
{
print("3");
}
else
{
fprintf(stderr, "[%d:parent-2;child=%d]\n",
(int)getpid(), (int)pid);
int status;
if ((pid = wait(&status)) > 0)
{
fprintf(stderr, "[%d:corpse=%d;status=0x%.4X]\n",
(int)getpid(), (int)pid, status);
print("4");
}
}
}
else
{
fprintf(stderr, "[%d:child]\n", (int)getpid());
if ((pid = fork()) == 0)
{
print("1");
exit(0);
}
fprintf(stderr, "[%d:parent-3;child=%d]\n", (int)getpid(), (int)pid);
print("2");
}
print("0");
return 0;
}
示例运行:
$ ./f11;echo
[6781:initial]
[6781:parent-1;child=6782]
[6782:child]
[6781:parent-2;child=6783]
[6782:parent-3;child=6784]
[6782:2]
[6782:0]
[6784:1]
201[6783:3]
[6781:corpse=6782;status=0x0000]
[6781:4]
[6783:0]
[6781:0]
4030
$
如果没有标准错误,输出序列将为2014030。
请注意,我总是看到完整的输出(20
,30
,40
和1
)。如果你错过了一些输出,可能是因为你的PS1
提示覆盖了它(这需要一个不寻常但不是不可能的PS1值,包括回车)。