一、简介:
信号量是一种基于队列实现的解决同步问题的机制,可以实现对共享资源的有序访问。信号量又分为二值信号量、计数型信号量、互斥信号量和递归互斥信号量。
二、二值信号量
二值信号量的本质是一个队列长度为 1 的队列 ,该队列就只有空和满两种情况,这就是二值
二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但二值信号量有可能会导致优先级翻转问题,所以二值信号量更适用于任务同步,互斥信号量的优先级集成特点可解决优先级翻转,可用于互斥访问。
创建二值信号量函数:SemaphoreHandle_t xSemaphoreCreateBinary( void )
释放二值信号量函数:BaseType_t xSemaphoreGive( xSemaphore )不支持设置等待时间,即等待时间为0,
获取二值信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
三、计数型信号量
计数型信号量用于事件计数和资源管理。计数型信号量能够容纳多个资
源,这在计数型信号量被创建的时候确定的
- 事件计数
在这个场合中,每次事件发生的时候就在事件处理函数中释放信号量(增加信号量的计数值),其他任务会获取信号量(信号量计数值减一,信号量值就是队列结构体成员变量uxMessagesWaiting)来处理事件。在这种场合中创建的计数型信号量初始计数值为 0。
2、资源管理
在这个场合中,信号量值代表当前资源的可用数量,比如停车场当前剩余的停车位数量。一个任务要想获得资源的使用权,首先必须获取信号量,信号量获取成功以后信号量值就会减一。当信号量值为 0 的时候说明没有资源了。当一个任务使用完资源以后一定要释放信号量,释放信号量以后信号量值会加一。在这个场合中创建的计数型信号量初始值应该是资源的数量,比如停车场一共有 100 个停车位,那么创建信号量的时候信号量值就应该初始化为 100
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,//计数信号量最大计数值
UBaseType_t uxInitialCount )//计数信号量初始值
发送信号量和获取信号量和二值信号量的函数相同
四、互斥信号量
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信
号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!
1、优先级翻转
高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他
中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级
任务具有更高的优先权(即优先级翻转)
2、优先级继承
优先级继承就是为了解决优先级反转问题而提出的一种优化机制。其大致原理是让低优先级任务在获得互斥信号量的时候(如果有高优先级的线程也需要使用该互斥信号量时),临时提升其优先级。以前其能更快的执行并释放同步资源。释放同步资源后再恢复其原来的优先级。
/** 返回值
** NULL: 互斥信号量创建失败。
** 其他值: 创建成功的互斥信号量的句柄。
**/
SemaphoreHandle_t xSemaphoreCreateMutex( void )
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
//pxMutexBuffer:此参数指向一个 StaticSemaphore_t 类型的变量,用来保存信号量结构体
注意:互斥信号量不能用于中断服务函数中,原因如下:
(1) 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以
互斥信号量只能用与任务中,不能用于中断服务函数。
(2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
注意:创建互斥信号量时,会主动释放一次信号量