linux之pthread_atfork()函数讲解
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
pthread_atfork()在fork()之前调用,当调用fork时,内部创建子进程前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent ,子进程会调用child。
直接看下代码:
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *doit(void *arg)
{
printf("pid = %d begin doit ...\n", static_cast<int>(getpid()));
pthread_mutex_lock(&mutex);
struct timespec ts = {2, 0};
nanosleep(&ts, NULL);
pthread_mutex_unlock(&mutex);
printf("pid = %d end doit ...\n", static_cast<int>(getpid()));
return NULL;
}
void prepare(void)
{
pthread_mutex_unlock(&mutex);
}
void parent(void)
{
pthread_mutex_lock(&mutex);
}
int main(void)
{
pthread_atfork(prepare, parent, NULL);
printf("pid = %d Entering main ...\n", static_cast<int>(getpid()));
pthread_t tid;
pthread_create(&tid, NULL, doit, NULL);
struct timespec ts = {1, 0};
nanosleep(&ts, NULL);
if (fork() == 0)
{
doit(NULL);
}
pthread_join(tid, NULL);
printf("pid = %d Exiting main ...\n", static_cast<int>(getpid()));
return 0;
}
同样的流程,但在执行fork() 创建子进程之前,先执行prepare(), 将子线程加锁的mutex 解锁下,然后为了与doit() 配对,在创建子进程成功后,父进程调用parent() 再次加锁,这时父进程的doit() 就可以接着解锁执行下去。而对于子进程来说,由于在fork() 创建子进程之前,mutex已经被解锁,故复制的状态也是解锁的,所以执行doit()就不会死锁了。
执行结果如下:
simba@ubuntu:~/Documents/build/debug/bin$ ./deadlock_test2
pid = 4905 Entering main ...
pid = 4905 begin doit ...
pid = 4908 begin doit ...
pid = 4905 end doit ...
pid = 4905 Exiting main ...
simba@ubuntu:~/Documents/build/debug/bin$ pid = 4908 end doit ...
pid = 4908 Exiting main ...
simba@ubuntu:~/Documents/build/debug/bin$
pid = 4905 Entering main ...
pid = 4905 begin doit ...
pid = 4908 begin doit ...
pid = 4905 end doit ...
pid = 4905 Exiting main ...
simba@ubuntu:~/Documents/build/debug/bin$ pid = 4908 end doit ...
pid = 4908 Exiting main ...
simba@ubuntu:~/Documents/build/debug/bin$
可以看到子进程也正常退出了。