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之如何停止正在执行脚本问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • 浅谈Linux下修改/设置环境变量JAVA_HOME的方法

    浅谈Linux下修改/设置环境变量JAVA_HOME的方法

    这篇文章主要介绍了浅谈Linux下修改/设置环境变量JAVA_HOME的方法,环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。感兴趣的可以了解一下
    2020-07-07
  • 解读crontab脚本错误日志和正确的输出写入到文件

    解读crontab脚本错误日志和正确的输出写入到文件

    这篇文章主要介绍了解读crontab脚本错误日志和正确的输出写入到文件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Linux下的Memcache安装方法

    Linux下的Memcache安装方法

    最近在研究怎么让Discuz!去应用Memcache去做一些事情,记录下Memcache安装的过程。
    2010-05-05
  • Linux gzip 命令的使用

    Linux gzip 命令的使用

    这篇文章主要介绍了Linux gzip 命令的使用,帮助大家更好的理解和学习Linux系统,感兴趣的朋友可以了解下
    2020-08-08
  • Linux服务器上安装JDK全过程

    Linux服务器上安装JDK全过程

    文章内容总结:本文详细介绍了在Linux服务器上安装Java的步骤,包括下载JDK、上传服务器、解压缩、配置环境变量等,并提供了一个简单的命令来验证安装是否成功,希望本文能为读者提供有用的参考
    2024-11-11
  • Linux防火墙的配置全过程

    Linux防火墙的配置全过程

    这篇文章主要介绍了Linux防火墙的配置全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • CentOS服务器iptables配置简单教程

    CentOS服务器iptables配置简单教程

    这篇文章主要为大家详细介绍了CentOS服务器iptables配置简单教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • VMware虚拟机中Ubuntu18.04无法连接网络的解决办法

    VMware虚拟机中Ubuntu18.04无法连接网络的解决办法

    这篇文章主要为大家详细介绍了VMware虚拟机中Ubuntu18.04无法连接网络的解决办法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • 详解阿里云Linux启动tomcat并能外网访问

    详解阿里云Linux启动tomcat并能外网访问

    本篇文章主要介绍了详解阿里云Linux启动tomcat并能外网访问,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03

最新评论