rtthread 互斥量 学习笔记
概述
怎么独享厕所?自己开门上锁,完事了自己开锁。
你当然可以进去后,让别人帮你把门:但是,命运就掌握在别人手上了。
使用队列、信号量,都可以实现互斥访问,以信号量为例:
- 信号量初始值为 1
- 任务 A 想上厕所,"take"信号量成功,它进入厕所
- 任务 B 也想上厕所,"take"信号量不成功,等待
- 任务 A 用完厕所,"give"信号量;轮到任务 B 使用
这需要有
2
个前提:
- 任务 B 很老实,不撬门(一开始不"give"信号量)
- 没有坏人:别的任务不会"give"信号量
可以看到,使用信号量确实也可以实现互斥访问,但是不完美。
使用互斥量可以解决这个问题,互斥量的名字取得很好:
- 量:值为 0、1
- 互斥:用来实现互斥访问
它的核心在于:谁上锁,就只能由谁开锁。
使用过程
互斥量也被称为互斥锁,使用过程如下:
- 互斥量初始值为 1
- 线程 A 想访问临界资源,先获得并占有互斥量,然后开始访问
- 线程 B 也想访问临界资源,也要先获得互斥量:如果互斥量被别人占有了,线程 B 就会阻塞
- 线程 A 使用完毕,释放互斥量;线程 B 被唤醒、得到并占有互斥量,然后开始访问临界资源
- 线程 B 使用完毕,释放互斥量
注意
:在线程
A
占有互斥量的过程中,线程
B
、线程
C
等等,都无法释放互斥量。只
能由线程
A
也就是信号量的占有者释放
互斥量函数
互斥量是一种特殊的二值信号量。
使用互斥量时,先创建、然后去获得、释放它。
创建/初始化
互斥量的创建有两种方法:动态分配内存、静态分配内存,
- 动态分配内存:rt_mutex_create,从对象管理器中分配一个 mutex 对象, 并初始化这个对象
- 静态分配内存:rt_mutex_init,互斥量的内存要事先分配好
rt_mutex_create()
函数原型如下:
rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);
参数
|
说明
|
name
|
互斥量名称
|
flag
|
互斥量标志,已废除,均按
RT_IPC_FLAG_PRIO
处理
|
返回值
|
互斥量句柄:成功,返回句柄,以后使用句柄来操作互斥量
RT_NULL
:失败
|
rt_mutex_init()
函数原型如下:
rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);
参数
|
说明
|
mutex
|
互斥量对象的句柄
|
name
|
互斥量的名字
|
flag
|
互斥量标志,已废除,均按
RT_IPC_FLAG_PRIO
处理
|
返回值
|
RT_EOK
:成功
|
删除/脱离
不再使用一个互斥量时:
- 删除它:rt_mutex_delete(),只能删除使用 rt_mutex_create()创建的互斥量
- 脱离它:rt_mutex_detach(),只能脱离使用 rt_mutex_init()初始化的互斥量
删除互斥量的函数为
rt_mutex_delete()
,它会释放内存。原型如下:
rt_err_t rt_mutex_delete (rt_mutex_t mutex);
删除互斥量时,如果有线程在等待该互斥量,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR
),然后再释放互斥量使用的内存,最后删除互斥量对象。
脱离互斥量,就是将互斥量对象被从内核对象管理器中脱离。原型如下:
rt_err_t rt_mutex_detach (rt_mutex_t mutex);
脱离互斥量时,如果有线程在等待该互斥量,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR
)。
获取/释放
互斥量某一时刻只能被一个线程持有。
RT-Thread
有两个获取互斥量的函数
,
一个释放互斥量函数:
- rt_mutex_take() 获取互斥量
- rt_mutex_trytake() 无等待、尝试获取互斥量
- rt_mutex_release() 释放互斥量
如果互斥量没有被其他线程持有,使用
rt_sem_take()
即可获取互斥量。
如果互斥量已被其他线程持有,使用
rt_sem_take()
获取互斥量则挂起等待,直到其他线程释放或等待时间超时。
如果互斥量没有被其他线程持有,使用
rt_mutex_trytake()
即可获取互斥量。
如果互斥量已被其他线程持有,使用
rt_mutex_trytake()
直接返回失败,不会等待。
当线程完成资源的互斥访问后,应尽快使用
rt_sem_release()
释放互斥量,使其他线程能及时获取互斥量。
注意
:拥有互斥量控制权的线程才能释放它,其他线程无法释放互斥量。
获取互斥量的函数原型如下:
rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);
参数
|
说明
|
mutex |
互斥量对象的句柄
|
time
|
超时时间,单位为系统时钟节拍(
OS Tick
)
|
返回值
|
RT_EOK
:获取互斥量成功
RT_ETIMEOUT
:获取互斥量超时
RT_ERROR
:获取互斥量错误
|
无等待、尝试获取互斥量的函数原型如下:
rt_err_t rt_mutex_trytake(rt_mutex_t mutex);
参数
| 说明 |
mutex
|
互斥量的句柄
|
返回值
|
RT_EOK
:获取互斥量成功
RT_ETIMEOUT
:获取互斥量超时
|
释放互斥量的函数原型如下:
rt_err_t rt_mutex_release(rt_mutex_t mutex);
参数
| 说明 |
mutex
|
互斥量的句柄
|
返回值
|
RT_EOK
:获取互斥量成功
|