【问题标题】:Forking a piped sub processes分叉一个管道子进程
【发布时间】:2012-07-19 20:17:56
【问题描述】:

派生管道内衬子进程的最佳技术是什么?

我当前的程序需要运行另一个进程,这实际上是由管道链接的几个命令。我不需要知道命令的输出是失败还是成功,所以我使用 fork/exec。

命令行上的等价物是

 /path/to/A arg1 arg2 | /path/to/B argB1 | /path/to/C

注意:使用脚本并不实用,因为它的 A/B/C 将来可能会发生变化。

我想到的两种技术是:

  1. 递归分叉。连接下一个 fork 中可供子级使用的父级(输入到其父级)输出。

  2. 在顶层创建所有管道。
    然后使用循环来分叉所有可以正确连接管道的子节点。

【问题讨论】:

  • 后者是 shell 所做的,大概是有充分理由的。
  • @OliCharlesworth:你有参考吗?或者最好是示例代码的链接,这样我就不会重新发明轮子。
  • 如果你在Linux上工作,你可以通过运行pstree来推断这一点,它显示了所有进程的父子关系。

标签: c exec fork


【解决方案1】:

不要递归分叉。使 B 成为 A 的子进程并不是一个好主意。例如,如果 B 调用 setsid 在它自己的会话中运行,它会带上不相关的 A。如果 B 死了,A 会得到一个 SIGCHILD,而不是你。特别是,你将无法获得B的返回状态。

这是在一系列管道上分叉 n 个子节点的代码草图。警告:我直接在浏览器中输入了代码;可能有很多错别字,我省略了所有的错误检查。

char *executables[n];
char *args[n];
int pipes[2*n+2]; /* child i reads from  */
int child_pids[n];
int ret; /*Error checking omitted; abort if ret ever becomes negative*/
ret = pipe(pipes);
for (i = 0; i < n; i++) {
    ret = pipe(pipes + 2 * i + 2);
    ret = fork();
    if (ret == 0) {
        /* Code of child i */
        close(pipes[2*i+1]);
        close(pipes[2*i+2]);
        dup2(pipes[2*i], 0);
        dup2(pipes[2*i+3], 1);
        ret = execv(executables[i], args[i]);
    }
    close(pipes[2*i]);
    close(pipes[2*i+3]);
    child_pids[i] = ret;
}
/* interact with the subprocesses, then call wait or waitpid as needed */

【讨论】:

    【解决方案2】:

    如果您使用的是 unix,一个简单的 system("/path/to/A arg1 arg2 | /path/to/B argB1 | /path/to/C") 将满足您的需求。它以/bin/sh -c $STRING_PASSED_TO_SYSTEM 调用一个shell。如果您想要更精细的控制,例如读取输出或写入输入的能力,请考虑 C 库中的 popen() 例程。

    【讨论】:

    • 不想使用 system() 或 popen()。我使用的一些论点有点复杂,引用和转义引号会变得非常混乱。我想使用 execvp() 来确保参数正确传递给子进程。
    • 我向你保证,正确的命令转义是一个比创建工作管道链更简单的过程。或者,将带有奇怪参数的命令包装在通过文件等获取参数的脚本或变体版本中......使所有 pipe()/dup()/fork()/exec() 逻辑正确的过程是多毛且容易出错。正如 Oli 在上面指出的那样,shell 已经为您完成了。
    猜你喜欢
    • 1970-01-01
    • 2019-03-28
    • 1970-01-01
    • 2018-05-23
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    相关资源
    最近更新 更多