wait和fork在多线程程序中的注意事项
我们都知道fork函数可以创建一个子进程,而其内存资源是父进程的一个拷贝,比如打开的文件描述符,变量等都是和父进程一模一样的,而wait函数则是父进程用于阻塞等待子进程的退出并且回收子进程的资源。
但是如果执行fork函数和wait函数的进程恰好是多线程程序又会怎么样呢,最近在开发多进程程序的时候就遇到了这样一个问题。
当我们fork一个子进程时,如果父进程需要等待子进程退出后再继续,那么就需要调用wait函数阻塞父进程,可父进程是一个多线程程序呀,我们都知道进程是操作系统分配资源的最小单位,而线程是调度的最小单位,wait究竟会阻塞整个进程的所有线程还是只会阻塞调用wait的那个线程呢,这关系到父进程的其他线程的处理。经过一系列实验之后,我最终得出了结果,这里先贴出来:
·fork函数fork出的子进程永远是一个单线程进程,而且该线程对应的是父进程中调用fork函数的线程。
·wait函数仅会阻塞父进程中调用wait函数的线程,其余线程不会被wait阻塞。
如果你想了解实验过程的话,请继续往下看。
为了测试fork函数和wait函数对多线程进程的影响,我写了以下程序:
代码中关键的地方在于:父进程在主线程首先创建了一个线程1,然后再fork一个子进程。
运行结果如下:

从运行结果我们可以推理出2点:
①从线程1中打印的进程ID消息来看,这个线程1属于父进程,但没有看到来自子进程的线程1消息,由此可以确定,子进程中没有线程1在执行,而父进程的线程1仍在执行。
②子进程打印完3次”child process msg”后,继续打印了3次”main thread msg”后退出,而这时,因为子进程的退出导致父进程就绪,父进程继续往下执行打印3次”main thread msg”后退出。由此可以确定,子进程的主线程在执行,而父进程的主线程被阻塞。
以上2点可以说明,子进程只fork了父进程的主线程,父进程的主线程因为wait而被阻塞,但其线程1没有被阻塞。
到这里可以证明文章开头的结论了吗,不,还不行,我们只是证明了fork结论的前半句,wait结论的后半句。fork的子进程的线程对应的是父进程的哪一个线程还无法证明,万一不论怎样都是fork父进程的主线程呢,同理wait也是,因此我们需要做第二个实验。
第二个实验与第一个实验大同小异,区别在于,父进程创建子进程的操作从父进程的主线程移动到了父进程的线程1中:
运行结果:

从这个结果同样也能看出2点:
①通过打印的”thread 1 msg”后面的进程ID来看,这是子进程的线程1在执行,但是没有看到来自子进程的主线程消息,由此可以确定,子进程中没有原本来自父进程的主线程。
②通过打印的”main thread msg”后面的进程ID来看,这是父进程的主线程在执行,而父进程的线程1由于调用了wait已经被阻塞了。
综合两次实验结果,足够确定开头的结论是正确的了。因此在一些多线程程序中使用这两个函数必须明确调用它们的线程以及对应的处理方法。