【问题标题】:How to prevent child from interfering with parent's stdin after fork()如何防止孩子在 fork() 之后干扰父母的标准输入
【发布时间】:2015-06-12 19:22:16
【问题描述】:

我有一个从标准输入读取的程序,在执行此操作时,它有时需要 fork() 并异步执行命令。有时在此分叉后不久(可能在命令运行时),父级似乎丢失了从标准输入读取的数据。如果只丢失一个字节,程序将永远无法恢复。

fork() 的手册页说子进程继承了父进程的打开文件描述符集的副本,但是在 fork() 之后和 execvp() 之前尝试 close(STDIN_FILENO) 没有帮助。

我的程序基本上是这样的:

if (we_need_to_run_a_command_asynchronously) {
  if (!fork()) {
    close(STDIN_FILENO);
    char *args[] = { "command", "arg", "etc", 0 };
    setpriority(PRIO_PROCESS, 0, -19);
    execvp("command", args);
    exit(0);  // Ignore errors
  }
}

如何确保孩子不会干扰父母的标准输入(或其他任何属于父母的东西)?执行的命令通常是一个 shell 脚本。

我不知道我的程序到底出了什么问题,但只要它不运行任何命令,它就可以正常运行。只有有时(并非总是)在它运行命令之后,它从标准输入读取的数据以某种方式被破坏,这就是为什么我怀疑问题与 fork() 之后的标准输入有关。

【问题讨论】:

  • 您能否通过编写两个小型测试程序来检验您的假设,一个从标准输入读取,一个不读取,然后让您的父程序执行这些程序,看看会发生什么?
  • 请分享一个可编译的小程序。它可以帮助我们进入它
  • 您可以为标准输入设置 close-on-exec 标志,而不是显式关闭。但是,问题可能有不同的原因(演示问题的简短示例程序可能会有所帮助)。
  • 也许可以产生一个 pthread 而不是一个新进程?
  • 您执行的命令有权打开标准输入。你可以给它/dev/null 来阅读。您对command 了解多少(除了名称command 是一个内置的shell)?你写了吗?它是从什么读来的?基本上,如果您将其标准输入连接到/dev/null,您应该不会看到问题。

标签: c fork stdin


【解决方案1】:

您可以打开另一个文件并使用dup2 将新文件描述符复制到标准输入上,而不是关闭标准输入。如果您打开/dev/null 并在fork 之后和之前以及exec 之前将其重定向到标准输入,则孩子不会干扰父母的标准输入。

【讨论】:

  • /dev/null 是比 /dev/zero 更传统的选择,这是有充分理由的。
【解决方案2】:

我想我已经解决了这个问题。事实证明,在我的程序很少采用的路径中,它也执行了我在 fork() 之后忘记对子项中的 stdin 执行任何操作的命令。这段代码确实有效:

int pid = fork();
if (!pid) {
  int fd = open("/dev/null", O_RDWR);
  dup2(fd, 0);
  dup2(fd, 1);
  dup2(fd, 2);
  if (fd > 2)
    close(fd);

  execvp(...);

所以,我的错误,但也许我的问题仍然可以作为一个重要的提醒,即在分叉执行应该与父进程分开运行的命令时,通常需要对 stdin/stdout/stderr 执行某些操作。我认为上述方式是一种干净的方式。

【讨论】:

    【解决方案3】:

    我在execve() 的 POSIX 规范中发现了一个有趣的注释 及相关功能:

    如果文件描述符 0、1 或 2 在成功调用 exec 系列函数之一后将被关闭,则实现可能会为新进程映像中的文件描述符打开一个未指定的文件。如果执行标准实用程序或符合标准的应用程序时文件描述符 0 未打开以供读取或文件描述符 1 或 2 未打开以供写入,则执行实用程序或应用程序的环境应被视为不符合标准,因此实用程序或应用程序的行为可能与本标准中所述不同。

    推测您的实现是否正在执行“可能”选项很有趣。显式打开/dev/null 作为标准输入是最安全的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 2011-11-30
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多