#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int childs[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (pipe(p) == -1) { perror("pipe"); exit(1); }
pid_t pid = fork();
if (pid) {
close(p[0]);
childs[i] = p[1];
}
else {
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { ... }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(childs[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}
评论输出:
child 1 start
child 2 start
child 3 start
child 3 read (0), finish
2秒后显示下一行
child 2 read (0), finish
2秒后显示下一行
child 1 read (0), finish
我不写入父母的频道。关闭它,我想给将要在read
等待的孩子发出信号。
似乎有以下内容。 Сhild N
预计会从结果0
中读取,这没关系。儿童2 (N-1)
和1
已锁定在read
儿童3
已完成。那么孩子1
就像等待一样。
为什么会发生锁定?
答案 0 :(得分:2)
子进程从其父进程继承打开的文件描述符。您的主进程在循环中打开文件描述符(使用pipe
,仅保留写入结束)。子1没有描述符(stdin / stdout / stderr除外);子2继承childs[0]
(描述符转到子1);子3继承childs[0]
和childs[1]
(描述符转到子1和2)。
read
。因此,子1等待(因为子2和子3仍然具有打开的写入描述符)并且子2等待(因为子3仍然具有打开的写入描述符);独生子3睡觉和退出。这导致其文件描述符关闭,唤醒子2。然后子2睡眠并退出,关闭其文件描述符,最终唤醒子1。
如果要避免此行为,则必须关闭每个子项中的打开文件描述符:
else {
for (int j = 0; j < i; j++) {
close(childs[j]);
}
close(p[1]);
printf("child %d start\n", i + 1);
答案 1 :(得分:0)
管道的写入端由子节点继承。 由于filedescriptor被重新计数,因此只有在对所有引用都被关闭的情况下才会认为写入结束。
以下是您的代码,稍加重构,添加了修复程序:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int children_w[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (0>pipe(p))
{ perror("pipe"); exit(1); }
pid_t pid;
if(0> (pid= fork()))
{ perror("fork"); exit(1); }
if(pid==0) {
/* Fix -- close the leaked write ends */
int j;
for(j=0; j<i; j++)
close(children_w[j]);
/* end fix*/
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { perror("read");/*...*/ }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
children_w[i] = p[1];
close(p[0]);
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(children_w[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}