我一直在阅读关于wait()
和waitpid()
的文档,我仍然对它们的工作方式感到有些困惑(我收集到wait(&status)
等同于waitpid(-1, &status, 0);
})。下面是我正在研究的一小段代码。请帮助我理解这些片段是否写得正确,如果没有,那么为什么不这样。
目标1: 收获所有僵尸儿童。
int reapedPid;
do {
reapedPid = waitpid(-1,NULL,WNOHANG);
} while (reapedPid > 0);
我在这里尝试做的是遍历所有孩子,如果孩子已经完成,就让孩子收获,如果不是,就让它继续下去,当我的孩子用尽时reapedPid == -1
然后循环退出。我在这里感到困惑的原因是我没有看到waitpid()
应该知道哪些孩子已经被检查过,哪些没有被检查过。它做了这样的检查吗?或者这种方法不起作用?
目标2: 等待所有孩子完成。
int pid;
do {
pid = wait(NULL);
} while (pid != -1);
这里我不关心孩子的结果状态 - 这应该只是等待每个子进程完成,无论是成功还是不成功,然后退出。我认为这段代码是正确的,但我不确定。
目标3: 分叉一个孩子并等待它完成。
int pid = fork();
if (pid < 0) {
// handle error.
}
else if (pid == 0) {
// execute child command
}
else {
int status;
int waitedForPid = waitpid(pid,&status,0);
assert(waitedForPid == pid);
}
这里我只是试图分叉过程并让父母等待孩子完成。我不完全确定我是否应该通过0
选项,但看起来WNOHANG,WUNTRACED和WCONTINUED与我的目标并不相关。
答案 0 :(得分:2)
对于大多数这些,您应该能够轻松编写一些示例程序并验证您的理解。
目标1: 收获所有僵尸儿童。
我在这里感到困惑的原因是我不知道
waitpid()
应该知道哪些孩子已经被检查过,哪些没有被检查过。它做了这样的检查吗?
一旦孩子退出,只能wait
一次。因此,您的循环只会获取尚未wait
(僵尸)的子进程的退出状态。
对于目标2和3 ,再次,我会认为这是一个必需的练习,以编写示例以查看其工作原理。对于#2,我建议您的代码应该始终跟踪所有分叉的子代,以便它可以准确地知道wait
上的人。你的#3代码看起来不错;不需要options
。请务必使用WEXITSTATUS
和朋友宏从status
获取信息。
另见:
答案 1 :(得分:2)
跟踪进程是内核的工作。跟踪死亡过程是微不足道的。内核可以判断哪些子进程已经死亡但尚未等待,并且每次调用都将返回其中一个死亡的子进程,直到没有任何进程报告为止。 (由于WNOHANG
选项,可能仍有孩子需要等待,但剩下的孩子都没有死。但
这第二个循环也很好,几乎等同于第一个循环。不同之处在于它会在返回-1之前等待所有孩子死亡。
这第三个片段很好;断言将是真实的,除非在特殊情况下(例如程序中的另一个线程也等待孩子并收集尸体)。但是,如果你在某个地方启动另一个进程并让它在后台运行,你可能会收集僵尸,而通过修改其他循环,你可以收集僵尸并仍然等待正确的孩子:
int pid = fork();
if (pid < 0)
{
// handle error.
}
else if (pid == 0)
{
// execute child command
}
else
{
int status;
int corpse;
while ((corpse = waitpid(-1, &status, 0)) > 0)
if (corpse == pid)
break;
}