如何防止孩子在fork()之后干扰父母的stdin

时间:2015-06-12 19:22:17

标签: c fork stdin

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

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脚本。

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

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分: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做一些事情。我认为上述方法是一种干净的方式。

答案 2 :(得分:0)

我在execve()的POSIX规范中找到了一个有趣的注释 和相关的功能:

  

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

有趣的是推测您的实施是否正在行使'可能'选项。明确打开/dev/null作为标准输入是最安全的。