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

Linux——线程(3)线程同步

一、线程同步的引入

通过上面的抢票系统我们发现,有的线程,进行工作(挂锁),当其马上结束工作(解锁),发现外面有很多线程在排队等着加锁执行任务,这个线程解锁后就立马给自己加锁(可以想象成自己能直到解锁的时间,所以加锁的优势比其他线程大),但是如果这个线程本身并没有做什么工作,就会使工作效率低下,线程饥饿等问题。

为了解决这个问题,我们规定:所有线程等待加锁必须排队,加锁的线程解锁后必须排在队尾等待下一次加锁,这样就能保证所有线程都可以执行任务。这就是线程同步。

二、条件变量

条件变量与互斥锁的相关接口几乎完全相同,在这里就不多介绍语法了。

但也有些新的接口。

我们用一个场景来介绍一下这些接口是怎么用的。

我们现在有一个主线程和若干个新线程(共用一个锁)

主线程负责派发任务,新线程负责执行(如果不派发就无法执行)

所以,当一个线程拿到锁进行查看时,如果发现有任务就执行,但如果发现任务还没派发,就会去某个条件变量那里进行等待(pthread_cond_wait接口),后面的线程也是如此,这里是在条件变量这的等待队列(先进先出)。在等待过程中就不会一直的申请加锁而阻止主线程派发任务了。在所有新线程等待的情况下,当主线程加锁后派发任务后,会通知(唤醒)第一个开始等待的新线程,让它去加锁执行任务(pthread_cond_signal接口),同时,主线程也可以一次唤醒多个线程,让他们去抢夺该资源(pthread_cond_broadcast接口),这便是这些接口的使用方法。

三、生产者消费者模型

对于多线程并发的情况,我们可以用生产者消费者模型来解释一下。

首先,我们把主线程称为生产者,可以视为派发任务方,然后多个新线程称为消费者,视为取得任务并执行任务。在二者之间,有一个桥梁——共享或临界资源。那么生产者就会对这份资源进行派发任务的行为,其他消费者要执行任务时,并不会直接向生产者询问索取,而是直接访问该临界资源、上锁并执行。通过这个临界资源,我们就可以讲生产和消费进行解耦了。同时,临界资源可以作为媒介,当生产者派发任务多时可以间接通知消费者并增加消费者数量,反之则减少。

而在这个模型中,我们需要研究多个生产与多个消费的同步互斥关系。

首先,生产者与生产者之间是互斥的,毕竟从现实角度考虑,我派发了就不允许你派发。

消费者与消费者之间也是互斥的,如果任务很少而线程很多时,就会出现我抢到任务了而别人都没抢到。

还有就是生产者与消费者,他们是既互斥又同步的,互斥在于,生产者在派发任务时不允许消费者进来枪任务干扰生产者,而消费者在抢任务时也不许生产者发任务干扰。同步在于,生产者派发任务时,虽然无法抢,但消费者们可以进行排队等待,而对于生产者们也是一样的。

总结就是:2个角色,3个关系,1个交易场所。

有了这个模型,我们就可以把条件变量的接口来解释了。

首先

wait就相当于创建该媒介,让线程在该阻塞队列中等待。signal就是叫醒排在最前面的一个线程执行,broadcast就是一次唤醒所有在队列的线程。

至于wait的接口为什么还要把锁传进去呢?——在线程进入等待的时候要解锁!即解锁与等待是原子性操作。

条件等待是线程间同步的⼀种手段,如果只有⼀个线程,条件不满足,⼀直等下去都不会满足, 所以必须要有⼀个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好 的通知等待在条件变量上的线程。条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据。由于解锁和等待不是原子操作。调用解锁之后, pthread_cond_wait 之前,如果已经有其他线程获取到互斥量,摒弃条件满足,发送了信号,那么 pthread_cond_wait 将错过这个信 号,可能会导致线程永远阻塞在这个 pthread_cond_wait 。所以解锁和等待必须是⼀个原子操作。

同时,被唤醒的线程也会重新申请锁。

四、信号量

什么是信号量呢?首先,信号量和信号并没有关系。

对于一块公共资源(临界区),我们可以当作一整份使用,比如我们的阻塞队列。但有时,我们也可以分成多块,然后以块为单位访问这块资源,就可以让多个执行流并发访问该块资源了。

首先,信号量是一个计数器,用来表明临界资源中的资源数目。而我们申请信号量,本质是对临界资源的预订(并非等同于使用),只要预订成功即使不使用,其他线程也无法使用。而我们信号量作为保护公共资源的机制,本身自己也属于临界资源,因此申请信号量的操作必须是原子的。此外,如果我们的计数器只有0和1,那不就成为了我们在线程互斥提到的锁了吗。

五、有关信号量的环形队列

在上面的生产者消费者模型,我们的交易场所是阻塞队列,有了信号量的引入,我们介绍一种新的交易场所模型——基于信号量的环形阻塞队列(首尾相连)。(为空或为满,都指向一个位置)

在这个队列中,任何人访问此临界资源,必须先申请信号量!对于生产者来说,在意的是剩余空间,而对于消费者来讲在意的是剩余数据。我们介绍一下此队列的两种情况

1.生产消费同时访问同一个位置

如果为空,说明队列无数据,消费者就需要阻塞等待,让生产者放入数据。

如果为满,说明队列满数据,生产者就需要阻塞等待,让消费者取得并拿出数据。这两种情况都可以保证原子性!体现了互斥同步原则。

2.指向不同位置

此时就有点像追及问题,此时生产者和消费者就可以同时进行访问临界资源,直到回到1情况再继续一方等待。这种情况就满足了并发原则。

因此,我们要设计两个信号量分别给生产消费,以让他们看到临界资源的使用情况。

六、信号量的相关接口

1.sem_init

第一个参数不说了,第二个是是否设置为线程间共享,默认设置为0即可,第三个是设置信号量的初始值。

2.sem_destroy

3. P操作(申请信号量)

申请失败就会阻塞

4.V操作(释放信号量)

提一下,假设我们现在是生产者的视角,我们就需要让空间信号量先进行P操作,等放入数据后,再让消费者(数据信号量)进行V操作。

关于P、V操作

P、V本质都是对信号量的操作,P操作就是申请信号量,预订资源(但如果信号量为负就会阻塞等待,直到有其他资源释放导致该信号量++,然后把信号量--),V操作是释放资源以及唤醒其他阻塞等待的线程,如果没有等待的线程,那么信号量的值会累加。

对于空间信号量(生产)和数据信号量(消费)而言,我们简述一下大致流程:
当要放入数据时,空间信号量会预订(P)(如果没有等待就进行插入操作),然后放完数据后,让数据信号量进行V(因为插入一个数据后导致数据个数增加,消费者对于这块空间的可访问量++)。而消费者进行消费过程正好与之相反。 (我们把信号量看成可访问资源块的数量就好理解了)

http://www.xdnf.cn/news/249985.html

相关文章:

  • ✨从噪声到奇迹:扩散模型如何“想象“出世界
  • 本地服务器备份网站数据,本地服务器备份网站的操作步骤
  • 产品手册小程序开发制作方案
  • C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 17)
  • python自动化测试
  • 【业务领域】计算机网络基础知识
  • 基于预计技术研究加速因子:原理、应用场景及模型验证
  • socket-IO复用技术
  • 米酒的功能和优缺点
  • 范围for 和 万能引用
  • 【业务领域】电脑网卡是主板还是cpu(主板的网卡是什么意思)
  • 神经网络入门
  • 题解:CF1133E K Balanced Teams
  • 专题二十一:无线局域网——WLAN
  • VAO与VBO的相关操作
  • 【软件技能】Verdi使用技巧总结
  • TactileNet 利用 AI 生成触觉图形填补视障人士无障碍鸿沟
  • 文章记单词 | 第56篇(六级)
  • 【信息系统项目管理师-论文真题】2024上半年(第二批)论文详解(包括解题思路和写作要点)
  • 交我算使用保姆教程:在计算中心利用singularity容器训练深度学习模型
  • VLM-R1 训练:max_anyres_num 参数与多图处理机制解析
  • Origin绘图操作:图中迷你图绘制
  • 【c语言】字符函数和字符串函数
  • PB的框架advgui反编译后控件无法绘制的处理(即导入pbx的操作步骤)
  • 编程题python常用技巧-持续
  • 【java WEB】恢复补充说明
  • 基于hr2管理系统的学习
  • BG开发者日志501:故事模式的思路2
  • 2025五一杯数学建模B题:矿山数据处理问题,详细问题分析,思路模型
  • 有没有贴吧备份的网站,备份贴吧网站数据的方法