#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
我不写入父 channel 。关闭它,我想给将在 read
中等待的 child 一个信号。
好像有下面的。 Сhild N
expected 完成从结果 0
读取,没问题。 child 2 (N-1)
和 1
被锁定在一个 read
到 child 3
完成。然后 child 1
是相似的将等待。
为什么会出现锁?
最佳答案
子进程从父进程继承打开的文件描述符。您的主进程在循环中打开文件描述符(使用 pipe
,仅保留写入端)。 child 1 不继承任何描述符(stdin/stdout/stderr 除外); child 2 继承 childs[0]
(描述符转到 child 1); child 3 继承了 childs[0]
和 childs[1]
(描述符指向 child 1 和 2)。
read
就会阻塞。所以 child 1 等待(因为 child 2 和 child 3 仍然有一个打开的写描述符)并且 child 2 等待(因为 child 3 仍然有一个打开的写描述符);只有 child 3 sleep 并退出。这会导致其文件描述符关闭,从而唤醒 child 2。然后 child 2 休眠并退出,关闭其文件描述符,最终唤醒 child 1。
如果你想避免这种行为,你必须关闭每个 child 中打开的文件描述符:
else {
for (int j = 0; j < i; j++) {
close(childs[j]);
}
close(p[1]);
printf("child %d start\n", i + 1);
关于c - 关闭写入器后从管道读取被阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39195735/