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.
See pthread_atfork, especially RATIONALE section, for a discussion of problems related to
forkin multithreaded environment. It also gives a hint on what supposed to be valid before and afterforkwithin 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
execafterforkis supposed to be safe for any state of multithreaded program (that is, any threads holding any mutexes). As of the things possible betweenforkandexec, 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 offorkbecomes 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
forkis safe when it’s possible, that is, if theforking thread owns the mutex in the first place. That’s howpthread_atforkhandlers usually work: locking mutexes beforefork, 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 forPTHREAD_MUTEX_RECURSIVE); if it was owned by another thread, it remains locked forever and can’t be reacquired.By registering appropriate
pthread_atforkhandlers, third-party libraries can provide a guarantee of being safe to use betweenforkandexec. (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 betweenforkandexec(abandoningfork/execforposix_spawnwould be even better).The problem is,
forkitself can be invoked in signal handler. It precludes any nontrivial use ofpthread_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:
pthread_atforkhandlers in a program which is known to never callforkin a signal handler.forkcall which is not in a signal handler.But it’s crystal clear which reading is to be used for portable applications.