当前位置: 首页 > news >正文

Linux初阶——线程(Part2):互斥同步问题

一、互斥锁

1、CPU 运算过程

执行完整个语句后,才会把数据写入内存;如果执行时被中断,那么数据和上下文就会保存到线程的 TCB,但数据并不会被写入内存。

1.1. 当 CPU 执行完整个语句时

CPU 最终执行完整个语句的过程

就用上图举个例子。 CPU 是如何执行 a-- 这个句代码的呢?

  • 第一步,CPU 将内存中变量 a 的值(100)拷贝到运算器中。
  • 第二步,在运算器中减一。
  • 第三步,把新的值(99)拷回变量 a 里。

1.2. 当 CPU 还未执行完这个语句,线程就被换出时

CPU 执行完减 1 操作,线程就被换出了

以上图为例,CPU 刚执行完减 1 操作,线程就被换出。遇到这种没执行完语句的情况,CPU 会把计算数据和该线程执行的上下文(即该线程执行到哪一行代码)拷到该线程的 TCB 里;然后再为下一个线程服务。

2、解决方案——互斥锁(mutex)

2.0. 什么是互斥问题

当多个线程并发执行,并访问同一个变量时,就会很容易发生变量的一致性问题。

如图所示,假如我想让变量 a 从 100 减到 0.

线程 1 在做完 a-- 操作后就被换出了:
 

线程 1 被换出

线程 2 正常执行完整个减 1 操作,并重复了很多次,直到减到 10,被换出,线程 1 进来了:

线程2被换出
线程 1 执行

而此时 a 这个全局变量又从 10 变成 100 了。

所以,这个变量从始至终都只能被一个执行流(线程)访问。

2.1. 互斥锁原理

下面这是线程申请锁和释放锁的汇编代码:

lock: // 申请锁movb $0, %alxchgb %al, mutexif (al 寄存器的内容 > 0) return 0; // 申请锁成功else 挂起等待;goto lock;unlock: // 释放锁movb $1, mutex唤醒等待 Mutex 的线程;return 0;
lock 部分的汇编代码的前 2 行的执行过程

但是,如果当该线程执行完第一句后就被换出了,那么该线程会把 al 寄存器的值和上下文保存到 TCB;然后再被换出;然后第二个线程再进来从上次的上下文开始接着执行。所以,其实申请锁的本质就是看哪个线程拿到 1,拿到 1 的那个线程就申请到锁了。

2.2. 相关函数

2.2.1. pthread_mutex_t 类型

就是互斥锁的类型。

2.2.2. pthread_mutex_lock 函数

这个函数用于申请互斥锁。注意,这里只是把锁加上而已,并不会创建锁。 

2.2.3. pthread_mutex_unlock 函数

这个函数用于释放锁。注意,这里只是把锁解开了,锁还在。

2.2.4. 初始化全局的锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
2.2.5. 初始化局部变量的锁 
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);参数:
mutex:要初始化的互斥锁
attr:nullptr
 2.2.6. 销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

这个函数是直接让锁消失。

注意:

  • 如果创建的锁是用宏创建的,就不能掉这个函数。 
  • 一定要在解开锁了之后才能调用这个函数。
  • 确保后面没有线程用到这个锁。

2.3. 临界区

处于 pthread_mutex_lock 函数和 pthread_mutex_unlock 函数之间的区域就是临界区。

2.4. 临界资源

多线程执行流共享的资源就叫做临界资源。不过,临界资源都是每次只能让一个一个线程访问的。但是当线程申请锁时,那么锁也是共享资源;所以申请锁和释放锁本来就被汇编语言设计成原子性的(即只用一句汇编实现)。

二、死锁

1、产生死锁的必要条件

  • 互斥条件:一个资源每次只能被一个执行流使用。
  • 请求和保持条件:一个执行流因请求资源而阻塞时,它同时也持有已有的资源,且不释放。
  • 不剥夺条件:如果申请不到资源,只能等待,不能强行抢占。
  • 循环条件:执行流之间形成有环的等待资源的关系。

2、如何解决

  • 破坏上面的 4 条必要条件的其中一条。
  • 资源一次性分配。
  • 加锁顺序一致。
  • 避免未释放的场景。

三、同步问题

1、什么是同步

同步就是让线程按照一定顺序获取资源,而不是一窝蜂地去抢。举个例子,假如厕所是一个共享资源,一次只能一个人用。当有人进去后,就会有很多人在外面等。如果不同步的话,一旦厕所里的那个人出来,全部人就会一窝蜂地去抢厕所;而如果刚出来的那个人的抢占能力非常强,那么厕所就会一直被抢占能力最强的那个人占用,因为这个人可以出来后再抢。于是就会导致其他人长时间没得上厕所,进而引发其他人的饥饿问题。

因此,解决方法就是让所有人排队,一个个上厕所。从厕所出来的人无论抢占能力强还是弱,都要去队尾排队。这种让人们有序地使用厕所就是同步。而把线程看成人,那就就是线程的同步了。所以,总结来说,在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。

2、条件变量

2.1. 什么是条件变量

还记得前面厕所排队的例子吗?条件变量就是这个等待队列的头节点,当申请到资源时,线程就会从等待队列出来,然后访问共享资源;而如果线程没申请到资源时,该线程就会进入以条件变量为头节点的等待队列里。

2.2. 相关函数

2.2.0. pthread_cond_t 类型

该类型为条件变量类型。

2.2.1. 初始化全局的条件变量
pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
2.2.1. 初始化局部变量的条件变量

参数介绍

  • cond:条件变量的地址。
  • attr: 条件变量的性质。

这个函数用于初始化条件变量。其实就是初始化等待队列的头节点。

2.2.2. pthread_cond_destroy 函数

参数介绍

  • cond:传条件变量的地址。 

注意:

  • 如果创建的条件变量是用宏创建的,就不能掉这个函数。 

这个函数用于释放条件变量。其实就是初始化等待队列的头节点。

2.2.3. pthread_cond_wait 函数

参数介绍

cond:传条件变量的地址。

mutex:传互斥锁的地址。 

此函数用于把线程加入等待队列。如果此时没申请到共享资源,该线程就会进入以条件变量为头节点的等待队列里。

2.2.4. pthread_cond_signal 函数

参数介绍

  • cond:条件变量地址。 

此函数用于唤醒线程。 即当线程申请到共享资源时,这个函数就能让一个线程的 TCB 退出以条件变量为头节点的等待队列。

2.2.5. pthread_cond_broadcast 函数

参数介绍

  • cond:条件变量地址。 

即当线程申请到共享资源时,这个函数就能让所有线程的 TCB 退出以条件变量为头节点的等待队列。 

四、应用:生产者消费者问题(cp 问题)

1、什么是生产者消费者问题

简单来说,前提就是生产者和消费者之间有一个共享资源(共享内存),生产者负责向共享内存放数据,消费者负责从共享内存里拿数据。然后我们通过一定的策略解决它们的互斥与同步问题。

2、3 种关系

2.1. 生产者与生产者

生产者与生产者之间是竞争关系,因此生产者与生产者之间是互斥关系。

2.2. 生产者与消费者

2.2.1. 互斥关系

因为要保证公共资源的安全性,因此要让生产者与消费者处于互斥关系,每次只能有一个线程访问共享资源。

2.2.2. 同步关系

因为共享内存里先有数据,消费者才可以拿数据。而生产者是负责向内存放数据的。因此先有生产者向共享内存放数据,才有消费者从共享内存拿数据,这是一种顺序访问共享内存;因此生产者与消费者也处于同步关系。

2.3. 消费者与消费者

消费者与消费者之间是竞争关系,因此生产者与生产者之间是互斥关系。

相关文章:

Linux初阶——线程(Part2):互斥同步问题

一、互斥锁 1、CPU 运算过程 执行完整个语句后,才会把数据写入内存;如果执行时被中断,那么数据和上下文就会保存到线程的 TCB,但数据并不会被写入内存。 1.1. 当 CPU 执行完整个语句时 CPU 最终执行完整个语句的过程 就用上图举…...

力扣——二叉树的后序遍历(C语言)

1.题目: 给你一棵二叉树的根节点 root ,返回其节点值的后序遍历。 2.原理: 这里的遍历,是要存入到数组中,所以需要建立数组,这里传参有*returnSize,需要求节点个数,可以调用前面Tr…...

利用kimi编程助手从0到1开始搭建小程序!

电脑崩了,更新5次小程序,什么都不剩!(但是遗留下来了一些东西,开源的思维和不断地对于技术的使用和掌握“一个软件更多的哲学:(01)优秀的ui页面设计(02)更加细…...

WSL(Ubuntu20.04)编译和安装DPDK

编译和安装DPDK DPDK可以使用工具meson和ninja在您的系统上进行配置、构建和安装。 DPDK配置 要配置DPDK构建,请使用: meson setup build --prefix/home/xx/dpdk19.11xxxx:~/dpdk-stable-19.11.14/$ meson setup build Message:Content Skipped libs…...

HLS协议之nginx-hls-多码率测试环境搭建

运行环境:ubuntu 20.04 时间:2024年10月26日 环境更新 sudo apt-get update sudo apt-get install build-essential libtool libpcre3 libpcre3-dev zlib1g-dev openssl下载nginx wget http://nginx.org/download/nginx-1.19.2.tar.gz tar xvzf n…...

函数式接口与回调函数实践

函数式接口与回调函数实践 一、Java 的函数式接口 是指仅包含一个抽象方法的接口,通常用于 lambda 表达式或方法引用。Java 8 引入了很多内置的函数式接口,比如 Runnable、Callable、Predicate、Function、Consumer 等 演示,数据类型转换的函…...

Windows11系统如何使用自带的录音、录屏工具?

电脑录音和录屏作为现代办公的辅助工具,不仅极大地提升了工作效率,也保障了信息传递的准确性和完整性。通过合理利用这些工具,我们可以更好地保存和管理重要资料,为办公带来无与伦比的便利。 在会议记录、讲座学习、语音备忘等场景…...

使用 web (vue 和DRF))实现 模拟一个IDE 功能思路

采用文件系统和数据库相结合的方案,不仅可以实现基本的文件管理,还可以为未来的扩展提供灵活性。结合我们讨论的内容,以下是更完善的策略: 方案概述:文件系统与数据库结合 文件系统负责实际的文件存储和执行操作&…...

智航船舶租赁综合管理系统

1.产品介绍 产品介绍方案 产品名称: 智航船舶租赁综合管理系统 主要功能: 船舶信息管理租赁合同管理运营调度与优化财务分析与报告功能介绍: 1. 船舶信息管理 具体作用与使用方式:该功能模块允许用户录入、编辑和查询所有船舶的详细信息,包括但...

统信UOS下启动图形界面应用工具monitor报JAVA相关错:An error has occurred. See the log file

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、前言 在博文《基于飞腾2000CPU浪潮电脑统信UOS安装达梦数据库详解 https://blog.csdn.net/LaoYuanPython/article/details/143258863》中介绍了基于飞腾2000CPU浪潮电脑统信UOS安装达梦数据库的详细过程…...

N-154基于springboot酒店预订管理系统

开发工具:IDEA 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 前端技术:AdminLTEBootstrapLayUIHTMLjQuery 服务端技术:springbootmybatis-plusthymeleaf 本项目分前台和后台…...

微信小程序如何实现地图轨迹回放?

要在Uni-app中实现微信小程序的地图轨迹回放功能,你可以按照以下步骤进行操作: 在Uni-app项目中引入地图组件:在页面中使用uni-app提供的map组件,可以使用uni.createMapContext方法获取地图上下文对象,以便后续操作地图…...

vscode的一些使用心得

问题1:/home目录空间有限 连接wsl或者remote的时候,会在另一端下载一个.vscode-server,vscode的插件都会安装进去,导致空间增加很多,可以选择更换这个文件的位置 参考:https://blog.csdn.net/weixin_4389…...

Python金色流星雨(完整代码)

文章目录 环境需求完整代码下载代码代码分析1. 导入库和窗口设置2. 创建画笔对象3. 流星的颜色4. 定义流星类`Meteor`5. `meteor`方法:绘制流星6. `move`方法:流星的运动7. 创建流星对象列表8. 动画循环总结系列目录写在后面环境需求 python3.11.4PyCharm Community Edition …...

[山河CTF 2024] week3

一周不在家,这是补的最后一篇。后边的还有0xgame和shctf的末周。打不动了。 Crypto Approximate_n 题目分两部分,flag分两块两个RSA,第1个泄露了4个n_approxkpr的值,后边只泄露了1个。 第1部分利用以前的模板,造格…...

Java集合常见面试题总结(5)

HashSet 如何检查重复? 当你把对象加入HashSet时,HashSet 会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发…...

牛客网刷题(3)(Java的几种常用包)

目录 一、牛客网案例题目。 二、Java常用包的总结。 <1>JAVA常用包&#xff08;图片&#xff09;。 <2>java.lang包。 <3>java.util包。 &#xff08;1&#xff09;集合框架。 1、Collection接口。 2、List接口。 3、Set接口。 4、Queue接口。 5、Map接口。 …...

PyTorch nn.Conv2d 空洞卷积

torch.nn.Conv2d() 中 dilation 参数控制卷积核的间隔 dilation controls the spacing between the kernel points 当 dilation1 时, 表示卷积核没有额外的空白间距, 也就是标准卷积当 dilation>1 时, 表示空洞卷积(dilated convolution) 动画演示: 手动计算 以 2*2 的卷…...

像素、分辨率、PPI(像素密度)、帧率的概念

文章目录 前言一、像素1、定义2、像素点也不是越多越好 二、分辨率1、定义 三、PPI(像素密度)1、定义2、计算公式3、视网膜屏幕 四、帧率1、帧 (Frame)2、帧数 (Frames)3、帧率 (Frame Rate)4、FPS (Frames Per Second)5、赫兹 五、其他1、英寸2、为何显示器尺寸以英寸命名 总结…...

两步GMM计算权重矩阵

在广义矩方法&#xff08;GMM&#xff09;中&#xff0c;权重矩阵(W)的选择是关键的一步。理想情况下&#xff0c;(W)应该等于矩条件的协方差矩阵的逆矩阵。这是因为使用这样的权重矩阵可以使得估计量达到最小方差&#xff0c;从而提高估计效率。 两步GMM计算权重矩阵(W) 第一…...

leetcode452. 用最少数量的箭引爆气球

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一…...

【Android】使用TextView实现按钮开关代替Switch开关

介绍 Android 本身自己带的有开关控件&#xff0c;但是很多时候我们是不愿意使用这种开关的&#xff0c;感觉使用起来比较麻烦&#xff0c;特别是遇到需要延迟操作的情况。 比如有一个需求是这样的&#xff1a;我们需要打开一个设置&#xff0c;但是这个设置是否打开需要经过…...

(49)MATLAB实现迫零均衡器原理与代码

文章目录 前言一、迫零均衡器设计说明二、迫零均衡器MATLAB源代码1.函数说明2.代码实现3.辅助函数 前言 使用MATLAB实现迫零均衡器。给出完整的MATLAB设计源代码。 一、迫零均衡器设计说明 理想的迫零均衡器有无限多个抽头权系数&#xff0c;是不能实现的&#xff0c;本文考虑…...

滚柱导轨出现异常损坏的原因

滚柱导轨是一种精密的直线滚动导轨&#xff0c;具有较高的承载能力和较高的刚性&#xff0c;对反复动作、起动、停止往复运动频率较高情况下可减少整机重量和传动机构及动力成本。滚柱导轨可获得较高的灵敏度和高性能的平面直线运动&#xff0c;在重载或变载的情况下&#xff0…...

架构师考试系列(6)论文专题:论分布式架构设计

论分布式架构设计 摘要: 2020年2月,我司中标了某省电力公司的配网运维管控项目,该项目接入电力公司营销、设备和调度等多个部门的专业数据,为配网运行、配网检修、配网抢修、配网工程、供电服务等核心业务提供数据支撑。由于本项目是省级项目,系统可靠性、可用性要求比较…...

leetcode hot100【LeetCode 230. 二叉搜索树中第K小的元素】java实现

LeetCode 230. 二叉搜索树中第K小的元素 题目描述 给定一个二叉搜索树的根节点 root&#xff0c;和一个整数 k&#xff0c;请你找出其中第 k 小的节点。 注意&#xff1a; 题目保证 k 的有效性。 示例&#xff1a; 给定二叉搜索树&#xff1a; 5/ \3 7/ \ \ 2 4 …...

从0开始深度学习(23)——图像卷积

上节了解了卷积层的原理&#xff0c;本节以图像为例&#xff0c;介绍一下它的实际应用 1 互相关运算 严格来说&#xff0c;卷积层是个错误的叫法&#xff0c;因为它所表达的运算其实是互相关运算&#xff08;cross-correlation&#xff09;。 首先&#xff0c;我们暂时忽略通…...

编程小白如何成为大神

成为编程大神的过程需要时间、耐心和实践。以下是一些适合大学新生的入门攻略&#xff1a; 1. 确定学习目标 选择语言&#xff1a;选择一门编程语言作为起点&#xff0c;如 Python、Java 或 JavaScript。Python 是初学者的热门选择&#xff0c;因为其语法简洁易懂。设定目标&…...

JetCache启动循环依赖分析

问题呈现 项目性能优化&#xff0c;需要将本地内存&#xff08;JVM内存&#xff09;替换为本地Redis&#xff08;同一个Pod中的Container&#xff09;&#xff0c;降低JVM内存和GC的压力&#xff0c;同时引入了JetCache简化和统一使用&#xff08;对JetCache也做了扩展&#x…...

【科研绘图】3DMAX管状图表生成插件TubeChart使用方法

3DMAX管状图表生成插件TubeChart&#xff0c;一款用于制作3D管状图表的工具。可以自定义切片的数量以及随机或指定切片颜色。 【版本要求】 3dMax 2008及更高版本 【安装方法】 TubeChart插件无需安装&#xff0c;使用时直接拖动插件脚本文件到3dMax视口中打开即可&#xff0…...