偶然看到CU上的一篇关于讨论的帖子,里面讨论了fork() in thread,里面有很多东西不是很明白,就自己研究了一下,才有了这篇心得。
fork() in thread
一个基本原则是:应当避免在pthread中使用fork(),除非你在新程序中立即执行exec()
这里最关键的一点就是:mutex的状态不会因为fork而发生变化,在parent中是locked的在child中也是locked的。
考虑下面的情况:
线程组A中有线程1和2,线程1中lock了一个mutex a;线程2调用了fork()创建了一个新的进程B,进程B中需要使用mutex a保护的数据,lock(mutex a)。这个时候就会出现问题,
线程2和线程1在同一个线程组里面,共享地址空间,线程1总会unlock(mutex a)的,那么线程2还是可以使用lock(mutex a)的(需要等到线程1调用unlock(mutex a))。但是对于进程B,
也拷贝了mutex a,但是是locked状态,又与线程组不同的地址空间,没有代码来unlock(mutex a),那么它就会hang在lock(mutex a)上面。
上面讨论的情况,可以用下面的流程图来表示:
process A process B
thread 1 thread 2
lock(mutex a)
fork() =====>
lock(mutex a) lock(mutex a)
unlock(mutex a) .....(hang) <===== mutex a locked
......
unlock(mutex a)
参考2里面的一句话,实际上是sun的《多线程编程指南》里面的一段:
例如,假设当T2 fork 新进程时,T1 在进行打印,且对printf() 持有锁定。在子进程中,如果唯一的线程(T2) 调用printf(),则T2 将快速死锁。
刚开始怎么都不理解,后来看了《Programming With Posix Threads》才恍然大悟:
stdio一般使用静态存储空间进行buffer的存放,因此需要一些mutex或者是semphore来访问buffer,因此在stdio操作的mutex在fork_with_thread会引发问题。
再考虑上面的那段话:
T2调用fork()的时候,T1正在printf(),也就是说T1获得了mutex,T2新fork的进程也会得到已经locked的mutex,那么在T2新fork的进程中调用printf,尝试lock(mutex)的话,就会出现上面的问题(新进程hang在lock(mutex)上面)。
参考:
1.《Programming With Posix Threads》
2.fork_with_thread
http://iunknown.javaeye.com/blog/102767
3.Linux多线程编程和Linux 2.6下的NPTL
阅读(3082) | 评论(0) | 转发(0) |