FreeRTOS学习-信号量与优先级反转

转载自https://blog.csdn.net/weixin_43866583/article/details/125528885?spm=1001.2014.3001.5502

FreeRTOS学习-信号量与优先级反转

FreeRTOS中最常用到的信号量有:二值信号量、计数信号量、互斥信号量。

二值信号量

二值信号量是指所创建的信号量只有两个值(0 和 1),通常用于互斥访问或者同步。

二值信号量在某处被占有使用之后,其他地方想要申请这个二值信号量是无法成功申请的,只有当这个被占有的二值信号量被使用完毕并释放之后,才能被再次申请占有使用!

总而言之,二值信号量被使用之后会变为无效状态,需要被重新释放才能进入有效状态。

创建二值信号量

1
SemaphoreHandle_t xSemaphoreCreateBinary(void)

函数描述:

​ 函数 xSemaphoreCreateBinary 用于创建二值信号量。

​ 返回值:如果创建成功会返回二值信号量的句柄,创建失败会返回 NULL。

等待二值信号量

1
2
xSemaphoreTake( SemaphoreHandle_t xSemaphore,     /* 信号量句柄 */ 
TickType_t xTicksToWait ); /* 等待信号量可用的最大等待时间 */

函数 xSemaphoreTake 用于在任务代码中获取信号量。

在中断中等待信号量

1
xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )

释放二值信号量

1
xSemaphoreGive( SemaphoreHandle_t xSemaphore ); /* 信号量句柄 */

返回值,如果信号量释放成功返回 pdTRUE,否则返回 pdFALSE,因为信号量的实现是基于消息队列,返回失败的主要原因是消息队列已经满了。

用于在中断中释放二值信号量

1
2
xSemaphoreGiveFromISR(    SemaphoreHandle_t xSemaphore, 
signed BaseType_t *pxHigherPriorityTaskWoken)

计数信号量

计数信号量是一个相当于长度大于1的队列,用于任务之间的同步和共享资源的保护。

计数信号量与二值信号量的不同在于,二值信号量只能被一个地方申请使用,只有在这个申请使用的地方了释放了才能被其他处申请使用。而计数信号量是可以创建一定数量的信号量的,多个地方可以同时申请使用,直到达到最大的计数信号量的阈值。

创建计数信号量

1
2
3
SemaphoreHandle_t xSemaphoreCreateCounting( 
UBaseType_t uxMaxCount, /* 支持的最大计数值 */
UBaseType_t uxInitialCount); /* 初始计数值 */

优先级反转 & 互斥信号量

在实时操作系统中,优先级反转的问题是不容忽视的,程序设计的过程中,也是要充分考虑这个问题的。

那优先级反转到底是什么呢?

优先反转是指:假如一个系统中有高(H)、中(M)、低(L)三个优先级的任务,并有一个二值信号量。在某一个时刻二值信号量被低(L)优先级的任务使用了,并在运行过程中,高优先级任务(H)抢占了低优先级(L)的CPU使用权,但是也想要获取二值信号量被低优先(L)的任务占有着,高优先级任务(H)由此被挂起等待了,中优先级任务(M)因为不需要二值信号量,会抢占低优先级(L)任务的执行而得到运行,而高优先级任务(H)依然只能等到低优先级任务(L)释放二值信号量才能得到执行。

由此造成了高优先级任务得不到及时的执行,而低优先级任务却能比高优先级任务更多的得到执行。

解决优先级反转的问题最好的办法是使用互斥信号量。

互斥信号量和二值信号量比较相似,不同之处在于互斥信号量具有优先级继承的特性,如果一个互斥信号量正在被一个低优先级的任务使用,而此时这个高优先级的任务也希望获取这个互斥信号量的话就会被阻塞。

使用互斥信号量时,高优先级的任务会把低优先级的任务的优先级先提高到和自己相同的优先级,保证低优先级的任务能够继续运行至结束这样极大减少了因为高优先级获取不到信号量被阻塞过长时间的问题。

创建互斥信号量

1
SemaphoreHandle_t xSemaphoreCreateMutex(void)