c - 关闭写入器后从管道读取被阻塞

标签 c unix ipc system-calls

#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/

相关文章:

string - 排序 : string comparison failed Invalid or incomplete multibyte or wide character

python - 使用 pyzmq 零拷贝共享数据

c++ - 如何在特定时间段内使用 `accept()` 接受任意数量的连接?

C - 处理字符串的简单链表程序

c - 制作 : compile object file twice in the same target

c - 以下表达式中发生了什么转换?

c++ - WM_COPYDATA 数组与 vector

c - 从文件中读取分号分隔的字符串

linux - 用linux文件中的字符串替换字符串模式

linux - 在 sed 命令中扩展 unix 变量