当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥里、读写锁、条件变里的状态继承过来。也就是说,如果父进程中互斥里是锁着的,那么在子进程中互斥里也是锁着的(尽管子进程自己还没有来得及lock),这是非常不安全的,因为不是子进程自己锁住的,它无法解锁。
实例
代码:
#include "apue.h"
#include <pthread.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);
}
else 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 0;
}
运行结果:
child线程进入死锁过程。
子进程内部只有一个线程,由父进程中调用fork函数的线程副本构成。如果调用fork的线程将互斥量锁住,那么子进程会拷贝一个pthread_mutex_lock副本,这样子进程就有机会去解锁了。或者互斥里根本就没被加锁,这样也是可以的,但是你不能确保永远是这样的情况。
实例
代码:
#include "apue.h"
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_fun(void *arg)
{
sleep(1);
printf("new thread\n");
pid_t pid;
pthread_mutex_lock(&mutex);
pid = fork();
if (pid == 0)
{
pthread_mutex_unlock(&mutex);
printf("child\n");
}
else if (pid > 0)
{
pthread_mutex_unlock(&mutex);
printf("parent\n");
}
}
int main()
{
pthread_t tid;
if (pthread_create(&tid, NULL, thread_fun, NULL))
{
printf("create new thread failed\n");
return;
}
printf("main\n");
pthread_join(tid, NULL);
return 0;
}
运行结果:
pthread_atfork函数,会注册三个函数
#include <pthread.h>
int pthread_atfork(void (*prepare)(void),void (*parent)(void), void(*child)(void) );
prepare是在fork调用之前被调用,作用是获取父进程定义的所有锁;parent在fork返回父进程之前调用, 作用是对prepare处理程序获取的所有锁进行解锁;child在fork返回子进程之前调用,作用同parent一样。如果在prepare在中加锁所有的互斥量,在parent和child中解锁所有的互斥量,那么在fork返回之后,互斥量的状态就是未加锁。
可以有多个pthread_atfork函数,也就会有多个处理程序(prepare、parent、child)。多个prepare的执行顺序与注册顺序相反,而parent和child的执行顺序与注册顺序相同。
实例:
代码:
#include "apue.h"
#include <pthread.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);
}
else 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 0;
}
运行结果: