Process duplication and termination

Because all processes have at least one thread, creating (that is, duplicating) and terminating a process implies the creation and the termination of threads.

This section describes the interactions between threads and processes when duplicating and terminating a process.

Read the following to learn more about process duplication and termination:

Forking

Programmers call the fork subroutine in the following cases:

  • To create a new flow of control within the same program. AIX® creates a new process.
  • To create a new process running a different program. In this case, the call to the fork subroutine is soon followed by a call to one of the exec subroutines.

In a multithreaded program, the first use of the fork subroutine, creating new flows of control, is provided by the pthread_create subroutine. The fork subroutine should thus be used only to run new programs.

The fork subroutine duplicates the parent process, but duplicates only the calling thread; the child process is a single-threaded process. The calling thread of the parent process becomes the initial thread of the child process; it may not be the initial thread of the parent process. Thus, if the initial thread of the child process returns from its entry-point routine, the child process terminates.

When duplicating the parent process, the fork subroutine also duplicates all the synchronization variables, including their state. Thus, for example, mutexes may be held by threads that no longer exist in the child process and any associated resource may be inconsistent.

It is strongly recommended that the fork subroutine be used only to run new programs, and to call one of the exec subroutines as soon as possible after the call to the fork subroutine in the child process.

Fork handlers

The preceding forking rule does not address the needs of multithreaded libraries. Application programs may not be aware that a multithreaded library is in use and will call any number of library routines between the fork and the exec subroutines, just as they always have. Indeed, they may be old single-threaded programs and cannot, therefore, be expected to obey new restrictions imposed by the threads library.

On the other hand, multithreaded libraries need a way to protect their internal state during a fork in case a routine is called later in the child process. The problem arises especially in multithreaded input/output libraries, which are almost sure to be invoked between the fork and the exec subroutines to affect input/output redirection.

The pthread_atfork subroutine provides a way for multithreaded libraries to protect themselves from innocent application programs that call the fork subroutine. It also provides multithreaded application programs with a standard mechanism for protecting themselves from calls to the fork subroutine in a library routine or the application itself.

The pthread_atfork subroutine registers fork handlers to be called before and after the call to the fork subroutine. The fork handlers are executed in the thread that called the fork subroutine. The following fork handlers exist:
Subroutine Description
Prepare The prepare fork handler is called just before the processing of the fork subroutine begins.
Parent The parent fork handler is called just after the processing of the fork subroutine is completed in the parent process.
Child The child fork handler is called just after the processing of the fork subroutine is completed in the child process.

Process termination

The prepare fork handlers are called in last-in first-out (LIFO) order, whereas the parent and child fork handlers are called in first-in first-out (FIFO) order. This allows programs to preserve any desired locking order.

When a process terminates, by calling the exit, atexit, or _exit subroutine either explicitly or implicitly, all threads within the process are terminated. Neither the cleanup handlers nor the thread-specific data destructors are called.
Note: The unatexit subroutine unregisters functions that were previously registered by the atexit subroutine. If the referenced function is found, it is removed from the list of functions that are called at normal program termination.

The reason for this behavior is that there is no state to leave clean and no thread-specific storage to reclaim, because the whole process terminates, including all the threads, and all the process storage is reclaimed, including all thread-specific storage.