读取一个 Child 进程阻塞其他 Children

Reading From One Child Process Blocks Other Children

正如您从我在下面分享的代码中看到的那样,我正在尝试实施 1 个中央服务器和 n children。首先,我通过从服务器分叉来创建所有 n children。此外,在分叉之前,我使用 Pipe 创建双向管道。分叉并创建 n children 后,我想从 child 代码中读取字符。他们都发送字符 'A',但我只能从一个 child 读取。我使用 poll to select active children 并尝试从中读取数据。什么可能导致程序在一个 child 上阻塞?我将不胜感激任何帮助。

#define Pipe(fd) socketpair(AF_UNIX, SOCK_STREAM, PF_UNIX, fd)
int n = 5;    
struct pollfd pfd[n];

for (int i = 0; i < n; i++){
    Pipe(fd[i]);
    if (fork() == 0){
        close(fd[i][0]);
        dup2(fd[i][1], 0);
        dup2(fd[i][1], 1);
        close(fd[i][1]);
        execl(code, arguments);
    }

    else {
        close(fd[i][1]);
        dup2(fd[i][0], 0);
        dup2(fd[i][0], 1);
        close(fd[i][0]);
    }

    struct pollfd s;
    s.fd = fd[i][1];
    s.events = POLLIN;
    s.revents = 0;
    pfd[i] = s;
}   

while(1){
    poll(pfd, n, 2);
    for (int i = 0; i < n; i++){
        if (pfd[i].revents && POLLIN){
            char data;
            read(0, &data, 1);

            if (data == 'A'){ 
            .
            .
            .
            }
        }
    } 
}

父级只能有一个标准输入文件描述符和一个标准输出文件描述符。你的代码是这样的:

for (int i = 0; i < n; i++){
    Pipe(fd[i]);
    if (fork() == 0){
        close(fd[i][0]);
        dup2(fd[i][1], 0);
        dup2(fd[i][1], 1);
        close(fd[i][1]);
        execv(code, arguments);
    }
    else {
        close(fd[i][1]);
        dup2(fd[i][0], 0);
        dup2(fd[i][0], 1);
        close(fd[i][0]);
    }
    …poll setup…
}

这会在每次创建子项时仔细切换父项中的标准输入和标准输出,使程序只与最后一个子项建立连接。

您不应该像在父级中那样使用 dup2();您可能需要在数组中保持文件描述符处于打开状态,以便使用它们分别与子项通信。

我没有检查过你为什么在 fd[i] 之后使用下标 [0][1],但感觉不对。

您应该在 execv() 调用之后至少放置一个 exit(1);_exit(1);;我更希望看到一条错误消息也打印到 stderr,报告 execv() 失败。您不需要检查 return 值;如果 execv() returns,失败;如果成功,则不会 return。否则,如果 execv() 失败,您可能会得到多个进程都认为它们是父进程。这会导致混乱。始终确保您处理执行其他程序的失败!