天天看點

在多線程中使用fork函數導緻死鎖,以及解決方案

    在多線程程式設計中,如果某個線程調用了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;
}
           
c