Situation: I have a multithreaded program written in C. If one of the threads forks, the child process is replaced by another using exec() and the parent waits for the child to exit.
Problem: After the child process is created by fork() there are a few lines of code that compile the arguments to be used in the following exec() command.
Hypothesis Am I correct in assuming that in the time between the child process being created by fork() and being replaced by exec(), the child process - being a copy of the parent - will have all the threads of the parent and therefore these threads will run - albeit for a very brief period?
If so, is the correct solution to call exec() immediately after fork()?
The fork( ) system call creates an exact duplicate of the address space from which it is called, resulting in two address spaces executing the same code. Problems can occur if the forking address space has multiple threads executing at the time of the fork( ).
Concurrency and Parallelism In a multithreaded process on a single processor, the processor can switch execution resources between threads, resulting in concurrent execution. Concurrency indicates that more than one thread is making progress, but the threads are not actually running simultaneously.
So when processing a task in a thread is trivial, the cost of creating a thread will create more overhead than distributing the task. This is one case where a single thread will be faster than multithreading.
The POSIX fork() or Solaris fork1() duplicates only the thread that calls it. (Calling the Solaris fork() duplicates all threads, so this issue does not come up.)
Only the thread that calls fork
will be running in the new process. However, there are limits to which functions you can call before exec
. From fork
:
A process shall be created with a single thread. If a multi-threaded process calls
fork()
, the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources. Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of theexec
functions is called. Fork handlers may be established by means of thepthread_atfork()
function in order to maintain application invariants acrossfork()
calls.
I believe this means you should generally be okay, as long as any multi-threaded
libraries use pthread_atfork
properly.
EDIT: The pthread_atfork
page explains further how the library can protect itself:
The expected usage is that the prepare handler acquires all mutex locks and the other two fork handlers release them.
For example, an application can supply a prepare routine that acquires the necessary mutexes the library maintains and supply child and parent routines that release those mutexes, thus ensuring that the child gets a consistent snapshot of the state of the library (and that no mutexes are left stranded). Alternatively, some libraries might be able to supply just a child routine that reinitializes the mutexes in the library and all associated states to some known value (for example, what it was when the image was originally executed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With