许多 child 进程与单个 parent 通信

Many child processes communicating to single parent

我需要尝试生成一个 parent 并与多个 child 进程进行有意义的通信。这意味着发送数据并让他们将数据发送回单个 parent。首先,我一直在尝试让我的 children 输出一些东西并让我的 parent 捕捉它,最终目标是允许所有 children 之间的双向通信parent。为此,我为每个 children 实例化了两个管道,并将所有管道存储到一个名为 pipes 的多维数组中。多维管道数组存储使得每个索引 i 用于 ith + 1 child 并且 [i][0] 索引具有专门用于 parent 的管道到 child[i][1] 索引有一个专门供 childparent 通信的管道。 children 进程都是非常简单的派生,只执行这段代码:

foo.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv) {
    printf("Hi there!");
    close(STDOUT_FILENO); //Close our write end
    close(STDIN_FILENO); //Close our read end
    //Else do nothing
    return 0;
}

我的主要代码位于此,它首先创建所有必要的管道(每个 children 有 2 个)。然后我 dup2 STDINSTDOUT 所以 printf 打印到我想要​​的管道。

fork_complex.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#define MAXSIZE 4096
#define CHILDREN 5

int main(int argc, char ** argv) {
    //Needs command line arguments
    int ** pipes[CHILDREN]; //The multi-dimensional array that contains CHILDREN pipes
    //Allocate the space
    for (int i = 0; i < CHILDREN; i++) {
        //Each children will need two pipes, one for comunicating and one for writing
        pipes[i] = malloc(sizeof(int*) * 2);
        pipes[i][0] = malloc(sizeof(int) * 2); //This pipe is specifically parent to child
        pipes[i][1] = malloc(sizeof(int) * 2); //This pipe is for specifically for the child to parent

        //Create the pipes
        if (pipe(pipes[i][0]) == -1 || pipe(pipes[i][1]) == -1) {
            //There was a failure in generating one of the pipes
            perror("Error on generating the pipe");
        }
    }
    //Spawn the child processses
    for (int i = 0; i < CHILDREN; i++) {
        int status = fork(); //Fork a child
        switch (status) {
            case -1:
                perror("Failed to fork the process");
                exit(1);
                break;
            case 0:
                //Child process, exec the floor
                dup2(pipes[i][0][0], fileno(stdin));
                dup2(pipes[i][1][1], fileno(stdout));
                execl("./foo", "");
                break;
        }
        //Parent continues the loop to spawn more children
    }
    
    char readed[MAXSIZE] = ""; //Reading buffer
    //Now read back from the pipes
    for (int i = 0; i < CHILDREN; i++) {
        while (read(pipes[i][1][0], readed, MAXSIZE) > 0) {
            printf("From pipe %d, we have read %s\n", i, readed);
        }
    }
    return 1;
}

但是,我的代码似乎一直卡在底部的 while 块中以从管道中读取,因为当我删除它时,代码会完全执行。我有一些猜测,可能我们有僵尸 children(因为它们在 parent 可能进入 for 循环之前终止)。我不确定当 child 死亡时管道会发生什么(除此之外与其相关的文件描述符已关闭)我们仍然可以从中读取(我对此也很好奇)。但是,根据我过去的经验,您似乎仍然可以。我已经被这个问题困了几个小时,任何见解都将不胜感激(或者我可能做错了什么)!

当您 read 4096 字节时,某些系统(如 linux)将尝试满足完整请求并阻塞直到另一端 1) 写入所有 4096 字节或 2) 关闭写端。 write end的所有duplicates都需要关闭,不只有一个。 duping 创建对文件描述符的新引用。当您 fork 时,就好像您 dup 编辑了您当时打开的所有文件描述符。 要完成 read,您要么需要满足完整的 4096 字节请求,要么生成 EOF,要使后者发生,需要关闭写入端的所有克隆。

因为您的每个 children execs,您可以做的是设置每个管道 O_CLOEXEC(使用 fcntl),并且 close 每个写入结束parent 在你 fork 掉 child 之后,将写入到写入端。

(除此之外,请确保包含您需要的所有 headers 并确保您处理所有错误)。