[APUE] 线程和fork
2014-04-17 20:14
246 查看
1 线程中调用fork()产生的问题
线程可以通过调用fork()来创建新的进程,新的进程只有一个线程,它是调用fork()的线程的副本。由于写时拷贝(创建新的进程时,子进程共享父进程的地址空间,只有父进程或者子进程进行写操作时,才会拷贝父进程的东西来创建新的子进程的地址空间)的作用,此时的子进程中的线程共享父进程的调用fork()的线程的地址空间,如果父进程或者子进程对内存做了改动,就会创建父进程的副本,此时,子进程就从父进程那么继承了所有互斥量、读写锁和条件变量的状态。但是,如果父进程在调用fork()之前就获得了某些锁,而子进程获得的状态是锁定的,它就没有办法知道是否该释放哪些锁。换句话说,子进程中的锁是被不存在的线程锁定的。因此,该锁永远不会被释放,
2 解决方案
通常建议,在调用fork()后,子进程立即调用exec()来重置子进程的所有状态。
但是,这并没有从根本上解决问题。应用程序并不知道关于锁的任何问题,他们可能会在fork()和exec()之间调用其它的函数,那么,原来的问题还是来了。
为了解决这个问题,poxis多线程库提供了pthread_atfork()函数。
pthread_atfork()为多线程提供了一种保护子进程的机制,允许程序清理锁的状态。
从它的原型可以看到,它的参数是三个函数:prepare, parent, child。他们分别在三个时期进行调用。
prepare由父进程在fork()创建子进程前调用,负责获取父进程的所有锁。
parent在fork()创建子进程之后,返回子进程前在父进程环境中调用,负责释放prepare获得的所有锁。
child在fork()返回之前,在子进程环境中调用,负责释放prepare获得的所有锁。
线程可以通过调用fork()来创建新的进程,新的进程只有一个线程,它是调用fork()的线程的副本。由于写时拷贝(创建新的进程时,子进程共享父进程的地址空间,只有父进程或者子进程进行写操作时,才会拷贝父进程的东西来创建新的子进程的地址空间)的作用,此时的子进程中的线程共享父进程的调用fork()的线程的地址空间,如果父进程或者子进程对内存做了改动,就会创建父进程的副本,此时,子进程就从父进程那么继承了所有互斥量、读写锁和条件变量的状态。但是,如果父进程在调用fork()之前就获得了某些锁,而子进程获得的状态是锁定的,它就没有办法知道是否该释放哪些锁。换句话说,子进程中的锁是被不存在的线程锁定的。因此,该锁永远不会被释放,
2 解决方案
通常建议,在调用fork()后,子进程立即调用exec()来重置子进程的所有状态。
但是,这并没有从根本上解决问题。应用程序并不知道关于锁的任何问题,他们可能会在fork()和exec()之间调用其它的函数,那么,原来的问题还是来了。
为了解决这个问题,poxis多线程库提供了pthread_atfork()函数。
pthread_atfork()为多线程提供了一种保护子进程的机制,允许程序清理锁的状态。
int pthread_atfork(void (*prepare)(), void (*parent)(), void (*child)());
从它的原型可以看到,它的参数是三个函数:prepare, parent, child。他们分别在三个时期进行调用。
prepare由父进程在fork()创建子进程前调用,负责获取父进程的所有锁。
parent在fork()创建子进程之后,返回子进程前在父进程环境中调用,负责释放prepare获得的所有锁。
child在fork()返回之前,在子进程环境中调用,负责释放prepare获得的所有锁。
相关文章推荐
- ASP.NET线程相关配置
- 浅析linux环境下一个进程最多能有多少个线程
- 解析Java线程同步锁的选择方法
- 深入Android线程的相关问题解惑
- 深入探讨linux下进程的最大线程数、进程最大数、进程打开的文件数
- Java线程关闭的3种方法
- JAVA实现线程的三种方法
- 深入Java线程中断的本质与编程原则的概述
- Java线程模型缺陷
- C#线程定义和使用方法详解
- android开发教程之使用线程实现视图平滑滚动示例
- .net让线程支持超时的方法实例和线程在执行结束后销毁的方法
- java多线程编程之使用runnable接口创建线程
- java线程之线程的生命周期的使用
- java多线程编程之线程的生命周期
- Java虚拟机最多支持多少个线程的探讨
- JAVA中 终止线程的方法介绍
- java中thread线程start和run的区别
- Java线程的相关方法详细解析
- java多线程编程之java线程简介