apue中的对pthread_atfork的使用说明:
pthread_atfork(void (*prepare)(void),void (*parent)(void), void(*child)(void))
prepare在父进程fork创建子进程之前调用,这里可以获取父进程定义的所有锁;
pthread_atfork(void (*prepare)(void),void (*parent)(void), void(*child)(void))
prepare在父进程fork创建子进程之前调用,这里可以获取父进程定义的所有锁;
child fork返回之前在子进程环境中调用,在这里unlock prepare获得的锁;
parent fork创建了子进程以后,但在fork返回之前在父进程的进程环境中调用的,在这里对prepare获得的锁进行解锁;
1、使用场景
当父进程有多线程时,子进程继承父进程所有的互斥量、读写锁和条件变量的状态,子进程只存在一个线程,它是由父进程中调用fork的线程的副本构成的。如果父进程中的线程占有锁(任一线程),子进程同样占有这些锁。如果父进程马上调用exec,老的地址空间被丢弃,所以锁的状态无关紧要。否则,则要清除锁的状态。
2、猜想
(1)如果子进程并不访问从父进程继承来的互斥量,不使用pthread_atfork是否会影响父进程,子进程的运行?
(2)如果子进程也需要访问从父进程继承来的locked互斥量,不使用pthread_atfork是否会影响父进程,子进程的运行?
(3)如果子进程主动释放从父进程继承来的互斥量,不使用pthread_atfork是否会影响父进程,子进程的运行?
带着这几个疑问,下面进行了几组实验。
3、验证
实验一:子进程并不访问从父进程继承来的互斥量
(1)执行顺序(“|”代表线程的生命周期):
父进程主线程:| ,lock, unlock |
父进程子线程: | lock, fork, ,unlock |
子进程主线程: | |
(2)结果:
父进程的new thread, 能够正常unlock, 主线程能够正常lock, unlock
不使用
pthread_atfork并不会影响父进程,子进程的运行。
(3)代码:
为了简化实验代码,使用了sleep来控制线程之间的同步。
(1)执行顺序(“|”代表线程的生命周期):
父进程主线程:| |
父进程子线程: | lock, fork, unlock,
lock, unlock |
子进程主线程: | run, lock, unlock |
(2)结果:
父进程中的子线程,能够正常unlock, 但是子进程一直没能够getlock
不使用pthread_atfork并不会影响父进程,但是会影响子进程的运行。
(3)代码:
为了简化实验代码,使用了sleep来控制线程之间的同步。
void * thr_main(void * arg)
{
printf("parent process: new thread start \n");
pthread_mutex_lock(&lock);
printf("parent process: new thread get lock \n");
pid_t pid;
if((pid = fork()) < 0)
{
perror("fork");
pthread_exit(0);
}
else if(pid == 0) // child process
{
printf("child process: start\n");
printf("child process: unlock and get lock \n");
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
printf("child process: exit\n");
}
else // parent process
{
sleep(10);
pthread_mutex_unlock(&lock);
printf("parent process: new thread unlock \n");
printf("parent process: new thread exit \n");
}
return ((void*)0);
}
int main(void)
{
printf("parent process: main thread start \n");
int err = 0;
pthread_t tid;
err = pthread_create(&tid, NULL, thr_main, NULL);
if(err != 0)
{
perror("pthread_create");
exit(1);
}
sleep(50);
printf("parent process: main thread exit \n");
return 0;
}
实验三:
子进程主动释放从父进程继承来的互斥量
(1)执行顺序(“|”代表线程的生命周期):
父进程主线程:| |
父进程子线程: | lock, fork, , unlock |
子进程主线程: | run, unlock, lock |
(2)结果:
父子进程都能够正常运行。
(3)代码:
为了简化实验代码,使用了sleep来控制线程之间的同步。
既然,子进程中主动释放锁能够起到跟
pthread_atfork一样的效果,相比而言,pthread_atfork有些什么好处呢?
有可能是为了更好的管理代码,使用pthread_atfork,只需要处理自己写的代码;而前者需要做统一的管理,容易出现遗漏;
5、更进一步思考
第三方库(如libc库),如果大量使用了锁(如malloc),但是库并没有使用
pthread_atfork来注册清理函数,则我们需要谨慎在多线程中使用fork。