【线程的互斥】

news2024/11/17 22:32:06

线程的互斥

    • 临界区资源
    • 多个线程的运行
    • 多个线程对同一资源的竞争
    • 原子性
    • 保持线程之间地互斥
      • 互斥量(锁的原理)为什么是原子的
    • 正确使用锁

临界区资源

进程创建线程,是共享内存的,可以对共享的资源有很方便的操作,当一些共享资源可以被多个线程进行访问操作,该共享的资源被称之为临界资源。比如多个线程如果都有对全局的静态变量进行访问或操作,则该变量就是共享资源。每个执行流的代码访问临界资源就叫做临界区。
在这里插入图片描述

多个线程的运行

多个线程在执行的时候,调度哪一个执行流是程序员不可知道的,是由操作系统OS来进行调度的,多个线程可能会有交叉的现象,这种现象是不允许的,比如订票的系统,如果两个线程出现了交叉的现象,可能就会造成最后一张票被两个线程进行获取,两个线程在竞争。有些线程的执行是需要其他的线程执行完之后才能被调度,线程A的资源可能要等到线程B运行完才会有,所以线程会有先后顺序。

多个线程对同一资源的竞争

在这里插入图片描述

1step:当票数为1的时候,线程A进行抢票,线程A先对票数进行检查,如果大于1,则进行先一步购票,对票数自减。线程A已经判断出票数剩余1,进行抢票,但系统发现线程A分配的运行时间已经到了,但线程A还未进行购票进行票数自减,然后暂时退出自己的执行流,但线程A会把已经处理的数据(CPU寄存器的数据,判断票数大于1)进行保存(保存在自己进程的上下文),在下次再次被调度时继续使用。
2step:此时,线程B开始被调度进行抢票,假设线程B的时间片足够长,线程B开始执行,也对票数进行判断,票数为1,因为线程A还没对票数进行自减时间片就到了,所以在系统的内存当中,票数依旧为1,然后线程B购票,对票数进行了自减,最后票数为0了,然后再把0的票数拷贝到系统内存,最后票数为0了。此时线程B结束。
3step:过了极短的时间,线程A又有了时间进行调度,因为线程A在之前调度时已经逻辑运算判断票数为1,并把数据保存在自己的进程上下文当中,再次调度时,线程A就会执行下一步购票的任务,首先会在系统的内存当中拷贝剩余的票数到CPU,然后进行自减,因为票数已经被线程B已经自减为0了,所以线程A会对票数0进行自减,最后得到-1的值,然后再把-1拷贝会系统内存当中。会发现剩余票数为-1,导致了数据不正确。对与上述的票资源,本质上是临界资源。是多线程程序中的共享变量。引发数据不准确的原因,又是因为线程时间片结束时,但执行流还未执行完,导致有些数据保存到进程独立的上下文最后因为这些行为不是原子的所导致。这种行为就是线程不是安全的。

原子性

在这里插入图片描述

票数的操作在C语言的情况下是不原子的,经过编译后会有三条汇编语句,虽然每条汇编语句是原子的。两条C语句经过汇编会生成5条汇编语句,每执行到一条汇编时,线程都有可能会被操作系统切换,一旦还没执行完全部任务,就会把这些寄存器的数据保存到自己的独立上下文。即使每条汇编是原子的,但多条汇编不一定是原子的,所以C语句不是原子的,每个线程调用时,不能保证在执行完整的过程中,保证该资源一直时一个线程独享的。

保持线程之间地互斥

为了保证共享资源得安全性,临界资源只能由一个执行流访问并进行操作,需要使用一些手段让临界资源只有一个执行流,这种就是互斥。可以通过添加互斥量(锁)这个资源来对多个线程对临界资源进行单独访问操作(加锁)。当执行流已经完成了临界资源得访问和临界区得代码执行完毕,就可以释这个互斥量(解锁)让其他得线程可以访问临界资源和申请锁这个资源继续单独得访问临界资源(锁是原子的)。

int cnt = 100;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 申请锁资源并初始化,这个锁是全局的
///
while(true)
{
	pthread_mutex_lock(&mutex);//加锁
	if (cnt > 0)
	    cnt--;
	pthread_mutex_unlock(&mutex);//解锁
}

如果一个线程成功申请了锁这个变量,在解锁和加锁这段临界区的临界资源,其他线程是无法访问到的,即使申请成功锁得线程随时被OS切换不调度,必须要等待该线程把锁资源释放掉了(等待过程就是阻塞得过程),其他线程才有机会申请到锁资源并访问临界资源(锁本身也得原子的)。

互斥量(锁的原理)为什么是原子的

互斥量为了保证自身是原子性的,为了实现这一目的,大多数体系结构提供了swap或exchange指令,这些指令用于交换两个操作数(通常是寄存器%al和内存单元mutex,寄存器的数据为线程独有的)的值。由于这些指令的执行是原子的,因此它们可以在多线程环境中安全地用于加锁和解锁操作。当%al为1和内存mutex为0时表明成功获得了锁。当线程完成对共享资源的访问并准备释放锁时,它只需将内存中的锁变量值重置为0即可。这通常可以通过简单的写入指令(而非swap或exchange指令)完成,因为此时没有其他线程会尝试获取锁。最后,多个线程达到了互斥的目的,此时,线程才是安全的,之前不加锁的时候是线程不安全的。
在这里插入图片描述

正确使用锁

对于临界资源,多个线程访问,进行申请锁,则每个线程需要申请的时同一个锁才有意义。如果操作不当,会产生死锁问题。
产生死锁的必要条件

  • 互斥条件:一个资源每次只能被一个执行流使用,因为要使用了锁。
  • 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放,一直独占该锁资源。
  • 不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系。
    破坏死锁的四个必要条件
  • 避免死锁。
  • 加锁顺序一致。
  • 避免锁未释放的场景。
  • 资源一次性分配。

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

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

相关文章

【编译原理--- 汇编、编译、解释系统】

汇编、编译、解释系统 1.编译方式和解释方式 程序种类是否生成目标程序是否参与程序的运行过程程序执行速度可移植性编译程序生成不参与快差解释程序不生成参与慢好 编译方式过程:词法分析、语法分析、语义分析、(中间代码生成、代码优化、&#xff0…

重生奇迹MU格斗家上手最轻松的职业

重生奇迹MU格斗家玩法攻略,有一个比较奇葩的职业,那就是格斗家。格斗家拥有其他职业没有的优势,就是加体力和敏捷都可以提升攻击力百分比。格斗家玩法攻略 目前格斗家最多的就是敏格玩法,配合智力MM加成后的幽冥光速拳可以说是第…

修改VSCode中md文件中上传图片的路径

vs上打开md上传一个图片默认的路径是当前文件夹,可以发现,图片一多,非常的乱。 我们希望的是在单独的一个文件中存放图片即可。 使用ctrl , 快捷键,输入markdown 添加一个新的key/value。 **/*.md assets/${documentBaseName}/…

抖音运营_如何做好抖音直播

目录 如何做好抖音直播 一 带货主播应具备的技能 1 专业技能 2 语言表达能力 3 场控应变技能 4 熟悉平台规则 二 选品技巧 1 选择与账号属性相关的产品 2 选择试用过的产品 3 选择热销产品 4 选择低客单价产品 三 直播间产品的管理 四 打造转化率高的直播间 1 突出…

探秘SpringBoot默认线程池:了解其运行原理与工作方式(@Async和ThreadPoolTaskExecutor)

文章目录 文章导图Spring封装的几种线程池SpringBoot默认线程池TaskExecutionAutoConfiguration(SpringBoot 2.1后)主要作用优势使用场景如果没有它 2.1版本以后如何查看参数方式一:通过Async注解--采用ThreadPoolTaskExecutordetermineAsync…

Jenkins 构建 Maven 项目:构建服务器和部署服务器分离的情况

bash内容 #!/bin/bash#删除历史数据 rm -rf ruoyi-admin.jar# appname$1 appnamevideo.xxxxx.com #获取传入的参数 echo "arg:$appname"#获取正在运行的jar包pid # pidps -ef | grep $1 | grep java -jar | awk {printf $2} pidps -ef | grep $appname | grep java …

C# 深拷贝和浅拷贝

文章目录 1.深拷贝2.浅拷贝3.拷贝类4.浅拷贝的实现5.深拷贝实现5.1 浅拷贝对象,对引用类型重新一个个赋值5.2 反射实现5.3 利用XML序列化和反序列化实现 1.深拷贝 拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。…

聊聊ChatGPT的本质

这是鼎叔的第九十八篇原创文章。行业大牛和刚毕业的小白,都可以进来聊聊。 阶段性总结下我对ChatGPT的基础理解,算是一篇学习思考笔记吧。其中难免有很多不准确的,或过于简略的地方,将来再迭代学习。 OpenAI做ChatGPT的底层逻辑…

mfc140.dll丢失原因和mfc140.dll丢失修复办法分享

mfc140.dll是与微软基础类库(Microsoft Foundation Classes, MFC)紧密相关的动态链接库(DLL)文件。MFC是微软为C开发者设计的一个应用程序框架,用于简化Windows应用程序的开发工作。以下是mfc140.dll文件的一些关键属性…

spring boot 整合j2cache 项目启动警告 Redis mode [null] not defined. Using ‘single‘

好 之前的文章 spring boot 整合j2cache 基础操作 在spring boot环境中整合了 j2cache 我们 项目启动时 日志会有一个关键信息 Redis的模式 没有定义 默认使用 single Redis 的这个模式有四种 大家可以自己去网上找一下 做个了解 不用很纠结 我们直接在 j2cache.properties …

医院门诊互联电子病历|基于SSM+vue的医院门诊互联电子病历管理信息系统的设计与实现(源码+数据库+文档)

医院门诊互联电子病历管理信息系统 目录 基于SSM+vue的医院门诊互联电子病历管理信息系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台登录模块 5.2.1管理员功能 5.2.2用户功能 5.2.3医生功能 四、数据库设计 五、核心代码…

requests_html使用介绍

文章目录 一、requests_html 基本介绍二、requests_html 基本使用三、发送带有参数的请求四、图片抓取实战案例 一、requests_html 基本介绍 A、装库: pip install requests_html B、介绍: requests 和 requests_html 是同一个作者 二、requests_html 基本使用 A、导包: fro…

辐射度技术在AI去衣中的魅力与科学

引言: 在当今的数字化时代,人工智能正逐渐渗透到我们生活的方方面面。其中,AI去衣技术作为一项颇具争议但又不失其科技创新的应用,正引起越来越多的关注和讨论。而在实现高质量图像渲染的过程中,辐射度技术凭借其卓越的…

Linux指令初识

ls:显示当前目录底下的指定文件或目录 ls -l更详细的信息 ls -a显示当前目录下的所有文件 命令中的选项可以一次传递多个 ,例如:ls -al 命令和选项有必须一个或多个空格 以.开头的文件,为隐藏文件ls -a可以看到,ls -l看不见 支持命令拼在一起&#…

Rust开源Web框架Salvo源码编译

1.克隆源码: https://github.com/salvo-rs/salvo.git 2.进入salve目录并运行cargo build编译 编译成功 3.编译生成的库 4.安装salve-cli git clone --recursive https://github.com/salvo-rs/salvo-cli.git 编译salve-cli

stm32-PWM输出比较配置

配置流程 1.RCC开启时钟 2.时钟源选择和配置时基单元 这一部分上一篇有写,可以参考一下上一篇的内容,此处不多赘述了。 原文链接:https://blog.csdn.net/m0_74246768/article/details/139048136 3.配置输出比较单…

链表类型的无界阻塞线程安全队列-ConcurrentLinkedQueue(FIFO)

ConcurrentLinkedQueue是非阻塞线程安全(volatile不能完全保证线程安全)的队列,适用于“高并发”的场景。是一个基于链表节点的无界线程安全队列,按照 FIFO(先进先出,尾先进头先出)原则对元素进行排序。队列元素中不可以放置null元素(内部实现的特殊节点除外)。 volati…

【WEEK13】 【DAY5】Shiro第五部分【中文版】

2024.5.24 Friday 接上文【WEEK13】 【DAY4】Shiro第四部分【中文版】 目录 15.7.Shiro请求授权的实现15.7.1.修改ShiroConfig.java15.7.1.1.添加一行验证授权的代码15.7.1.2.重启 15.7.2.修改MyController.java15.7.3.修改ShiroConfig.java15.7.4.重启15.7.5.修改UserRealm.ja…

风电机组的振动控制

文章目录 0. 背景1. 原文记录 0. 背景 混塔机组的频率大概是目前业内遇见的比较普遍的通病。最近在了解风电机组振动控制的知识,看到一篇科普性质的文章,感觉不错,所以记录下来。想要看原文的点击这里。感谢原作者。 1. 原文记录

在IDEA中配置servlet(maven配置完成的基础下)

在IDEA中配置servlet&#xff08;maven配置完成的基础下&#xff09; 1.先新建一个项目 2.选择尾巴是webapp的&#xff0c;名称自定义 3.点击高级设置&#xff0c;修改组id 点击创建&#xff0c;等待jar包下载完成。在pom.xml中配置以下 <dependency><groupId>ja…