Linux多线程中fork与互斥锁过程示例

 更新时间:2021年11月30日 11:26:25   作者:code-016  
大家好,本篇文章主要讲的是Linux多线程中fork与互斥锁过程示例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下哦

问题提出:

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

(一)初次尝试

代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t mutex;

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

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
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 lock\n");
		sleep(3);
		
		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	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 <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t mutex;

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

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
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 lock\n");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	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 <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

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 lock\n");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}

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 lock\n");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}
	
	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	return 0;
}

结果:

在这里插入图片描述

到此这篇关于Linux多线程中fork与互斥锁过程示例的文章就介绍到这了,更多相关Linux多线程fork与互斥锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Linux在应用层读写寄存器的方法及实现实例

    Linux在应用层读写寄存器的方法及实现实例

    这篇文章主要介绍了Linux在应用层读写寄存器的方法及实现实例的相关资料,需要的朋友可以参考下
    2017-02-02
  • 学习Apache的mod rewrite、access写法

    学习Apache的mod rewrite、access写法

    Apache的mod_rewrite是提供了强大URL操作的杀手级的模块,可以实现几乎所有你梦想的URL操作类型,其代价是你必须接受其复杂性,因为mod_rewrite的主要障碍就是初学者不容易理解和运用,即使是Apache专家有时也会发掘出mod_rewrite的新用途。
    2008-09-09
  • Apache 开通子站点配置方法

    Apache 开通子站点配置方法

    前一段时间突发奇想,想自己给自己做个记录系统,暂且就叫他记录系统吧。其实木的就是记录一些乱七八糟的事情,譬如,账簿,记事本之类的
    2012-06-06
  • linux系统之间通过nfs网络文件系统挂载设置方法

    linux系统之间通过nfs网络文件系统挂载设置方法

    NFS允许一个系统在网络上与他人共享目录和文件,通过使用NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件,下面介绍linux系统之间通过nfs网络文件系统挂载的设置方法
    2014-01-01
  • Linux中find命令的用法汇总

    Linux中find命令的用法汇总

    Linux下find命令在目录结构中搜索文件,并执行指定的操作。Linux下find命令提供了相当多的查找条件,功能很强大。由于find具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。下面我们就来简单汇总下其用法
    2017-03-03
  • linux中tar打包指定路径文件的实现方法

    linux中tar打包指定路径文件的实现方法

    下面小编就为大家带来一篇linux中tar打包指定路径文件的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • CentOS虚拟机克隆后无法上网(网卡信息不一致)问题的解决方法

    CentOS虚拟机克隆后无法上网(网卡信息不一致)问题的解决方法

    这篇文章主要为大家详细介绍了CentOS虚拟机克隆后无法上网,即网卡信息不一致问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • linux CentOS 系统下如何将php和mysql命令加入到环境变量中

    linux CentOS 系统下如何将php和mysql命令加入到环境变量中

    这篇文章主要介绍了linux CentOS 系统下如何将php和mysql命令加入到环境变量中的相关资料,需要的朋友可以参考下
    2016-11-11
  • Linux编译LVGL仿真器出错问题解决

    Linux编译LVGL仿真器出错问题解决

    大家好,本篇文章主要讲的是Linux编译LVGL仿真器出错问题解决,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • Linux打包和压缩工具的使用详解

    Linux打包和压缩工具的使用详解

    对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名 给搞晕。别个不说,单单就压缩文件为例,我们知道在Windows下最常见的压缩文件就只有两种,一是,zip,另一个是.rar。可是Linux就不同 了,它有.gz、.tar.gz、tgz、bz2、.Z、.tar等众多的压缩文件名
    2018-07-07

最新评论