CMSIS-RTOS 信号量与互斥锁详解
CMSIS-RTOS
信号量
信号量简介
- 信号量又分为计数信号量和二值信号量。信号量在创建是可以指定计数最大的次数,如果最大计数次数为1则是二值信号量,如果是2及以上是计数信号量。调用API每获取或释放一次信号量,信号量的值减少1或增加1。当信号量的值为0的时候,获取信号量的API无法获取信号量,会阻塞等待该API指定等待的时间(如果指定等待时间为0则不等待)。这两个本质上是一个东西,只有最大计数量的区别,只是为最大计数量为1的信号量起了一个名字叫二值信号量
- 信号量用于解决多任务之间的同步问题:比如UART发送,要等待ADC数据采样完了再发送(仅举例作用,这种一般用消息列队)。这时我们就可以创建一个信号量,可以在创建时指定该信号量第一次能不能被获取。
当ADC任务采样完成后,释放信号量。未释放信号量的时候,串口任务被调度器判定为阻塞态,不会执行。当释放信号量之后调度器会优先让更高优先级的任务获取信号量。获取信号量之后,信号量的计数值减1,并让获取到该信号量的任务进入运行态。 - 如何选择二值信号量和计数信号量
- 任务同步使用二值信号量(同步的意思是?)
- 表达资源可用数量,如一个数组的使用情况
- 使用信号量需要注意容易遇到的问题
/// Acquire a Semaphore token or timeout if no tokens are available.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return status code that indicates the execution status of the function.
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);
```
- 任务锁死:可以看到上方获取信号量的API第三个参数是等待时间,意思是尝试获取该信号量,如果没有获取到,尝试在等待时间内获取信号量,如果等在时间内没有获取到信号量则会执行下一句并返回osErrorTimeout,当然也可以设置等待时间为osWaitForever,意思是永久等待。但是一般不推荐永久等待,因为这会导致任务锁死,即如果其他任务没有正确的释放信号量,这个任务将会一直阻塞等待而不执行。 同时也要确保设计信号量时,每一个获取操作都要有与之对应的释放操作,否则很容易锁死
- 优先级反转:[[RTOS演示.canvas|RTOS演示]]
- 中断中使用:osSemaphoreAcquire和osSemaphoreRelease这两个API都可以在中断中使用,但是要注意获取信号量的这个不能设定阻塞时间,必须立即返回,否则会报错osErrorParameter指参数错误(在中断中指定非0超时时间)[[RTOS#哪些API不能在中断中调用]]
- 禁止递归获取:在递归函数中要注意
5. 学完后需能独立回答以下几点
- 什么是信号量?
- 二值信号量和互斥信号量的区别?
- 两种信号量使用的时候怎么选择?
- 使用时应该注意哪些问题?
请根据这些问题进行查缺补漏,并前往CMSIS-RTOS2 文档翻译 - STM32F407 - 硬汉嵌入式论坛 - Powered by Discuz!翻看熟悉关于信号量的其他API
信号量实操
互斥锁
互斥锁概念
互斥锁一般用于访问共享资源,如同一个外设和全局变量
互斥锁和二值信号量相似,但又有一些特点:
- 所有权机制:哪个任务获取的互斥锁那么就只能由这个任务释放。信号量则是任何任务都可以释放。
- 优先级继承机制:用于解决信号量导致的优先级反转
- 支持递归获取:在一个任务中可以进行多次获取,在结束时也进行同样次数的释放即可
除了这几点之外,互斥锁和二值信号量还是很像的
哪些API不能在中断中调用

当中断中调用了允许使用的API时,必须确保这个中断的优先级在RTOS可管理的范围内。因为在中断中调用RTOS的API时,内核会把不在掌控范围内的中断全部临时屏蔽以确保操作的安全。5-15
下面这些API不能在中断中使用
- 信号量的删除
- 互斥锁的获取和释放和删除
- 消息列队的重置和删除
- 待补充
