GNU Info

Info Node: (libc.info)Threads and Fork

(libc.info)Threads and Fork


Next: Streams and Fork Prev: Threads and Signal Handling Up: POSIX Threads
Enter node , (file) or (file)node

Threads and Fork
================

   It's not intuitively obvious what should happen when a
multi-threaded POSIX process calls `fork'. Not only are the semantics
tricky, but you may need to write code that does the right thing at
fork time even if that code doesn't use the `fork' function. Moreover,
you need to be aware of interaction between `fork' and some library
features like `pthread_once' and stdio streams.

   When `fork' is called by one of the threads of a process, it creates
a new process which is copy of the  calling process. Effectively, in
addition to copying certain system objects, the function takes a
snapshot of the memory areas of the parent process, and creates
identical areas in the child.  To make matters more complicated, with
threads it's possible for two or more threads to concurrently call fork
to create two or more child processes.

   The child process has a copy of the address space of the parent, but
it does not inherit any of its threads. Execution of the child process
is carried out by a new thread which returns from `fork' function with
a return value of zero; it is the only thread in the child process.
Because threads are not inherited across fork, issues arise. At the
time of the call to `fork', threads in the parent process other than
the one calling `fork' may have been executing critical regions of
code.  As a result, the child process may get a copy of objects that
are not in a well-defined state.  This potential problem affects all
components of the program.

   Any program component which will continue being used in a child
process must correctly handle its state during `fork'. For this
purpose, the POSIX interface provides the special function
`pthread_atfork' for installing pointers to handler functions which are
called from within `fork'.

 - Function: int pthread_atfork (void (*PREPARE)(void), void
          (*PARENT)(void), void (*CHILD)(void))
     `pthread_atfork' registers handler functions to be called just
     before and just after a new process is created with `fork'. The
     PREPARE handler will be called from the parent process, just
     before the new process is created. The PARENT handler will be
     called from the parent process, just before `fork' returns. The
     CHILD handler will be called from the child process, just before
     `fork' returns.

     `pthread_atfork' returns 0 on success and a non-zero error code on
     error.

     One or more of the three handlers PREPARE, PARENT and CHILD can be
     given as `NULL', meaning that no handler needs to be called at the
     corresponding point.

     `pthread_atfork' can be called several times to install several
     sets of handlers. At `fork' time, the PREPARE handlers are called
     in LIFO order (last added with `pthread_atfork', first called
     before `fork'), while the PARENT and CHILD handlers are called in
     FIFO order (first added, first called).

     If there is insufficient memory available to register the handlers,
     `pthread_atfork' fails and returns `ENOMEM'.  Otherwise it returns
     0.

     The functions `fork' and `pthread_atfork' must not be regarded as
     reentrant from the context of the handlers.  That is to say, if a
     `pthread_atfork' handler invoked from within `fork' calls
     `pthread_atfork' or `fork', the behavior is undefined.

     Registering a triplet of handlers is an atomic operation with
     respect to fork.  If new handlers are registered at about the same
     time as a fork occurs, either all three handlers will be called,
     or none of them will be called.

     The handlers are inherited by the child process, and there is no
     way to remove them, short of using `exec' to load a new pocess
     image.


   To understand the purpose of `pthread_atfork', recall that `fork'
duplicates the whole memory space, including mutexes in their current
locking state, but only the calling thread: other threads are not
running in the child process. Thus, if a mutex is locked by a thread
other than the thread calling `fork', that mutex will remain locked
forever in the child process, possibly blocking the execution of the
child process. Or if some shared data, such as a linked list, was in the
middle of being updated by a thread in the parent process, the child
will get a copy of the incompletely updated data which it cannot use.

   To avoid this, install handlers with `pthread_atfork' as follows:
have the PREPARE handler lock the mutexes (in locking order), and the
PARENT handler unlock the mutexes. The CHILD handler should reset the
mutexes using `pthread_mutex_init', as well as any other
synchronization objects such as condition variables.

   Locking the global mutexes before the fork ensures that all other
threads are locked out of the critical regions of code protected by
those mutexes.  Thus when `fork' takes a snapshot of the parent's
address space, that snapshot will copy valid, stable data.  Resetting
the synchronization objects in the child process will ensure they are
properly cleansed of any artifacts from the threading subsystem of the
parent process. For example, a mutex may inherit a wait queue of
threads waiting for the lock; this wait queue makes no sense in the
child process. Initializing the mutex takes care of this.


automatically generated by info2www version 1.2.2.9