我正在看书Unix 环境中的高级编程。有一个测试程序可以测试该fork
功能。它在我的 Ubuntu 上运行良好。但令我困惑的是,为什么子进程退出后没有命令指示符提示。原来的程序如下所示。
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
if ((pid = fork()) < 0)
{
printf("fork error.\n");
return 1;
}
else if (pid == 0)
{
if ((pid = fork()) < 0)
{
printf("fork error.\n");
return 1;
}
else if (pid > 0)
{
printf("first child %d exit.\n", getpid());
exit(0);
}
sleep(2);
printf("second child %d has parent pid = %d.\n",getpid(), getppid());
exit(0);
}
printf("waitid %d.\n", pid);
if (waitpid(pid, NULL, 0) != pid)
{
printf("waitid error.\n");
return 1;
}
printf("process %d will exit..\n", getpid());
exit(0);
}
然后我跑
jerryli@ubuntu:~/project/unix$ ./p183.o
waitid 2256
first child 2256 exit.
process 2255 will exit..
jerryli@ubuntu:~/project/unix$ second child 2257 has parent pid = 1.
上面一行提示后,没有任何继续。我希望它会显示
jerryli@ubuntu:~/project/unix$
为了获得上述指标,我必须输入Enter.
你能知道原因吗?是因为第二个子进程的父进程变成了系统init进程吗?
答案1
fork
在后台启动一个进程。当前台进程(调用 的进程fork
)终止时,调用 shell 会收到通知,并显示一个新的提示符。 shell 是原始前台进程的父进程;它不是任何一个分叉进程的父进程。
原始进程和分叉进程的执行顺序并不固定,但由于 2 秒的延迟,不太可能出现任何相关的偏差。在您的测试中,时间线恰好是:
fork
原始进程中的第一个子进程。fork
第一个孩子中的第二个孩子。- 原始进程打印
waitid
跟踪并开始waitpid
调用以等待第一个子进程。 - 第一个子进程打印其
exit
踪迹,然后退出。 - 原始进程收到子进程死亡的通知,并且其
waitpid
调用返回。 - 原始进程打印其
will exit
痕迹。 - shell 会收到原始进程已退出的通知并打印其提示符。
- 不到 2 秒后,
sleep
第二个子级中的调用完成,第二个子级打印其has parent
跟踪。
shell 不会收到关于最后事件的任何通知,因为它不是终止进程的父进程。无论如何,它已经显示了一个提示符,正在等待您输入新命令;它没有理由做任何事情(如果您正在输入命令,这可能会造成干扰)。
答案2
按照@Gilles的回答,我打算实现与@jerry要求类似的事情:1.在分叉之前存储终端PID 2.在每组打印之后发送SIGINT以“推动”终端以显示提示
很脏,但似乎可以完成工作