.. _multi:

Multi-process Programming
=========================

Advanced operating systems such as Unix and Windows have the
ability to run multiple processes at the same time. The system
actually switches between processes, but to the user, it appears
that they are all running in parallel. Here we discuss how to
create additional processes and some system calls which are
commonly used together when creating additional processes.

Examples of when we might want to create an additional process
are:


- 
   When the parent program needs to continue running while another
   process services some request, (e.g., a network based server
   program).

- 
   When another program can be used to accomplish a desired objective,
   (e.g., calling `lpr` to print some data.)


fork()
------

The `fork()` system call starts a new process which is identical to
the original running process except for the value returned from the
`fork()` system call. The new process is called the *child* process
and `fork()` returns a value of zero to the child. The original
process is called the *parent* and `fork()` returns the PID of the
child to the parent.

The `fork()` system call is the only system call which creates a
new process in UNIX. When the operating system boots, it starts a
process called `init` which calls `fork()` as needed to create
other processes. Thus, `init` is considered the parent of all
processes running on the computer. When a user logs in, they are
given a shell which reads commands from the user and runs programs
for the user. The shell begins the task of running a new program by
first calling `fork()` to create a new process.

pipe( int \* )
--------------

The `pipe()` system call creates a mechanism for passing data
between processes, such as between the child and parent process
after a `fork()` system call. We pass an integer array of size two
as an argument to `pipe()`. `pipe()` puts two open file descriptors
in the array. The two file descriptors are related to each other in
the sense that the first descriptor is opened for reading and the
second descriptor is open for writing and what ever is written to
the write descriptor can be read from the read descriptor. Thus we
say that we have an I/0 pipe.

    ::

        int p[2];
        
        pipe( p );     /* p[0] - read end of pipe  */
                       /* p[1] - write end of pipe */


dup( int )
----------

The `dup()` system call is used in relation to pipes. If we want to
redirect standard input or standard output to be one of the ends of
a pipe, then `dup()` is used to duplicate a file descriptor. The
new value associated with the duplicated descriptor is always the
numerically lowest available descriptor. So if we close `stdin` or
`stdout`, then we can use `dup()` to redirect `stdin` or `stdout`
to one of the ends of a pipe.

    ::

        int main(void)
        {
           int p[2];     /* for pipe */
        
           /*
            * parent's stdout goes to child's stdin
            */
           pipe( p );
           if( fork() == 0 ) {  /* child */
              close(0);         /* close stdin */
              dup( p[0] );      /* stdin now comes from the pipe */
              close( p[0] );    /* close extra descriptor */
              close( p[1] );    /* close extra descriptor */
              ....
           } else {             /* parent */
              close(1);         /* close stdout */
              dup( p[1] );      /* stdout now go to the pipe */
              close( p[0] );    /* close extra descriptor */
              close( p[1] );    /* close extra descriptor */
              ....
           }
        }


execl( char \*cmdPath, char \*arg0, ... )
-----------------------------------------

The final system call which is commonly used with `fork()` and
friends is `execl()`. It is used to replace the current running
program with another program which is loaded from an executable
file on the file system. The arguments passed to `execl()` need to
specify where the file to run is located (its path) and also what
the contents of `char **argv` should be. Thus the number of
arguments is variable. Since the last element in `argv` is a
pointer to `NULL`, the last argument passed to `execl()` should be
a zero.

    ::

        execl( "/usr/bin/cat", "cat", 0 );  /* no extra argument to cat */
        
        execl( "/usr/bin/cat", "cat", "filename", 0 ); /* one extra argument to cat */

.. seealso::

   See :ref:`topic8-example` for a complete example of using `fork`, `pipe`,
   `dup` and `execl` in a working program.

Signals
=======

Signals provide another means of interprocess communication
(besides `pipe`). Signals are also used by the operating system to
communicate with a processes when something has gone wrong.