Basics of multi-process programming

Let's start our journey by writing the famous Hello, World! program.

#include <stdio.h>

int
main()
{
  printf("Hello, World!\n");
  exit(0);
}
Now, let's see the multi-process version of this program.
#include <stdio.h>
#include <unistd.h>

int
main()
{
  int pid;

  if ((pid = fork())== -1) {		/* create a child process */
    perror("fork() failed");
    exit(1);
  }

  if (pid == 0) {
    /* child process */
    printf("Hello, ");
    fflush(stdout);
  }
  else {
    /* parent process */
    printf("World!\n");
    fflush(stdout);
  }

  exit(0);
}
When the above program runs, there is only ONE process. When the system call fork() (see man page for its usage) is called, however, the program is splitted into TWO independent processes. One is another's child. The child process prints out "Hello, ", and the parent process prints out "World\n".

Run it to see what happens. If you are lucky, you will see,

Hello, World!
But, in most cases, you will see,
World!
Hello,
This is because the two processes are independent, the order of their execution is not guaranteed. We need a mechanism to suspend the parent process until the child finish its job. The system call wait() is for this purpose. Below is the correct multi-process version that guarantees the output "Hello, World!".
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int
main()
{
  int pid;

  if ((pid = fork())== -1) {		/* create a child process */
    perror("fork() failed");
    exit(1);
  }

  if (pid == 0) {
    /* child process */
    printf("Hello, ");
    fflush(stdout);
  }
  else {
    /* parent process */
    wait(NULL);				/* wait the child exit */
    printf("World!\n");
    fflush(stdout);
  }

  exit(0);
}

Now let's make the problem a little bit more challenging. How to let the child process wait until the parent finishes its job? Wait() doesn't work! There are many other ways for interprocess communication (IPC). Below is the the program using signal(), pause() and kill().

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void parentdone(int signum) {}

int
main()
{
  int pid;

  if ((pid = fork())== -1) {		/* create a child process */
    perror("fork() failed");
    exit(1);
  }

  if (pid == 0) {
    /* child process */
    signal(SIGUSR1, parentdone);	/* set up a signal */
    pause();				/* cause the child to sleep
                                           until a signal is received */
    printf("World!\n");
    fflush(stdout);
  }
  else {
    /* parent process */
    printf("Hello, ");
    fflush(stdout);
    kill(pid, SIGUSR1);			/* send a signal to the child */
    wait(NULL);				/* wait the child exit */
  }

  exit(0);
}

When the child process starts, it sets up a signal and then sleeps. When it receives a signal from the parent, it goes on to print out "World!\n", and exits.

The parent process first print out "Hello, ", and then send a signal to the child, and finally wait until the child terminates.

One application of multi-process programming is shell. Here is a simple shell program. It accepts a command from the keyboard, spawn a child process and wait until the child process finishes executing the command, and so on.