RT-Thread IPC
本文章为RT-Thread5.0.x版本
一、IPC机制
RT-Thread中的IPC可以分成了两大块:
- 线程同步
- 线程间通信
二、线程同步
线程同步主要是为了保证多个线程在访问共享资源时的正确性和一致性,避免由于竞争条件导致的数据不一致和程序错误。
线程同步是通过多种机制来实现的,主要包括信号量、互斥量、事件集。
1.信号量
信号量是一种轻型的用于解决线程间同步问题的内核对象,一个或多个运行线程可以获取或释放它,从而达到同步或互斥的目的。用于实现任务与任务之间、任务与中断处理程序之间的同步与互斥。
信号量可以是二值信号量或计数信号量。
- 二值信号量:顾名思义,只有两个状态,类似于互斥锁,用于确保只有一个线程可以访问共享资源。
- 计数信号量:用于限制对资源的访问数量。
具体信号量使用的API可以参考文档中心。下面重点讲述信号量的管理机制。
a.信号量控制块
b.获取信号量
路径:.\rt-thread\src\ipc.c
这个是获取信号量的API,我们来看一下内部是怎么实现的。
获取信号量可以大致分为这几种情况:
- 信号量不为0
-
信号量为0
- 不等待
- 等待
笔者手误了,这边应该是把线程从就绪链表中移除,并添加到信号量的挂起链表,当有信号量释放的时候,就会判断挂起链表中是否有线程,并把其他变为就绪链表。(为什么不重新打就是因为懒,qq截图不能直接重新编辑,不知道有什么比较好的工具)
线程的超时回调函数
c.释放信号量
路径:.\rt-thread\src\ipc.c
路径:.\rt-thread\src\ipc.c
路径:.\rt-thread\src\scheduler_comm.c
如果在等待时间内的想获取信号量的线程就会被重新调度。
2.互斥量
互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。互斥量类似于只有一个车位的停车场:当有一辆车进入的时候,将停车场大门锁住,其他车辆在外面等候。当里面的车出来时,将停车场大门打开,下一辆车才可以进入。
互斥量与信号量不同的点:
- 只能由持有线程释放
- 解决线程优先级翻转问题(会将持有线程优先级提高跟等待线程一样)
重点看一下互斥量是怎么解决优先级翻转问题的。
a.互斥量控制块
路径:.\rt-thread\src\ipc.c
路径:.\rt-thread\include\rtdef.h
b.获取互斥量
路径:.\rt-thread\src\ipc.c
获取互斥量可以分成这几种情况:
- 拥有者
- hold++
-
不是拥有者
- 互斥量还未被拥有
-
互斥量已经被拥有
- 不等待
-
等待
将线程移至互斥量的挂起链表,并设置亮着为互斥对象,以及判断是否比当前挂起的线程中优先级高
设置定时器,发起调度。
c.释放互斥量
路径:.\rt-thread\src\ipc.c
rt_err_t rt_mutex_release(rt_mutex_t mutex)
释放信号量大致可以分为这几种情况:
- 不是拥有着
-
是拥有着且拥有的互斥锁为0
- 没有其他线程想获取互斥量
- 有其他线程想获取互斥量
3.事件集
事件集用于线程之间的事件通知和同步。一个事件集包含多个事件标志,线程可以等待一个或多个事件标志。
至于API参考官方文档
a.事件集控制块
路劲:rt-thread\include\rtdef.h
b.接收事件
路径:.\rt-thread\src\ipc.c
- 接收成功
-
接收不成功
- 不等待
- 等待
c.发送事件
路径:rt-thread\src\ipc.c
- 是否有线程挂起
三、线程间的通信
在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取,根据读取到的全局变量值执行相应的动作,达到通信协作的目的。RT-Thread 中则提供了更多的工具帮助在不同的线程中间传递信息。
1.邮箱
邮箱用于在线程之间传递固定大小的消息。每次发送和接收的消息大小都是固定的。邮箱适用于需要简单、高效传递固定大小数据的场景。
a.邮箱控制块
路径:.\rt-thread\include\rtdef.h
b.接收邮箱
路径:.\rt-thread\src\ipc.c
接收邮箱可以大致分为这几种情况:
- 没有邮箱且不等待
- 没有邮箱且等待
c.发送邮箱
路径:.\rt-thread\src\ipc.c
- 满了不等待
- 满了等待
- 成功发送邮箱
2.消息队列
消息队列用于在线程之间传递可变大小的消息,可以设置消息的优先级。消息队列适用于需要传递不同大小数据和具有优先级调度需求的场景。
邮箱队列的机制跟邮箱大致一样,不同的是两者可以传递的消息大小不一样。