如何解决有人可以解释 fork() 吗?
有人能解释一下 fork()
并举例说明它的用法吗?
我从一些在线资源中了解到的是:
- fork() 创建一个子进程,其运行方式与父进程相同。
- 将创建 2^n 个进程,n = fork() 的数量。
- 子进程的 ID 将始终为 0,而父进程的 ID 将是其他内容 - 正整数 != 0。
我还有一个问题,首先请看我下面的代码:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int id = fork();
int i = 45;
fork();
fork();
if(id == 0) {
printf("\nChild Process id = %d",id);
printf("\ni = %d ; i = %d",i++,i);
}
else {
printf("\nParent Process id = %d",i,i+2);
}
return 0;
}
/*
O/P:
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
*/
为什么最后一个子进程不显示第二个 printf() 即,
printf("\ni = %d ; i = %d",i);
你能解释一下为什么第二个 printf() 没有被执行而第一个 printf() 被执行了 8 次 - 子进程。
解决方法
fork 的正确用法意味着立即测试当前进程是子进程(fork 返回 0)还是父进程(fork 返回子进程的 pid),并相应地采取行动。在您的情况下,父母和孩子都启动了一对或虚假的进程,它们将无法知道它们是什么,因为返回的值被忽略。其中一些会认为它们是父进程。
通常子进程会执行一个新的可执行文件,如果需要做一些严肃的事情。
,fork() 创建与父进程运行相同的子进程。
没错。 fork() 创建一个子进程,它是它的父进程的副本。
将创建 2^n 个进程,n = fork() 的数量。
取决于代码!
int i = 0;
while (i < n)
{
fork();
i++;
}
这里,假设没有 fork() 失败,那么是的,会有 2^n 个进程。
子进程的 ID 将始终为 0,而父进程的 ID 将是其他东西 - 正整数 != 0。
子进程的fork() 返回值为0!不是id,而是返回值! 父进程fork()的返回值是子进程的实际pid。
现在到你的代码
1. int main() {
2. int id = fork();
3. int i = 45;
4. fork();
5. fork();
6. if(id == 0) {
7. printf("\nChild Process id = %d",id);
8. printf("\ni = %d ; i = %d",i++,i);
9. }
10. else {
11. printf("\nParent Process id = %d",id);
12. printf("\ni = %d ; i = %d",i,i+2);
13. }
14. return 0;
15. }
在第 4 行,有 2 个进程
parent | child_1
id > 0 | id == 0
i == 45 | i == 45
现在调用一个fork
parent | child_1 | child_OF_1 | child_2
id > 0 | id == 0 | id == 0 | id > 0
i == 45 | i == 45 | i == 45 | i == 45
child_1
和 child_OF_1
将有 id == 0
并输入 if 语句,而
child_2
和 parent
将转到 else 语句并打印 47
我忽略了第 3 个 fork(),那时你有 8 个进程,其中 4 个将进入 if 语句,而其他将进入 else 块。这就是为什么 你看
i = 45 ; i = 47
4 次!
,您期望的所有输出都在那里,只是您在后台将其写出而无需终止换行。这意味着某些输出可能会被 shell 提示过早出现并出现在程序输出的中间而被掩盖或覆盖。
要确切了解这是如何实现的,以下是您程序中某些进程的 strace
输出:
3215092 write(1,"\n",1) = 1
3215092 write(1,"Child Process id = 0\n",21) = 21
3215092 write(1,"i = 45 ; i = 46",15) = 15
3215094 write(1,1) = 1
3215094 write(1,21) = 21
3215094 write(1,15) = 15
这里是 Zsh 如何绘制它的提示。首先是缺少换行指示符,然后是提示本身。特别注意,提示以 \r
开头,回车:
3215036 write(10,"\33[1m\33[3m%\33[23m\33[1m\33[0m "...,306) = 306
3215036 write(10,"\r\33[0m\33[23m\33[24m\33[Jmyhostname.i"...,34) = 34
由于您在后台对写入终端的进程进行分叉,因此所有分叉的进程都在与 Zsh 竞争以写入其输出。
这是一种可能的、有效的排序,这可能导致:
1. 3215036 write(10,306) = 306
2. 3215092 write(1,1) = 1
3. 3215092 write(1,21) = 21
4. 3215092 write(1,15) = 15
5. 3215094 write(1,1) = 1
6. 3215094 write(1,21) = 21
7. 3215094 write(1,15) = 15
8. 3215036 write(10,34) = 34
第 1-7 步发生得相当顺利,结果是这样的屏幕(光标标有 |
):
[...]
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46|
由于没有终止换行符,光标在最后一个字符串之后而不是在最后一个字符串之下。
现在,正如你在写 8
中看到的,Zsh 以一个前导回车开始它的默认提示。这意味着将转到行首:
[...]
i = 45 ; i = 46
Child Process id = 0
|i = 45 ; i = 46
然后继续用提示覆盖该行:
[...]
i = 45 ; i = 46
Child Process id = 0
myhostname.internal%
实际上,即使输出的最后一行被写入屏幕,Zsh 提示通过使用回车符覆盖它来有效地擦除它。
您可以使用重定向来输出到文件,以便更清楚地看到您的程序产生的输出:
./foo > myfile
在编辑器中打开文件显示您的预期结果:
Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
您可以类似地添加自己的终止换行符和延迟以在终端中显示输出:
./foo; sleep 5; echo
这给出了与上面相同的结果。
正确的程序会输出换行符after 而不是before 行,并且会为每个子进程wait()
。 (请注意,如果您只修复其中一个,而保留另一个,则它将不起作用)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。