Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
453 views
in Technique[技术] by (71.8m points)

c - Child process cannot read after the exiting of parent process

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.

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?

Code of child program:

/* cc child.c -o child */

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

Code of parent program:

/* 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);
  }
}

In zsh shell:

zsh>: ./parent ./child
zsh>: This is what child program read:   // read nothing and print nothing
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.

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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...