父进程退出后子进程无法读取 [英] Child process cannot read after the exiting of parent process

查看:31
本文介绍了父进程退出后子进程无法读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过函数execvp()fork并执行子程序后,父进程退出.然而这会导致子进程中的函数 fgets() 立即返回,而无需等待来自 stdin 的输入.

After forking and executing a child program by function execvp(), the parent process exit. However this cause the function fgets() in the child process return immediately without waiting for input from stdin.

我猜父进程的退出会向子进程发送一些信号,使 fgets() 函数返回.有人可以为我解释更多吗?

I guess the exiting of the parent process will send some signals to the child process which make the fgets() function return. Could some one explain more for me?

子程序代码:

/* cc child.c -o child */

int main () {
  char buffer[10];
  fgets(buffer, 10, stdin);
  printf("This is what child program read:
%s", buffer);
}

父程序代码:

/* cc parent.c -o parent */

int main (int argc, char **argv) {
  pid_t pid = fork();
  if (pid < 0) {
    perror("fork");
    exit(EXIT_FAILURE);
  }
  else if (pid == 0) {
    execvp(*(argv+1), argv+1);
  }
  else {
  //    while(1);  if while(1) or wait() is used, child process can wait for input
    exit(1);
  }
}

在 zsh shell 中:

In zsh shell:

zsh>: ./parent ./child
zsh>: This is what child program read:   // read nothing and print nothing

推荐答案

终端由前台进程组控制.当 shell 调用父进程时,它使父进程成为前台进程组的领导者.孩子继承该组并有权访问终端.

The terminal is controlled by the foreground process group. When the shell invokes the parent, it makes the parent the leader of the foreground process group. The child inherits that group and has access to the terminal.

但是,当父进程退出时,shell 收回对终端的控制权,成为前台进程组的领导者.子进程不再在前台进程组中,因此它无法访问终端.在这种情况下,fgets() 将返回 NULL 并设置错误代码.

However, when the parent exits, the shell takes back control of the terminal and becomes the leader of the foreground process group. The child is no longer in the foreground process group, so it has no access to the terminal. In this case, fgets() will return NULL and an error code will be set.

如果您从终端以外的其他地方获取输入,例如管道,那么您将看到程序按预期工作.例如:

If you take input from someplace other than the terminal, such as a pipe, then you'll see that the program works as expected. For example:

$ echo test | ./parent ./child

所以这个问题只有在终端输入时才会出现.

So this problem only occurs when input comes from the terminal.

回想起来,如果检查了 fgets 错误代码,回答这个问题会更直接.在这种情况下,fgets 返回 null,但随后您需要检查 feof() 和/或 ferror() 以确定这是否意味着已到达文件末尾(标准输入关闭)或出现错误.在这种情况下,NULL 意味着存在 EIO 错误.

In retrospect, answering this question would have been more straighforward if the fgets error code was checked. In this case, fgets returns null, but then you need to check feof() and/or ferror() to determine if this means that the end of the file was reached (stdin closed) or there was an error. In this case, the NULL meant there was an EIO error.

较早的错误答案(请参阅评论线程以获取解释,由于冗长的讨论而将其留在这里):当你 fork 时,子进程继承 stdin 等.当父进程退出时,它关闭 stdin,所以子进程尝试从关闭的描述符中读取并且什么也得不到.通过添加对 wait() 的调用,您可以保持标准输入打开,这允许您的子程序按预期工作.

Earlier wrong answer (see comment thread for explanation, leaving this here because of the lengthy discussion): When you fork, the child process inherits stdin etc. When the parent process exits, it closes stdin, so the child tries to read from a closed descriptor and gets nothing. By adding the call to wait(), you keep stdin open and this allows your child program to work as expected.

这篇关于父进程退出后子进程无法读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆