gpt4 book ai didi

c - 在下面的示例中,如何等待每个进程终止?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:48:24 25 4
gpt4 key购买 nike

程序在从scanf中获取4或5个值后终止。
但我希望它接受8个值(总共8个进程),然后终止。

void main() {
fork();
fork();
fork();

scanf("%d",&j);
printf("The values are %d\n",j);

wait(0);
}

最佳答案

好吧,你要回答的第一个问题是你认为自己有多少个过程?由于您不使用fork(2)系统调用返回的值,因此即使您是父级还是子级,在执行每个fork之后也不知道。
在故事的开头有一个进程,它执行fork(2)系统调用并转换为两个进程,然后执行(父进程和子进程)第二个fork(2)调用,在第二个调用返回时转换为两个进程(两个以上,总共四个)。接下来是第三个,它再次复制了进程的数量,因此在故事的结尾,您将得到在二叉树执行历史层次结构中总共8个运行的进程,这个层次结构填充到了高度3。
但过程关系不一样
每一个过程对于他们自己的孩子来说都可以wait(2),但是也有一些过程,因为他们的婚礼已经变成了三个,两个,一个,或者根本没有fork()。根节点是唯一一个生成三个fork()s的节点,因此它最多可以不出错地生成三个wait(2)s(对于每个子节点),第一个子节点只生成两个,第二个子节点只生成一个…这样地:

proc[0]---fork()-----fork()---fork()----exit();
| | |
| | proc[3]---exit();
| |
| proc[2]--fork()----exit();
| |
| proc[4]---exit();
|
proc[1]----fork()---fork()----exit();
| |
| proc[5]---exit();
|
proc[6]--fork()----exit();
|
proc[7]---exit();

所以
proc[0]可以 wait(2)proc[1]proc[2]proc[3]
proc[1]可以 wait(2)proc[5]proc[6]
proc[2]只能 wait(2)proc[4]
proc[3]不能 wait(2)(调用 wait(2)将导致错误);
proc[4]不能 wait(2)
proc[5]不能 wait(2)
proc[6]只能 wait(2)
proc[7]不能 proc[7]
由于 wait(2)只能等待其中一个子进程(子进程必须使用fork创建,否则调用将导致错误),因此必须发出与已发出的 wait(2)一样多的 wait(2)调用,才能等待所有子进程,因此必须控制已发出的子进程数(如您所见,每个进程的子进程数都不同)。例如,您可以在父进程(从 fork(2)接收 0结果的进程)中增加一个计数器,这样您就知道到目前为止发出的 fork(2)数量。
int main()
{
int forks_made = 0;
if (fork() > 0) forks_made++;
if (fork() > 0) forks_made++;
if (fork() > 0) forks_made++;
for (i = 0; i < forks_made; i++) wait(NULL);
exit(0);
}

或者简单地说,您可以 fork(2)直到系统调用导致错误(您没有更多的子级)
int main()
{
fork();
fork();
fork();
while(wait(NULL) == 0)
continue;
exit(0);
}

注意,进程层次结构与二进制历史树不同。流程层次结构如下:
proc[0]
|
+--proc[1]
| |
| +--proc[5]
| |
| `--proc[6]
| |
| `--proc[7]
|
+--proc[2]
| |
| `--proc[4]
|
`--proc[3]

假设我编写了以下代码:
int main()
{
fork(); fork(); fork();
wait(0); wait(0); wait(0);
exit(0);
}

结果是:
                                ok             ok         ok
p[0]-f()-f()-f()----------------w()------------w()--------w()-exit();
| | | ^ ^ ^
| | | err err err | | |
| | +-p[3]-w()-w()-w()-exit(); | |
| | | |
| | ok err err | |
| +-p[2]-f()----------------w()-w()-w()-exit(); |
| | ^ |
| | | |
| | err err err | |
| +-p[4]-w()-w()-w()-exit(); |
| ok ok err |
+-p[1]-f()-f()----------------w()------------w()-w()-exit();
| | ^ ^
| | err err err | |
| +-p[5]-w()-w()-w()-exit(); |
| ok err err |
+-p[6]-f()----------------w()-w()-w()-exit();
| ^
| err err err |
+-p[7]-w()-w()-w()-exit();

注意
即使子进程在父进程执行 wait(2)之前死亡,内核也会将它们作为僵尸进程保存在进程表中(但没有分配任何资源),只是等待父进程执行正确的 wait(2)系统调用。这就是为什么内核知道您可以执行 wait(2)或不执行 wait(2)的原因(仅当您已执行 fork(2)时才能等待)。
注2
为什么这个过程只是结果和结束的一部分?嗯,我读了一些文档并做了一些测试,在我测试过的三个操作系统上,它们的行为是不同的:
macos x.i已经测试过,当进程组领导 read(2)s时,它的所有子进程都从 exit(2)调用中唤醒,并给出一个 read(2)错误(令人惊讶)
弗里伯斯。在freebsd上,结果相似,但有不同的错误( ETIMEDOUT)。
Linux系统。在linux上,终端驱动程序在raw模式下只给每个进程一个输入字符(即使有更多的字符),这是迄今为止最奇怪的行为。
由于正常的作业控制使shell重新获取控制终端,而进程组不再是终端设备的控制组,因此终端应该用错误代码唤醒所有试图从中 EIO的进程,因此freebsd可能是我们应该得到的最一致的结果。
用于测试此情况的代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

void hndlr(int sig)
{
printf("%d(prnt=%d,pgrp=%d): signal %d received\n",
getpid(), getppid(), getpgrp(), sig);
}

int main()
{
int i;
char line[1024];

for (i = 1; i < 64; i++)
signal(i, hndlr);
printf("pid=%d, pgrp=%d\n", getpid(), getpgrp());
fork();
fork();
fork();
i = read(0, line, sizeof line);
switch(i) {
case -1:
printf("pid=%d, prnt=%d, pgrp=%d: read: %s(errno=%d)\n",
getpid(), getppid(), getpgrp(), strerror(errno), errno);
break;
case 0:
printf("pid=%d, prnt=%d, pgrp=%d: read: EOF\n",
getpid(), getppid(), getpgrp());
break;
default:
printf("pid=%d, prnt=%d, pgrp=%d: read: [%*.*s]\n",
getpid(), getppid(), getpgrp(), i, i, line);
break;
}
#if 0
wait(NULL);
wait(NULL);
wait(NULL);
#endif
} /* main */

关于c - 在下面的示例中,如何等待每个进程终止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38749152/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com