【发布时间】:2021-03-21 06:10:27
【问题描述】:
我在写这个问题时有点困惑,因为我觉得我遗漏了一些要点(这就是我写它的原因,毕竟)。
所以我一直在研究多个进程如何访问单个文件。我有一个基本代码,使fork 两次 - 两个孩子fprintf 进入同一个文件,主要区别在于其中一个sleeps 和更多fprintfs。当所有fprinfs 完成时,孩子exits。同时父waitpids,每次子终止它fprintfs到同一个文件中。
我想看到的是 1) 有更多 fprintfs 和 sleep 的子进程在另一个子进程之后被终止(我认为运行时间的差异应该会提供一个很好的可能性)-那会发生; 2)在文件中间某处看到父进程的第一个fprintf(我怎么想!)在第二个终止之前,第一个孩子应该是waitpided - 这不是发生的事情。
每次发生的情况是两个fprintfs 都由文件末尾的父文件产生到文件中,就像父文件等到两个孩子都被终止然后才waitpided 他们一样。
将waitpid 与wait 交换显然会产生相同的结果。
我有几个猜测:
- 第二个孩子终止得更快,然后父母有时间将
waitpid第一个孩子和fprintf放入文件中。 - 在第二个子节点终止之前,操作系统没有时间将
SIGCHILD发送给父节点。 - 这就是
waitpid的工作方式,比如信号是否已排队? (但我还没有找到任何此类功能的规范)。
有人能解释一下为什么我没有收到关于第一个孩子在文件中间终止的消息,而是在最后得到它吗?
程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#define N 1000000
#define SLEEP_TIME 20
int main(void)
{
FILE *fd1 = fopen("test.txt", "w");
pid_t pid1, pid2, cpid;
int wstatus;
pid1 = fork();
if(0 == pid1) {
for(int i = 0; i < N; ++i) {
fprintf(fd1, "child1 %d %d\n", getpid(), i);
}
sleep(SLEEP_TIME);
for(int i = 0; i < N; ++i) {
fprintf(fd1, "child1a %d %d\n", getpid(), i);
}
sleep(SLEEP_TIME);
fclose(fd1);
exit(EXIT_SUCCESS);
}
else if(-1 == pid1) {
exit(EXIT_FAILURE);
}
pid2 = fork();
if(0 == pid2) {
for(int i = 0; i < N/2; ++i) {
fprintf(fd1, "child2 %d %d\n", getpid(), i);
}
fclose(fd1);
exit(EXIT_SUCCESS);
}
else if(-1 == pid2) {
exit(EXIT_FAILURE);
}
while(((cpid = wait(&wstatus)) != -1)) {
//while(((cpid = waitpid(-1, &wstatus, WUNTRACED | WCONTINUED)) != -1)) if(WIFEXITED(wstatus))
fprintf(fd1, "child %d exited with status %d\n", cpid, wstatus);
}
if(errno == ECHILD) {
fprintf(fd1, "All children are waited for!\n");
}
else {
perror("waitpid");
exit(EXIT_FAILURE);
}
fclose(fd1);
exit(EXIT_SUCCESS);
}
结果文件的最后几行:
2499998 child1a 7359 999997
2499999 child1a 7359 999998
2500000 child1a 7359 999999
2500001 child 7360 exited with status 0 //I wanted this one to be in the middle of the file!
2500002 child 7359 exited with status 0
2500003 All children are waited for!
【问题讨论】:
-
请不要在您的minimal reproducible example 中包含行号,这会使我们更难尝试并复制和调试您的问题。如果您想在源代码中标出特殊行,请在该行添加注释,并在问题的主体中提及。
-
至于您的问题,
wait系列函数通常归结为内核本身,并且不依赖于用户空间信号。内核拥有关于进程的所有信息,运行、睡眠、等待和退出但未收获。 -
@Someprogrammerdude,知道了,谢谢,枚举已删除。