在多線程程式設計中,如果某個線程調用了fork()函數建立子程序,建立的子程序将繼承父程序所有的鎖。
如果在父程序中加鎖了,而在子程序中對鎖重新加鎖,将會導緻死鎖,以下是導緻死鎖的代碼
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>
pthread_mutex_t mutex;
void *child(void *arg)
{
printf("child thread add mutex\n");
pthread_mutex_lock(&mutex);
//睡眠5秒是為了讓主線程在建立子程序時,完成加鎖操作
sleep(5);
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_t pid;
pthread_create(&pid ,NULL, child, NULL);
//睡眠1秒是為了子線程完成加鎖
sleep(1);
pid = fork();
if(pid < 0)
{
pthread_join(pid, NULL);
pthread_mutex_destroy(&mutex);
return 1;
}
else if(pid == 0)
{
printf("child process, get lock\n");
//由于子線程已經對鎖進行了加鎖操作,這裡再次加鎖時将會導緻死鎖
pthread_mutex_lock(&mutex);
printf("die mutex blocking\n");
pthread_mutex_unlock(&mutex);
exit(0);
}
else
{
wait(NULL);
}
pthread_join(pid, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
解決方案:
可以使用pthread_atfork(), 清理線程中互斥鎖的狀态
函數原型:
#include<pthread.h>
pthread_atfork(void (*prepare)(void), void(*parent)(void), void(*child)(void))
prepare參數: 在fork()函數建立子程序之前調用,可以用來對多線程中的鎖進行加鎖操作
parent參數 : 在fork()函數建立子程序後,在fork()函數傳回之前,在父程序中被執行,可以用來對多線程中的鎖進行解鎖操作
child參數 : 在fork()函數傳回之前,在子程序中執行,可以用來對多線程中的鎖進行解鎖操作
修改後的代碼
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>
pthread_mutex_t mutex;
void prepare()
{
pthread_mutex_lock(&mutex);
}
void parent()
{
pthread_mutex_unlock(&mutex);
}
void child()
{
pthread_mutex_unlock(&mutex);
}
void *child(void *arg)
{
printf("child thread add mutex\n");
pthread_mutex_lock(&mutex);
//睡眠5秒是為了讓主線程在建立子程序時,完成加鎖操作
sleep(5);
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_t pid;
pthread_create(&pid ,NULL, child, NULL);
//睡眠1秒是為了子線程完成加鎖
sleep(1);
//調用pthread_atfork()函數,對鎖進行處理
pthread_atfork(prepare, parent, child);
pid = fork();
if(pid < 0)
{
pthread_join(pid, NULL);
pthread_mutex_destroy(&mutex);
return 1;
}
else if(pid == 0)
{
printf("child process, get lock\n");
//由于子線程已經對鎖進行了加鎖操作,這裡再次加鎖時将會導緻死鎖
pthread_mutex_lock(&mutex);
printf("die mutex blocking\n");
pthread_mutex_unlock(&mutex);
exit(0);
}
else
{
wait(NULL);
}
pthread_join(pid, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}