多线程程序执行fork调用是一个比较复杂的问题。首先fork调用的行为大概是复制一个和父进程一样的子进程,然后两个进程以不同的值返回。理论上,父子进程应该是非常相似的。fork调用在单线程上是非常容易理解的,在多线程上就不太好理解了。在多线程程序里存在着多个执行流,换句话说,就是fork()调用点只是一个程序的一个并行执行分支而已。说了这么多,其实真相非常简单。下面是《POSIX多线程程序设计》中的原话:“当多线程进程调用fork创造子进程时,Pthreads指定只用那个调用fork的线程在子进程中存在。”换句话说,就是fork得到的子进程只有一个执行流。
好吧!感觉问题简单多了。但是好像有点不太对劲,一个进程的全部信息不仅仅包括执行流(对应堆栈),还有堆空间数据、bss段和data段等等。这些数据是多线程程序中各个进程共有的,比如一些全局变量。换句话说,就是fork会把这些数据也复制到子进程中。那么问题就来了,比如说一个多线程程序中有一个全局互斥锁。fork会把互斥锁一起复制到子进程中,当然互斥锁的状态也是和复制时父进程中一样的。如果复制时的互斥锁是锁住的,那么程序的逻辑很可能被破坏。因为子进程中只有一个执行流,互斥锁如果不是执行fork的线程锁住的,那结果将是永远锁住,锁住互斥锁的线程在新进程中根本就不存在了。
所以POSIX对这个问题提供了一个解决方案,这就是pthread_atfork。具体的东西一看代码和注释便知。
好吧!感觉问题简单多了。但是好像有点不太对劲,一个进程的全部信息不仅仅包括执行流(对应堆栈),还有堆空间数据、bss段和data段等等。这些数据是多线程程序中各个进程共有的,比如一些全局变量。换句话说,就是fork会把这些数据也复制到子进程中。那么问题就来了,比如说一个多线程程序中有一个全局互斥锁。fork会把互斥锁一起复制到子进程中,当然互斥锁的状态也是和复制时父进程中一样的。如果复制时的互斥锁是锁住的,那么程序的逻辑很可能被破坏。因为子进程中只有一个执行流,互斥锁如果不是执行fork的线程锁住的,那结果将是永远锁住,锁住互斥锁的线程在新进程中根本就不存在了。
所以POSIX对这个问题提供了一个解决方案,这就是pthread_atfork。具体的东西一看代码和注释便知。
atfork注释
/*
* atfork.c
*
* Demonstrate the use of "fork handlers" to protect data
* invariants across a fork.
*/
#include <sys/types.h