Search code examples
clinuxpipeforkposix

Why my program in which a child process is forked needs user to type 'Enter' before exiting?


I have the following program:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/wait.h>

int main()
{
    int p[2];
    char *argv[2];
    argv[0] = "wc";
    argv[1] = "-w";
    argv[2] = NULL;

    pipe(p);
    if (fork() == 0)
    {
        close(0);
        dup(p[0]);
        close(p[0]);
        close(p[1]);
        execvp(argv[0], argv);
    }
    else
    {
        close(p[0]);
        write(p[1], "hello world\n", 12);
    }

    fprintf(stdout, "hello world\n");
}

And when I run it:

$ gcc a.c
$ ./a.out

I got the following:

hello world
$ 2
_    // the cursor is flickering here

After I type Enter, the program exit. What is the reason for this? In addition, if I exchange the content in the parent process and child process like this:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/wait.h>

int main()
{
    int p[2];
    char *argv[2];
    argv[0] = "wc";
    argv[1] = "-w";
    argv[2] = NULL;

    pipe(p);
    if (fork() == 0)
    {
        close(p[0]);
        write(p[1], "hello world\n", 12);
    }
    else
    {
        close(0);
        dup(p[0]);
        close(p[0]);
        close(p[1]);
        execvp(argv[0], argv);
    }

    fprintf(stdout, "hello world\n");
}

I got the output as I expect:

hello world
2
$

The program has exited and is ready to get next command. What's the problem of the first program?


Solution

  • If you look very carefully at your output, you'll see that your program has exited:

    hello world
    $ 2
    _    // the cursor is flickering here
    

    See how the $ is printed? This is your shell waiting for input as usual. By pressing enter you've just input a blank command to your shell and obtained a second $ prompt.

    What's the 2 doing there? That's wc's output. Your program isn't actually waiting for wc to exit. This means that your program exits before wc does, so the shell resumes, prints its prompt, and only then does wc exit and print 2.

    To fix, you'll probably want to add some kind of wait call to wait for the child process in the parent.