使用exec程序从父级读取和写入多个子级

时间:2014-09-30 13:18:10

标签: c exec pipe fork dup2

我对C很新,不确定如何继续。

使用这段代码,我试图创建多个子进程,将它们的stdout发送到它们的父stdin,并且可以使用数组中指针位置的fdprintf写入stdin。

当使用读取stdin并打印到stdout(应该通过管道传输)的基本程序执行时,代码似乎不起作用。 (在主代码的另一部分我fprintf到管道的起始处,然后读取stdin等待应该写回的内容)。

int plumber(int *pipes[], int numChildren, char* command[]) {
    int i;
    char id;
    int nullSpace = open("/dev/null", O_WRONLY);

    for(i = 0; i < numChildren; ++i) {
        id = 'A' + i;
        pipe(pipes[2 * i]);
        pipe(pipes[2 * i + 1]);
        switch(fork()) {
            case (-1):
                fprintf(stderr, "Unable to start subprocess\n");
                exit(4);
                break;
            case 0:
                //child
                //close child's write, dupe its stdin to read
                //close childs old read
                close(pipes[2 * i][1]);
                if(dup2(pipes[2 * i][0], 0) == -1) {
                    fprintf(stderr, "Unable to start subprocess\n");
                    exit(4);
                }
                close(pipes[2 * i][0]);
                //close child's read, dupe its stdout to write
                //close childs old write
                close(pipes[2 * i + 1][0]);
                if(dup2(pipes[2 * i + 1][1], 1) == -1) {
                    fprintf(stderr, "Unable to start subprocess\n");
                    exit(4);
                }
                close(pipes[2 * i + 1][1]);
                close(1);
                //child stderr to nullspace
                if(dup2(nullSpace, 2) == -1) {
                    fprintf(stderr, "Unable to start subprocess\n");
                    exit(4);
                }
                close(2);
                execlp(command[i], "childprocess", numChildren, id, NULL);
                break;
            default:
                //parent
                //close read pipe from writing pipe
                close(pipes[2 * i][0]);
                //close write pipes and dupe stdin to read
                //close parents old read
                close(pipes[2 * i + 1][1]);
                if(dup2(pipes[2 * i + 1][0], 0) == -1) {
                    fprintf(stderr, "Unable to start subprocess\n");
                    exit(4);
                }
                close(pipes[2 * i + 1][0]);
        }
    }
    close(nullSpace);
    return 0;
}

该命令只是运行子进程,它也占用子进程数和从A到D的id。* pipes []是numChildren * 2乘2(所以沿着它的子1读取管道,child1写入管道,child2阅读,child2写等。 请提前帮助和谢谢。

1 个答案:

答案 0 :(得分:0)

父母只能有一个stdin。每次父母做:

dup2(pipes[2 * i + 1][0], 0)

它正在关闭之前的stdin并将其替换为管道的读取端。这意味着除了最后一个孩子之外,所有孩子的stdout都会有一个封闭的阅读结束,这会导致他们收到SIGPIPE(如果{EPIPE错误如果他们试图生成任何输出,则忽略1}}。此外,父母现在已经丢失了原来的SIGPIPE,这可能是也可能不重要。

您还应该检查stdin没有返回错误。如果是这样,你会得到非常奇怪的行为,因为失败的孩子将开始与父母同时产生所有剩余的孩子。

如果你真的想让所有孩子的输出出现在一个execlp上,那么他们都必须使用相同的管道。但是,这将导致它们的输出随机混合,因此父母不可能知道谁发送了什么。如果父对象只是将每个管道的读取端保留在其原始描述符中而不是尝试stdin将它们设置为0,那会更好。这样,父对象将保留其原始dup2,并且它可以使用stdin(或select或...)来确定何时获取输入以及从哪个孩子获得输入。

将孩子的pollstdin连接到同一个进程(父进程)通常是一个坏主意,因为它很容易导致死锁。管道只能缓冲有限数量的数据,并且在满时将对写入器施加压力(即阻塞)。如果父母和孩子都将大量数据写入他们的stdout,那么他们都会受到压力,这将阻止他们读取他们的输入并排出管道。您必须确保孩子在生成自己的任何输出之前消耗所有父输出,或者找到一种方法来保证即使stdout也可以始终从stdin开始阅读被封锁了。后者可以通过让单独的线程处理stdoutstdin,或者通过启用非阻塞I / O并使用stdout等来确定何时可以写入管道来实现。< / p>