栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

【Linux】多线程中fork与互斥锁

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Linux】多线程中fork与互斥锁

文章目录
      • 问题提出:
        • (一)初次尝试
        • (二)理性分析
        • (三)解决问题
          • (1)使用pthread_join()
          • (2)使用phread_atfork()注册一个fork之前的判断

问题提出:

我们有这样一个问题:在一个多线程程序中创建子进程并且让子线程和子进程去获取一把全局变量的锁,输出子线程得到锁,然后解锁,子进程拿到锁,然后解锁;

(一)初次尝试
  • 代码:
#include 
#include 
#include 
#include 
#include 

pthread_mutex_t mutex;

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lockn");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlockn");
}
int main()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_create(&id, NULL, fun, NULL);
	
	sleep(1);
	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);	
		printf("child get lockn");
		sleep(3);
		
		pthread_mutex_unlock(&mutex);
		printf("child unlockn");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main overn");
	return 0;
}
  • 猜想结果:

理一理思路:

  • 创建一把全局的锁,并初始化
    主线程创建子线程,去获取这把锁的同时,主线程休眠一秒,子线程得到这把锁,加锁fun get lock
    子线程休眠3秒,输出解锁fun unlock,子线程退出
    主线程开始fork,子进程得到这把锁,输出child lock
    子进程解锁输出child unlock
    父进程的主线程等待子进程的退出,最后销毁锁,输出main over
    所以…直接得到正确代码!!!
(二)理性分析

很遗憾,答案是错的!!!
我们先来康康运行结果:正常输出了子线程的内容,但是。。。。卡住了?没错阻塞了。。

再次分析:

  • 阻塞??难道是子进程获取锁时阻塞了?还是父进程等待子进程阻塞了?
  • 或者说:两处地方都阻塞了,子进程获取锁时阻塞,导致父进程阻塞。
  • 验证一下!!


所以程序就是两处地方都阻塞了,子进程获取锁时阻塞,导致父进程阻塞。

(三)解决问题

实际上,我们子线程在获取这把锁并加锁后睡眠3秒,主线程睡眠1秒,在主线程1秒睡眠结束后,开始执行fork,此时的子线程还未解锁正处于睡眠状态,fork过程中,会直接复制父进程的所有资源(**包括这把锁、锁的状态**),没错就是有两把锁。此时子线程进行了加锁的状态,所以子线程复制的锁也是加锁状态。所以子线程会正常退出,而子进程会因为拿到加锁的锁而阻塞,父进程wait因为子进程阻塞而阻塞;

(1)使用pthread_join()

fork之前使用pthread_join()在子线程结束之前,主线程都将会阻塞,等待子线程结束后,在进行fork,此时子进程得到的锁就是解锁状态

  • 代码:
#include 
#include 
#include 
#include 
#include 

pthread_mutex_t mutex;

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lockn");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlockn");
}
int main()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_create(&id, NULL, fun, NULL);
	pthread_join(id, NULL);
	
	sleep(1);

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);	
		printf("child get lockn");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlockn");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main overn");
	return 0;
}
  • 结果:
(2)使用phread_atfork()注册一个fork之前的判断

头文件 : pthread.h
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

  • prepare : fork执行之前调用该函数
  • parent : fork执行之后父进程调用该函数
  • child : fork执行之后子进程调用该函数
  • 返回值: 成功0,失败错误码
  • 代码:
#include 
#include 
#include 
#include 
#include 

pthread_mutex_t mutex;

void prepare_fun(void)
{
	pthread_mutex_lock(&mutex);
}

void parent_fun(void)
{
	pthread_mutex_unlock(&mutex);
}

void child_fun()
{
	pthread_mutex_unlock(&mutex);
}

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lockn");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlockn");
}

int main()
{
	
	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_atfork(prepare_fun, parent_fun, child_fun);
	pthread_create(&id, NULL, fun, NULL);
	
	sleep(1);

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);	
		printf("child get lockn");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlockn");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main overn");
	return 0;
}
  • 结果:
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/617891.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号