一、概述
1、当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量、
读写锁、条件变量的状态继承过来。也就是说,如果父进程中互斥量是锁着的,那么在子进程中互斥量也是锁着的(尽管子进程自己
还没有来得及lock),这是非常不安全的,因为不是子进程自己锁住的,它无法解锁。
2、子进程内部只有一个线程,由父进程中调用fork函数的线程副本构成。如果调用fork的线程将互斥量锁住,那么子进程会拷贝一个
pthread_mutex_lock副本,这样子进程就有机会去解锁了。或者互斥量根本就没被加锁,这样也是可以的,但是你不能确保永远是
这样的情况。
3、pthread_atfork函数给你创造了这样的条件,它会注册三个函数
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
prepare是在fork调用之前会被调用的,parent在fork返回父进程之前调用,child在fork返回子进程之前调用。如果在prepare中加锁所
有的互斥量,在parent和child中解锁所有的互斥量,那么在fork返回之后,互斥量的状态就是未加锁。
4、可以有多个 pthread_atfork函数,这是也就会有多个处理程序(prepare,parent,child)。多个prepare的执行顺序与注册顺序相反,
而parent和child的执行顺序与注册顺序相同
二、实例
1、在线程中 直接使用fork函数
可以看到结果,新线程的子进程已经死锁了
1、当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量、
读写锁、条件变量的状态继承过来。也就是说,如果父进程中互斥量是锁着的,那么在子进程中互斥量也是锁着的(尽管子进程自己
还没有来得及lock),这是非常不安全的,因为不是子进程自己锁住的,它无法解锁。
2、子进程内部只有一个线程,由父进程中调用fork函数的线程副本构成。如果调用fork的线程将互斥量锁住,那么子进程会拷贝一个
pthread_mutex_lock副本,这样子进程就有机会去解锁了。或者互斥量根本就没被加锁,这样也是可以的,但是你不能确保永远是
这样的情况。
3、pthread_atfork函数给你创造了这样的条件,它会注册三个函数
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
prepare是在fork调用之前会被调用的,parent在fork返回父进程之前调用,child在fork返回子进程之前调用。如果在prepare中加锁所
有的互斥量,在parent和child中解锁所有的互斥量,那么在fork返回之后,互斥量的状态就是未加锁。
4、可以有多个 pthread_atfork函数,这是也就会有多个处理程序(prepare,parent,child)。多个prepare的执行顺序与注册顺序相反,
而parent和child的执行顺序与注册顺序相同
二、实例
1、在线程中 直接使用fork函数
点击(此处)折叠或打开
- /*DATE: 2015-4-17
- *AUTHOR: DDDDD
- *DESCRIPTION: 安全使用fork
- */
- #include "apue.h"
-
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
- void *thread_fun(void *arg)
- {
- sleep(1);
- pid_t pid;
- pid = fork();
- if(pid==0)
- {
- pthread_mutex_lock(&mutex);
- printf("child\n");
- pthread_mutex_unlock(&mutex);
- }
- if(pid>0)
- {
- pthread_mutex_lock(&mutex);
- printf("parent\n");
- pthread_mutex_unlock(&mutex);
- }
- }
-
- int main()
- {
- pthread_t tid;
-
- if(pthread_create(&tid, NULL, thread_fun, NULL))
- {
- printf("create new thread failed\n");
- return;
- }
-
- pthread_mutex_lock(&mutex);
- sleep(2);
- pthread_mutex_unlock(&mutex);
- printf("main\n");
- pthread_join(tid, NULL);
-
- return;
- }
![](https://i-blog.csdnimg.cn/blog_migrate/2449f62e185e65be32875bd55759c99e.png)
可以看到结果,新线程的子进程已经死锁了
2、安全的使用fork
点击(此处)折叠或打开
- /*DATE: 2015-4-17
- *AUTHOR: DDDDD
- *DESCRIPTION: 安全的使用fork
- * prepare 在调用fork之前会被调用
- * parent 在fork返回父进程之前被调用
- * child 在fork返回子进程之前被调用
- */
- #include "apue.h"
-
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
- void prepare()
- {
- pthread_mutex_lock(&mutex);
- printf("I'm prepare\n");
- }
-
-
- void parent()
- {
- pthread_mutex_unlock(&mutex);
- printf("I'm parent\n");
- }
- void child()
- {
- pthread_mutex_unlock(&mutex);
- printf("I'm child\n");
- }
-
- void *thread_fun(void *arg)
- {
- sleep(1);
- pid_t pid;
- pthread_atfork(prepare, parent, child);
- pid = fork();
- if(pid==0)
- {
- pthread_mutex_lock(&mutex);
- printf("child process\n");
- pthread_mutex_unlock(&mutex);
- }
- if(pid>0)
- {
- pthread_mutex_lock(&mutex);
- printf("parent process\n");
- pthread_mutex_unlock(&mutex);
- }
- }
-
- int main()
- {
- pthread_t tid;
-
-
- if(pthread_create(&tid, NULL, thread_fun, NULL))
- {
- printf("create new thread failed\n");
- return;
- }
-
- pthread_mutex_lock(&mutex);
- sleep(2);
- printf("main\n");
- pthread_mutex_unlock(&mutex);
- pthread_join(tid, NULL);
-
- pthread_mutex_destroy(&mutex);
-
- return;
- }
![](https://i-blog.csdnimg.cn/blog_migrate/44cc7f8be1279f6f68b95e416c3b20bc.png)