为什么GNU脚本使用两个for而不是select和一个fork?

时间:2014-03-05 18:15:06

标签: c linux unix gnu

我刚刚意识到GNU linux上的“脚本”二进制文件正在使用两个forks而不是一个。 它可以简单地使用select而不是第一个fork()。为什么会使用两个叉子?

是否仅仅是因为在编码时没有选择存在且没有人有重新编码的动机或是否有正当理由?

man 1 script:http://linux.die.net/man/1/script

脚本来源:http://pastebin.com/raw.php?i=br8QXRUT

1 个答案:

答案 0 :(得分:3)

线索在代码中,我已经添加了一些注释。

child = fork();
sigprocmask(SIG_SETMASK, &unblock_mask, NULL);

if (child < 0) {
    warn(_("fork failed"));
    fail();
}
if (child == 0) {
            /* child of first fork */
    sigprocmask(SIG_SETMASK, &block_mask, NULL);
    subchild = child = fork();
    sigprocmask(SIG_SETMASK, &unblock_mask, NULL);

    if (child < 0) {
        warn(_("fork failed"));
        fail();
    }
    if (child) {
                    /* child of second fork runs 'dooutput' */
        if (!timingfd)
            timingfd = fdopen(STDERR_FILENO, "w");
        dooutput(timingfd);
    } else
                    /* parent of second fork runs 'doshell' */
        doshell();
} else {
    sa.sa_handler = resize;
    sigaction(SIGWINCH, &sa, NULL);
}
    /* parent of first fork runs doinput */
doinput();

因此有三个进程在运行:

  1. dooutput()
  2. doshell()
  3. doinput()
  4. 我认为你在问为什么要使用三个流程,而不是一个流程和select()select()自古代UNIX历史以来就存在,所以答案不太可能是select()不存在。答案更平淡无奇。 doshell()无论如何都需要处于一个单独的过程中,因为它的作用是exec具有适当管道fds的shell。因此,您至少需要一个叉子。在dooutput()循环中编写doinput()select()在我看来完全可能,但实际上更容易使用阻塞I / O而不必担心使用select等由于fork()相对轻量级(给定UNIX的CoW语义)并且几乎不需要在两个进程之间进行通信,为什么在select()非常好并且产生较小代码时使用fork()? IE的真正答案是“为什么不呢?”