互斥量实现原理探究

news2025/1/24 6:00:11

在这里插入图片描述

文章目录

  • 1. 如何实现线程的加锁和解锁
  • 2. 封装一个锁
  • 3. 可重入和线程安全
    • 3.1 可重入与线程安全联系
    • 3.2 可重入与线程安全区别
  • 4. 常见锁概念
    • 4.1 死锁
    • 4.2 代码实现
    • 4.3 死锁四个必要条件

1. 如何实现线程的加锁和解锁

经过上一篇文章的例子,大家已经意识到单纯的 i++ 或者 ++i 都不是原子的,如果我们能让它变成一条汇编语句那么就是原子的。

为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性

lock的伪代码
在这里插入图片描述
这里的%al是CPU里的寄存器,mutex是内存中的一个变量

现在有一个问题,当有多个线程一起执行第一句move时(意思是将0移到寄存器里),线程2的0会覆盖线程1的0吗?线程3的0会覆盖线程2的0吗
答案是:不会的。因为在寄存器中的数据,全部都是线程内部的上下文。多个线程看起来同时访问寄存器,但是互不影响。因为只有当某一个线程从CPU切走,另外一个线程才能被调度

过程如下
在这里插入图片描述
假设内存中的mutex变量里面的值是1,当线程1来加锁时,如果执行完第一句move后,就被切走了,线程2来执行。
在这里插入图片描述
那么线程2来执行move后,将0放进寄存器中:
在这里插入图片描述
然后xchgb一步将0和1进行交换:
在这里插入图片描述
那么此时如果线程2被切走,又来个优先级更高的线程3呢?
在这里插入图片描述
还是一样,线程2把寄存器上下文带走,线程3把0移到寄存器中,一步交换寄存器和内存mutex值,不过寄存器里面的值还是0。再后面if判断的时候,不会加锁,而是挂起。其它线程也是一样的道理。

unlock的伪代码
在这里插入图片描述
解锁就简单了,只需要将1写回到内存就可以了。

本质:将数据从内存读入寄存器,也就是将数据从共享变成线程私有

2. 封装一个锁

在这里插入图片描述
我们在这里锁的四步封装成一个类。
在这里插入图片描述
这里就是我们传一个锁进行加锁和解锁的类。
在这里插入图片描述
我们先全局声明自己的锁,声明的时候就初始化。
在这里插入图片描述
这是抢一次票的函数,我们在临界区是定义一个局部对象来完成加锁。当一次票就在析构的时候自动解锁。这就是RAII思想。
在这里插入图片描述
这是我们的多次抢票,当抢不到票时就break。
在这里插入图片描述
从运行结果可以看出:可以完成加锁和解锁操作。

那么以后我们可以这样去使用:

int cnt = 10000;
int main()
{
	//代码块
   {
    //临界资源
    LockGuard LockGuard(&mymutex);
    cnt++;
    ...
    ...
    ...
   }
}

3. 可重入和线程安全

线程安全:多个线程并发同一段代码时,不会出现不同的结果。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,会出现问题

重入:同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入,我们称之为重入。一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数

在这里插入图片描述
像上面抢票的例子,这个函数就是被重入了,因为线程安全的问题,需要加锁。而函数里的局部变量,每个线程各自一份,则不需要加锁。

常见的线程不安全的情况
1.不保护共享变量的函数。
2.函数状态随着被调用,状态发生变化的函数。
3.返回指向静态变量指针的函数。
4.调用线程不安全函数的函数。

常见的线程安全的情况
1.每个线程对全局变量或者静态变量只有读取的权限,而没有写入的权限,一般来说这些线程是安全的。
2.类或者接口对于线程来说都是原子操作。
3.多个线程之间的切换不会导致该接口的执行结果存在二义性。

常见不可重入的情况
1.调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的。
2.调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
3.可重入函数体内使用了静态的数据结构。

常见可重入的情况
1.不使用全局变量或静态变量。
2.不使用用malloc或者new开辟出的空间。
3.不调用不可重入函数。
4.不返回静态或全局数据,所有数据都有函数的调用者提供。
5.使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。

3.1 可重入与线程安全联系

1.函数是可重入的,那就是线程安全的。
2.函数是不可重入的,那就不能由多个线程使用,有可能引发线程安全问题。
3.如果一个函数中有全局变量,那么这个函数既不是线程安全也不是可重入的。

3.2 可重入与线程安全区别

1.可重入函数是线程安全函数的一种。
2.线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数,若锁还未释放则会产生死锁,因此是不可重入的。

4. 常见锁概念

4.1 死锁

死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其它进程所占用不会释放的资源而处于的一种永久等待状态

4.2 代码实现

在这里插入图片描述
我们让两个线程执行不同的回调函数,让线程1先申请A锁,让线程B先申请B锁。线程1再申请B锁,线程2再申请A锁都会阻塞,造成死锁。
在这里插入图片描述
我们从运行结果可以看到,处于一种阻塞的状态。

那么一把锁可以造成死锁吗
如果我们加过锁后,又继续加锁,就可能会导致死锁

    while (true)
    {
        pthread_mutex_lock(&mutex);
        cout << name << " count : " << cnt-- << endl;
        pthread_mutex_lock(&mutex);
        sleep(1);
    }

4.3 死锁四个必要条件

1.互斥条件:一个资源每次只能被一个执行流使用。
2.请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系

如何避免死锁呢
1.破坏死锁的四个必要条件。
2.加锁顺序一致。
3.避免锁未释放的场景。
4.资源一次性分配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/632338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速在linux上配置python3.x的环境以及可能报错的解决方案(python其它版本可同样方式安装)

一. linux安装python3.x 下面案例是安装python3.9 步骤&#xff0c;也可以指定其他版本安装 步骤1&#xff1a;安装系统依赖&#xff08;重要&#xff09; 这一步不执行&#xff0c;后面各种错误。 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sql…

【Python小技巧】更换python版本解决了plt.show()不显示图像的问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、df.plot() 显示不出图像&#xff1f;二、换个python版本问题解决总结 前言 from matplotlib import pyplot as plt kdata.plot(xtrade_time, y[close,BOLL…

ThreadPoolExecutor线程池

文章目录 一、ThreadPool线程池状态二、ThreadPoolExecutor构造方法三、Executors3.1 固定大小线程池3.2 带缓冲线程池3.3 单线程线程池 四、ThreadPoolExecutor4.1 execute(Runnable task)方法使用4.2 submit()方法4.3 invokeAll()4.4 invokeAny()4.5 shutdown()4.6 shutdownN…

SpringBoot-Actuator健康检查-打印日志改造应用策略模式+简单工厂

类图 包结构 代码实例 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apac…

【MySQL 数据库】10、MySQL 的触发器

MySQL 的触发器 零、存储函数一、触发器二、触发器的使用和语法 零、存储函数 存储函数是有返回值的存储过程存储函数的参数只能是 IN 类型 characteristic 说明&#xff1a; ① DETERMINISTIC&#xff1a;相同的输入参数总是产生相同的结果 ② NO SQL &#xff1a;不包含 SQL…

【PCB专题】案例:绕等长怎么直接以颜色区分看出是否绕好

PCB上对于时序的处理,在板卡上实际我们是通过绕等长的手段。做为一个合格的Layout工程师,等长的处理是不可或缺的技能。 一般来说,在绕等长的时候我们可以使用Delay Tune命令来改变走线的长度,然后通过规则管理器中分析看看哪根线长哪根线短。 但是在实际工作中,很可能绕着…

【AI绘画】为小白准备的最简单本地部署安装使用教程——webui启动器

什么是AI绘画&#xff1f; ai绘画&#xff0c;也叫“ai作画”、“人工智能绘画”&#xff0c;即通过 AI 生成技术得到画作或图片。ai作画由来已久&#xff0c;有许多创作ai绘画作品的方式&#xff0c;包括基于规则的图像生成算法、深度学习算法。最近火爆全网的是通过文本描述…

悟道3.0全面开源!LeCun VS Max 智源大会最新演讲

夕小瑶科技说 原创 作者 | 小戏 2023 年智源大会如期召开&#xff01; 这场汇集了 Geoffery Hinton、Yann LeCun、姚期智、Joseph Sifakis、Sam Altman、Russell 等一众几乎是 AI 领域学界业界“半壁江山”的大佬们的学术盛会&#xff0c;聚焦 AI 领域的前沿问题&#xff0c…

【EasyX】实时时钟

目录 实时时钟1. 绘制静态秒针2. 秒针的转动3. 根据实际时间转动4. 添加时针和分针5. 添加表盘刻度 实时时钟 本博客介绍利用EasyX实现一个实时钟表的小程序&#xff0c;同时学习时间函数的使用。 本文源码可从github获取 1. 绘制静态秒针 第一步定义钟表的中心坐标center&a…

使用Python绘制粽子消消乐,素描图(优化版,正常/漫画/写实风格),词云图,字符画图及提取轮廓

使用Python绘制粽子消消乐&#xff0c;素描图&#xff08;优化版&#xff0c;正常/漫画/写实风格&#xff09;&#xff0c;词云图&#xff0c;字符画图及提取轮廓 1. 效果图2. 源码2.1 素描图源码2.2 [优化版&#xff1a;制作不同风格的素描图&#xff08;正常&#xff0c;漫画…

String的理解

1.号 1. 1 号连接符的实现原理 StringBuilder&#xff08;或者StringBuffer&#xff09;的apend方法拼接&#xff0c;然后toString方法返回新的字符串 1.2 号的特殊情况 1.2.1 当""两端均为编译期确定的字符串常量时&#xff0c;编译器会进行相应的优化&#xf…

springboot项目外卖管理 day05-新增与删除套餐

文章目录 一、新增菜品1.1、需求分析1.2、数据模型setmealsetmeal_dish 1.3、代码开发-梳理交互过程1.3.1、下拉框展示1.3.2、菜品窗口展示1.3.3、新增套餐 2、套餐分页查询 一、新增菜品 1.1、需求分析 套餐就是菜品的集合。 后台系统中可以管理套餐信息&#xff0c;通过新…

solr快速上手:常用查询语法(八)

0. 引言 solr作为搜索引擎&#xff0c;就像我们使用mysql一样&#xff0c;在日常业务中&#xff0c;更多接触的则是各类操作语法&#xff0c;所以今天&#xff0c;我们再来学习solr的常用查询语法&#xff0c;为大家在工作中最基本的solr查询打下基础。 solr快速上手&#xff…

ia write 自定义 导出模板

https://github.com/yangyang5214/github-plus.iatemplate 使用了点个 star 吧&#xff09; 在原有的 GitHub 模板基础上&#xff0c;增加了 封面页面和页脚。 封面页面 展示文章标题 作者 时间。高端大气&#xff5e; 增加页脚&#xff0c;显示 page/pageCount 加载 通过…

做策划有这些特质才能成为行业大咖,看看你符合几个

这个问题确实很重要&#xff0c;策划也不是职业也不是适合所有人的&#xff01; 首先&#xff0c;从性格方面来说吧。 有些人就是适合说话&#xff0c;有些人就是适合埋头苦干&#xff0c;还有一些人有强大的学习能力和逻辑思维。所以就是适合做创意类、创作类、策划类、统筹…

百度翻译API使用教程(前端+后端)

1.资格获取 首先我们需要登录百度翻译开放平台&#xff0c;获取开发者资格&#xff1a; 访问 百度翻译开放平台 然后进行注册&#xff08;如果有百度账号的话可以直接登录&#xff09; 注册成功后点击“产品服务”&#xff1a; 跳转到通用文本API界面&#xff1a; 在页面底…

怎么自学电脑编程

首要之首&#xff1a;不要急于选择一种语言 新手们有一个常见的错误就是犹豫于判断哪种编程语言是做好的、最该先学的。 我们有很多的选择&#xff0c;但你不能说那种语言最好。 我们应该理解&#xff1a;说到底&#xff0c;什么语言并不重要。 重要的是理解数据结构、控制逻辑…

C语言——修改控制台背景色和字体颜色

C语言——修改控制台背景色和字体颜色 方法一&#xff1a;system(“color NUM1NUM2”) system("color NUM1NUM2");可以用库函数system(“color NUM1NUM2”)实现 需要头文件 <stdlib.h> NUM1,NUM2均为16进制数 NUM1控制控制台背景色&#xff0c;NUM2控制前…

大数据驱动的实时文本情感分析系统:构建高效准确的情感洞察【上进小菜猪大数据】

上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。 随着互联网的快速发展和大数据技术的不断成熟&#xff0c;用户推荐系统在各个应用领域变得越来越重要。本文将介绍如何利用大数据技术构建一个实时用户推荐系统。我们将通过结合Ap…

基本算法温习:打印金字塔

最终结果图如下&#xff1a; 想达到这个结果&#xff0c;通常的做法是通过拼结两个三角型达到&#xff0c;但是实际上还有最右边的第三个三角型没有处理&#xff0c;这个拼结的方法总让人看起来有一点不完美的感觉&#xff0c;于是我自创了一个思路&#xff0c;一气合成&#x…