Next: Streams and Fork, Previous: Threads and Signal Handling, Up: POSIX Threads
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
.
pthread_atfork
registers handler functions to be called just before and just after a new process is created withfork
. 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 beforefork
returns. The child handler will be called from the child process, just beforefork
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. Atfork
time, the prepare handlers are called in LIFO order (last added withpthread_atfork
, first called beforefork
), 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 returnsENOMEM
. Otherwise it returns 0.The functions
fork
andpthread_atfork
must not be regarded as reentrant from the context of the handlers. That is to say, if apthread_atfork
handler invoked from withinfork
callspthread_atfork
orfork
, 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. The mutexes are not usable after
the fork
and must be initialized with pthread_mutex_init
in the child process. This is a limitation of the current
implementation and might or might not be present in future versions.
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.