Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing threads, fork, and mutexes, what should I watch out for?

If I fork a process in which one thread holds a mutex, am I relatively safe if I immediately exec in the child? What things are safe to do in the child before I exec?

If the thread that executes fork then the child goes on to release a mutex before calling exec will this cause problems? What happens if I try to acquire a mutex in a child that the parent process owned before fork (and may or may not still own)?

Are the answers different on different platforms? I'm primarily concerned with Unix variants, and in particular Linux. But I am curious about NT. Though, of course, NT doesn't (to my knowledge) have fork.

like image 528
Omnifarious Avatar asked Jan 18 '13 21:01

Omnifarious


People also ask

What happens if you fork a process with multiple threads?

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( ).

What will happen if a Linux multi threaded process is cloned with fork ()?

fork creates a new process. The parent of a process is another process, not a thread. So the parent of the new process is the old process. Note that the child process will only have one thread because fork only duplicates the (stack for the) thread that calls fork .

Is fork () thread safe?

It's safe to fork in a multithreaded program as long as you are very careful about the code between fork and exec. You can make only re-enterant (aka asynchronous-safe) system calls in that span.

Do mutexes work across processes?

Mutexes can synchronize threads within the same process or in other processes. Mutexes can be used to synchronize threads between processes if the mutexes are allocated in writable memory and shared among the cooperating processes (see mmap(2)), and have been initialized for this task.


1 Answers

See pthread_atfork, especially RATIONALE section, for a discussion of problems related to fork in multithreaded environment. It also gives a hint on what supposed to be valid before and after fork within a child and a parent.

UPDATE: the RATIONALE section is non-normative, and it turned out to be in conflict with other parts of the standard. See this defect report by Dave Butenhof for more details.

Immediate exec after fork is supposed to be safe for any state of multithreaded program (that is, any threads holding any mutexes). As of the things possible between fork and exec, the situation is complicated:

The most important thing is that only one thread (that which called fork) is duplicated in the child process. Consequently, any mutex held by another thread at the moment of fork becomes locked forever. That is (assuming non-process-shared mutexes) its copy in the child process is locked forever, because there is no thread to unlock it.

Releasing mutex after fork is safe when it's possible, that is, if the forking thread owns the mutex in the first place. That's how pthread_atfork handlers usually work: locking mutexes before fork, unlocking in child and unlocking in parent.

As of acquiring a mutex that the process owned before fork (remember, we discuss a copy in the child's address space): if it was owned by a forking thread, it's recursive locking (works for PTHREAD_MUTEX_RECURSIVE); if it was owned by another thread, it remains locked forever and can't be reacquired.

By registering appropriate pthread_atfork handlers, third-party libraries can provide a guarantee of being safe to use between fork and exec. (I would expect it mostly from programming language runtimes, not for general purpose libraries).


After some more research, I would recommend to avoid relying in any way on pthread_atfork, and doing nothing but async-signal-safe calls between fork and exec (abandoning fork/exec for posix_spawn would be even better).

The problem is, fork itself can be invoked in signal handler. It precludes any nontrivial use of pthread_atfork, even if its RATIONALE explicitly mentions unlocking mutexes and recreating threads (!) in a child process.

I think that a "grey area" of different possible interpretations remains:

  1. For pthread_atfork handlers in a program which is known to never call fork in a signal handler.
  2. For non-pthread-atfork actions happening around the fork call which is not in a signal handler.

But it's crystal clear which reading is to be used for portable applications.

like image 76
Anton Kovalenko Avatar answered Nov 03 '22 01:11

Anton Kovalenko