Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
多线程同步
学习过程总结
RT-Thread学习笔记 --(5)RT-Thread线程间同步学习过程总结
发布于 2020-12-09 15:25:26 浏览:1862
订阅该版
[tocm] 多线程之间同步是继多线程学习之后,需要重点掌握的又一个重要内容。一个实时操作系统里面,如果只有多线程而没有线程间同步,各个线程都无序运行,那么必然会导致整个系统的运行出现各种问题。 正是由于一个较大的任务拆分为多个小任务,这些小任务是由多个线程去执行的,那么,这些小任务之间必然会存在着千丝万缕的关系,小任务的运行更不能只管自扫门前雪,不管他人瓦上霜,因此,线程间同步是必须掌握的内容。 关于多线程之间的同步,RT-Thread提供了比较丰富的文档作为参考,具体可以查看以下链接:[https://www.rt-thread.org/document/site/programming-manual/ipc1/ipc1/](https://www.rt-thread.org/document/site/programming-manual/ipc1/ipc1/) 本文尝试从以下几个方面总结一下RT-Thread线程间同步的学习过程 ![1.png](/uploads/20201209/0cdb084b9afb133b9d395b2e502a2aee.png) # **什么是线程间同步,为什么需要线程同步?** 上一篇文章[**RT-Thread学习笔记 -- (4)RT-Thread多线程学习过程总结**](https://club.rt-thread.org/ask/article/2366.html)里面提及到,音乐播放器通过多线程工作的时候,需要通过合理的调度方式,才能让各个线程协同工作。而这里所说的“合理的调度方式”,其中一种方式就是指多线程同步。 **什么是线程间同步?**通俗一点来说,线程间同步是指多个线程之间进行协商工作的方式。前面已经说过,线程在工作的时候,虽然只专心在做一件事情,但线程在工作的时候,并不能只埋头苦干,而不顾其他线程的状态,因此必须要有一种方式,来告知其他线程关于自身的工作状态。 **为什么需要线程同步?**继续用音乐播放器来举例说明,按照前文的图例,假如不使用多线程播放音乐,会有什么后果呢?后果有可能是,音乐文件读取线程比歌词文件读取线程跑得慢,导致歌曲还没播放到那一步,而歌词反而先显示出来了,还有其他可能性,导致歌曲,歌词,MV三者播放的顺序乱套了,不能同步显示。 ![2.png](/uploads/20201209/72a0fb0a9b56c4e551b0fd986e1a52c3.png) 如果要让音乐播放能正常工作,就需要在4个工作线程之间加入线程同步机制。比如歌词文件读取线程可能运行得比较快,而音乐文件读取线程读取音乐比较慢,那么,这两个线程之间就需要进行同步,快的线程要稍微等一下,等慢的线程发送一个同步消息,这样两者才能一起愉快地继续运行。 ![3.png](/uploads/20201209/1c45bb9526b234ca0330c26479b87b7a.png) # **线程间同步的方式** 针对RT-Thread实时操作系统,线程间同步主要有三种方式:**信号量,互斥量,事件集**。这三种线程同步机制各有优缺点,在实际开发工作里面,需要根据不同的应用场景进行区分使用。 **信号量**是一种非常灵活的线程同步方式,通过信号量可以衍生出多种功能,比如,锁、线程同步、资源计数,后面讲述的互斥量也可以通过二值型信号量来实现。生活中的停车场应用场景,就是信号量的一种具体体现。 1.当停车场空的时候,停车场的管理员发现有很多空车位,此时会让外面的车陆续进入停车场获得停车位; 2.当停车场的车位满的时候,管理员发现已经没有空车位,将禁止外面的车进入停车场,车辆在外排队等候; 3.当停车场内有车离开时,管理员发现有空的车位让出,允许外面的车进入停车场;待空车位填满后,又禁止外部车辆进入。 在这个场景里面,管理员就相当于信号量,管理员手中空车位的个数就是信号量的值(非负数,动态变化);停车位相当于公共资源(临界区),车辆相当于线程。车辆通过获得管理员的允许取得停车位,就类似于线程通过获得信号量访问公共资源。 信号量是没有“所有权”这种概念的,也就是说,对于一个非二值型的信号量,多个线程可以对其进行获取/释放操作,也可以递归获取信号量,因此,对于非二值型信号量,在使用过程中可能会出现线程优先级翻转和线程死锁的问题。 系统内核提供以下信号量的API函数接口,如下图所示。 ![4.png](/uploads/20201209/644f8769e4a44bf44058f5eedc41b704.png) **互斥量**,顾名思义,就是一种相互排斥的信号量,是一种特殊形式的二值型信号量。这种情况就类似于一个停车位,当A汽车占据了停车位(获取到互斥量)的时候,其他汽车就不能获取该车位了,必须等A汽车离开该车位的时候,才能有机会争夺该车位。 互斥量跟信号量不同的是,互斥量只有两种状态值,对于拥有互斥量的线程,表示该线程已经拥有了该互斥量的所有权和控制权,该互斥量只能由该线程来进行释放,这样就可以解决线程递归获取互斥量出现的死锁问题。 对于信号量中存在的优先级翻转问题,在互斥量里面不会出现,这是因为互斥量里面实现了高优先级继承算法。优先级继承是通过在高优先级线程尝试获取共享资源而被挂起的期间内,将低优先级的线程的优先级提升到高优先级线程的优先级别,从而解决优先级翻转引起的问题。 系统内核提供以下互斥量的API函数接口,如下图所示。 ![5.png](/uploads/20201209/84fba731cf2c5495422be0e7fd7c8b59.png) **事件集**也是线程同步的一种机制,但与信号量或互斥锁不同,事件集是可以实现一对多或多对多同步的。也就是说,一个线程发出一个(或多个)事件,一个(或多个)等待该事件的线程在获取到该事件后,就可以获得运行的权限。 事件集是使用一个32位无符号整型的变量来表示的,每一个位表示一个事件,这些事件可以是“逻辑与”或“逻辑或”的关系。换句话说,就是可以让一个线程等待一个事件(逻辑或)到达就执行,或者让一个线程等待所有事件(逻辑与)到达才执行。 事件集在某些场合里面是可以替代信号量的。但事件集与信号量不同,事件集的事件在清除之前,是不能累计的,也就是说,一个线程发送了多次同一事件,由于不能累计,也就相当于只发了一次该事件,直到该事件被清除。 系统内核提供以下事件集的API函数接口,如下图所示。 ![6.png](/uploads/20201209/e71bec3bd618bc963042f2c6d31df9d2.png) # **多线程同步的应用示例** 多线程同步的应用示例,主要是为了验证信号量,互斥量,事件集的API接口函数,并且通过实验现象观察这三种线程同步方式的运行情况。 示例源码下载链接:[https://github.com/embediot/rtthread_study_notes](https://github.com/embediot/rtthread_study_notes) **信号量示例**主要演示了一个“生产者-消费者”的设计模式,生产者线程不断生产产品(数值加1)放入仓库(循环数组),消费者线程不断从仓库里面取出产品,仓库的读写操作都需要使用信号量的锁机制进行同步。 **互斥量示例**主要创建了三个动态线程,这三个动态线程不断争夺这个互斥量的使用权,通过实验现象可以观察到,持有互斥锁的线程的优先级,会通过优先级继承算法,调整到等待线程优先级中的最高优先级。 **事件集示例**主要初始化了一个事件集和两个线程,一个线程发送事件,另一个线程等待事件。等待事件的线程,分别使用了“逻辑与”和“逻辑或”这两种事件接收方式。 具体示例的实现可以查看工程源码,在synchronize.h头文件中,打开相应的宏定义开关,重新编译工程并下载到开发板即可。 ![7.png](/uploads/20201209/f180e84401df228f9aef2879449b98cd.png) # **线程间同步的注意事项** 在进行多线程间同步的时候,关于信号量,互斥量,事件集这三种线程同步方式,有以下一些注意事项: 1.中断与线程间的互斥,不能采用信号量(锁)的方式,应该采用开关中断的方式。 2.资源计数类型的应用场景,多数都是混合方式的线程间同步,由于单个的资源处理存在线程的多重访问,因此需要对资源进行锁方式的互斥操作。 3.在使用信号量的时候,应该要注意优先级翻转的问题,合理安排任务的优先级。 4.不能递归获取信号量,否则有可能会造成“死锁”的情况。 5.线程不能长时间占用互斥量,在获得互斥量之后,不能再更改持有互斥量线程的优先级。 6.不能在中断服务程序里面使用互斥量。 7.事件集仅能用于线程同步,不能用于线程间传输数据。 8.事件集不会形成队列,在清除事件之前,发送多次跟发送一次都是同样的效果。 ![qrcode40.png](/uploads/20201209/44c54532c5d27ecb8d818f1e7e1b22cc.png)
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
embediot
这家伙很懒,什么也没写!
文章
11
回答
0
被采纳
0
关注TA
发私信
相关文章
1
生产消费者问题中限制生产者的产量应该最好使用什么机制
2
线程间同步和通讯同步使用
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部