1. 简介
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。
1.1 特点
- 当计数值大于0,代表有信号量资源
- 当获取信号量,信号量计数值减一
- 当释放信号量,信号量计数值加一
- 当信号量最大值被限定为1,那么就是二值信号量;如果最大值不是1,它就是计数型信号量。
2. 二值信号量
-
二值信号量的本质是一个队列长度为1 的队列,该队列就只有空和满两种情况,这就是二值。
-
二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值信号量更适合用于同步!
进程互斥,指的是对某个系统资源,一个进程正在使用它,另外一个想用它的进程就必须等待,而不能同时使用 。
2.1 二值信号量API函数
- 创建二值信号量函数
SemaphoreHandle_t xSemaphoreCreateBinary(void)
- 释放二值信号量函数
BaseType_t xSemaphoreCreateBinary(void)
- 获取二值信号量函数
BaseType_t xSemaphoreTake(xSemaphore,xBlockTime)
3. 计数型信号量
计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的。
3.1 适用场合
- 事件计数
当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1),其他任务会获取计数型信号量(计数值-1),这种场合一般在创建时将初始计数值设置为0
- 资源管理
信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1)才能获取资源控制权。当计数值减为0时表示没有的资源。当任务使用完资源后,必须释放信号量。信号量创建的计数值应等于最大资源数目。
3.3 相关API函数
- 创建计数型信号量
xSemapHoreCreateCounting(uxMaxCount,uxInitialCount)
- 获取信号量当前计数值大小
uxSemaphoreGetCount(xSemaphore)
- 计数型信号量的释放和获取与二值信号量相同!
优先级翻转
高优先级的任务反而慢执行,低优先级的任务反而优先执行!
在抢占式内核中优先级翻转是非常常见的,但是在实时操作系统中是不允许出现这种,因为优先级翻转会破坏任务的预期顺序,导致严重的后果。
总结:高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)
5.互斥信号量
一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。但在需要互斥访问的应用中互斥信号量最适合!
5.1 优先级继承
当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级的任务的优先级提升到与自己相同的优先级来。
5.2 注意
互斥信号量不能用于中断服务函数,在于:
- 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥信号量只能用于任务中,不能用于中断服务函数
- 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
- 创建互斥信号量时,会主动释放一次信号量。