1.某个线程调用fork()函数:
在一个多线程程序中的某个线程调用了fork函数,那么子进程只会拥有一个执行线程(调用fork函数的线程),其他"已经"创建的线程将不会复制给子进程,子进程多线程的情况是在调用fork函数的子线程之后调用pthread_create函数实现的。
2.调用fork函数之后锁的继承:
由fork函数创建的子进程会继承父进程的锁及其状态,但子进程可能不清楚从父进程继承而来的互斥锁的具体状态(是加锁还是解锁状态),这个互斥锁可能被加锁了,但是并不是由调用fork函数的那个线程锁住的,而是由其他线程锁住的。如果是这种情况,则子进程若再次对该互斥锁执行加锁操作就会导致死锁
确保fork调用后父进程和子进程都拥有一个清楚的锁状态的函数是 pthread_atfork;
int thread_atfork
(
void
(*prepare)(
void
),
void
(*parent)(
void
),
void
(*child)(
void
));
- prepare处理函数由父进程在fork创建子进程前调用,这个函数的任务是获取父进程定义的所有锁 。
- parent处理函数是在fork创建了子进程以后,但在fork返回之前在父进程环境中调用的。它的任务是对prepare获取的所有锁解锁。
- child处理函数在fork返回之前在子进程环境中调用,与parent处理函数一样,它也必须解锁所有prepare中所获取的锁。
下面代码并不是加锁一次解锁了两次,而是各自独自解锁。因为prepare函数是在创建子进程之前执行的,因此此时互斥锁是锁住的状态,parent函数执行是在子进程创建之后,其首先是对prepare中锁住的互斥锁解锁,但此时在子进程中任然有一个锁住的互斥锁的副本(fork的写时复制机制),因此需要在child中再次解锁。
需要注意的是pthread_atfork只能清理锁,但不能清理条件变量。在有些系统的实现中条件变量不需要清理。但是在有的系统中,条件变量的实现中包含了锁,这种情况就需要清理。但是目前并没有清理条件变量的接口和方法。
下面是引用别人的一段代码(使用非常清楚):
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<pthread.h>
//使用pthread_atfork函数进行获取锁
pthread_mutex_t mutex;
void *fun(void *arg)
{
printf("fun will get pthread\n");
pthread_mutex_lock(&mutex);
printf("fun mutex locked\n");
sleep(5);
pthread_mutex_unlock(&mutex);
printf("fun mutex unlcok\n");
}
void prepare() //pthread_atfork一旦被调用就会执行该函数,但是需要等待fun释放锁才可以将锁加上
{
pthread_mutex_lock(&mutex);
printf("prepare get mutex\n");
}
void parent()
{
pthread_mutex_unlock(&mutex);
printf("parent progress get mutex\n");
}
void child()
{
pthread_mutex_unlock(&mutex);
printf("child progress get mutex\n");
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_t id;
int res=pthread_create(&id,NULL,fun,NULL);
assert(res==0);
sleep(1);
pthread_atfork(prepare,parent,child);
if(fork()) //父进程与子进程相当与加了两把不同的锁了,没有什么关系了
{
printf("father will get mutex\n");
pthread_mutex_lock(&mutex);
sleep(1);
printf("father lock success\n");
pthread_mutex_unlock(&mutex);
printf("father over\n");
}
else
{
printf("child will get mutex\n");
pthread_mutex_lock(&mutex);
printf("child lock success\n");
sleep(2);
pthread_mutex_unlock(&mutex);
printf("child over\n");
}
}