C ++中管道()和fork()的新手 -

时间:2012-09-19 19:49:14

标签: c++ fork pipe

环境: x86_64上使用gcc 4.4.6的Linux 2.6.32(RHEL 6.3)

后台:我正在运行一些繁重的数据处理:~500 GB输入数据分布在~2000个文件中。我的主要流程分叉N个孩子,每个孩子都收到一个文件名列表来处理。

我想要的是是让控制台I / O通过父级。我一直在研究pipe()并看到一些有关使用poll()来获取父块的有趣内容,直到有错误消息要阅读。似乎我需要有N个管道(每个孩子一个)并传递poll()有关我想听的信号的信息。此外,我一旦我在每个孩子中dup2(pipe[1], STDOUT),每个孩子都应该像往常一样用cout << stuff;来写管道,对吗?

首先,就我上面所说的多个管道,poll()dup2()是否正确?

第二次,如何设置父poll()循环,以便在所有孩子都死后继续前进?

现在,这个(不完整的)代码段如下:

int status;
while (1) { // wait for stuff
    while ((status = poll(pollfds, ss.max_forks, -1)) > 1)
        cout << "fork "<< status << ": " << pipes[status][0];
    if (status == -1)   Die(errno, "poll error");
    if (status == 0) { // check that we still have at least one open fd
        bool still_running = false;
        for (int i=0; i<ss.max_forks; i++) {
             // check pipe i and set still_running if it is not zero
        }
        if (!still_running)
            break;
    }
}

第三次,我应该设置什么以及何时应该使用fcntl()进行设置?我想做O_ASYNC吗?我想要阻止还是阻止?

2 个答案:

答案 0 :(得分:2)

实际上,您需要关闭()两个进程(父进程和子进程)中相应的“未使用”端,以确保“破坏的管道”出现。因此,如果孩子写入Pipe [0],那么父母将从Pipe [1]读取并关闭自己的Pipe [0]。同样,孩子将关闭Pipe [1]。

如果这样做,父母在孩子死后从管道中读取时会收到错误。不要忘记使用waitpid()样式函数之一来清理死进程。

您可能希望将句柄设置为非阻塞,因此您可以只读取其中的任何内容而无需使用1字节读取,这将非常低效。虽然我只使用合适的缓冲区大小(通常为1024或4096)调用read(),但如果有更多数据,则让下一个轮询触发。但是,我通常只有一个孩子可以工作,而不是几百个: - )

至于你的循环,你必须跟踪每个孩子的状态,并在你没有活着的孩子时离开。

编辑:实际上,我发现即使设置了POLLIN,或者当我得到POLLERR或POLLHUP标志,当我得到0字节读取时,我认为孩子已经死了。不确定哪种情况是正确的......

答案 1 :(得分:1)

以下是关于select()poll()的问题:What are the differences between poll and select?

但是,您是否考虑过使用线程而不是单独的进程?您可以更好地控制与线程的交互,并且通过数据结构而不是流水线的I / O流进行通信。管道昂贵;你正在浏览操作系统,你必须格式化输出结果/解析输入结果,也很昂贵。

最后一点:无论您使用的是轻量级线程还是重量级的fork / exec,除非您拥有2000 CPU多处理器,否则您不希望一次启动2000个。如果CPU争用的线程/进程数多于CPU数,则会创建一个非常昂贵且连续的上下文交换的情况。