freeRTOS学习日记

六、二值信号量

什么是信号量?

信号量(SeMaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关

键代码段不被并发调用。

信号量这个名字,我们可以把它拆分来看,信号可以起到通知信号的作用,然后我们的量还

可以用来表示资源的数量,当我们的量只有0和1的时候,它就可以被称作二值信号量,只有

两个状态,当我们的那个量没有限制的时候,它就可以被称作为计数型信号量。
信号量也是队列的一种。|

什么是二值信号量?

二值信号量其实就是一个长度为1,大小为零的队列,只有0和1两种状态,通常情况下,我

们用它来进行互斥访问或任务同步。

互斥访问:比如门钥匙,只有获取到钥匙才可以开门

任务同步:比如我录完视频你才可以看视频

二值信号量相关API函数
  1. 创建二值信号量

    cpp 复制代码
    SemaphoreHandle_t xSemaphoreCreateBinary( void)

    参数:


    返回值:

    成功,返回对应二值信号量的句柄;

    失败,返回NULL。

  2. 释放二值信号量

    cpp 复制代码
    BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore)

    参数:
    xSemaphore:要释放的信号量句柄
    返回值:
    成功,返回 pdPASS;
    失败,返回errQUEUE_FULL。

  3. 获取二值信号量

cpp 复制代码
BaseType_t xSemaphoreTake(
                        SemaphoreHandle_t xSemaphore,
                        TickType_t xTicksToWait 
);

参数:

xSemaphore:要获取的信号量句柄

xTicksToWait:超时时间,0表示不超时,portMAX_DELAY表示卡死等待;
返回值:

成功,返回 pdPASS;

失败,返回errQUEUE_FULL。

七、计数型信号量

什么是计数型信号量?

计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在计

数型信号量被创建的时候确定的。

计数型信号量相关API函数

计数型信号量的释放和获取与二值信号量完全相同!

cpp 复制代码
SemaphoreHandle_t xSemaphoreCreateCounting(
                                        UBaseType_tuxMaxCount,
                                        UBaseType_tuxInitialCount
                                        );

参数:

uxMaxCount:可以达到的最大计数值

uxInitialCount:创建信号量时分配给信号量的计数值
返回值:

成功,返回对应计数型信号量的句柄;

失败,返回NULL。

八、互斥量

什么是互斥量?

在多数情况下,互斥型信号量和二值型信号量非常相似,但是从功能上二值型信号量用于同

步,而互斥型信号量用于资源保护。

互斥型信号量和二值型信号量还有一个最大的区别,互斥型信号量可以有效解决优先级反转

现象。

什么是优先级翻转?

以上图为例,系统中有3个不同优先级的任务H/M/L,最高优先级任务H和最低优先级任务L

通过信号量机制,共享资源。目前任务L占有资源,锁定了信号量,TaskH运行后将被阻

塞,直到TaskL释放信号量后,TaskH才能够退出阻塞状态继续运行。但是TaskH在等待

TaskL释放信号量的过程中,中等优先级任务M抢占了任务L,从而延迟了信号量的释放时

间,导致TaskH阻塞了更长时间,这种现象称为优先级倒置或反转。
优先级继承: 当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级

的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先
级的任务会将低优先级任务的优先级提升到与自己相同的优先级。

优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影
响。

互斥量相关API函数

互斥信号量不能用于中断服务函数中!

cpp 复制代码
SemaphoreHandle_t xSemaphoreCreateMutex(void)

参数:

返回值:
成功,返回对应互斥量的句柄;
失败,返回NULL。

九、事件标志组

什么是事件标志组?

事件标志位: 表明某个事件是否发生,联想:全局变量flag。通常按位表示,每一个位表示

一个事件(高8位不算)
事件标志组 是一组事件标志位的集合,可以简单的理解事件标志组,就是一个整数。

事件标志组本质是一个16位或32位无符号的数据类型EventBits_t,由configUSE_16_BIT_TICKS决定。

虽然使用了32位无符号的数据类型变量来存储事件标志,但其中的高8位用作存储事件标志

组的控制信息,低24位用作存储事件标志,所以说一个事件组最多可以存储24个事件标志!

事件标志组相关API函数
  1. 创建事件标志位

    cpp 复制代码
    EventGroupHandle_t xEventGroupCreate(void );

    参数:


    返回值:

    成功,返回对应事件标志组的句柄;

    失败,返回NULL。

  2. 设置事件标志位

    cpp 复制代码
    EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
    const EventBits_tuxBitsToSet );

    参数:

    xEventGroup:对应事件组句柄。

    uxBitsToSet:指定要在事件组中设置的一个或多个位的按位值。
    返回值:

    设置之后事件组中的事件标志位值。

  3. 清除事件标志位

    cpp 复制代码
    EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
    const EventBits_t uxBitsToClear

    参数:

    xEventGroup:对应事件组句柄。

    uxBitsToClear:指定要在事件组中清除的一个或多个位的按位值。
    返回值:

    清零之前事件组中事件标志位的值。

  4. 等待事件标志位

    cpp 复制代码
    EventBits_t xEventGroupwaitBits
    const EventGroupHandle_t xEventGroup,
    const EventBits_t uxBitsToWaitFor,
    const BaseType_t xClearOnExit,
    const BaseType_t xWaitForAllBits,
    TickType_t xTicksToWait );

    参数:

    xEventGroup:对应的事件标志组句柄

    uxBitsToWaitFor:指定事件组中要等待的一个或多个事件位的按位值

    xClearOnExit:pdTRUE------清除对应事件位,pdFALSE------不清除

    xWaitForAlIBits:pdTRUE------所有等待事件位全为1(逻辑与),pdFALSE---等待的事件

    位有一个为1(逻辑或)

    xTicksToWait:超时
    返回值:

    等待的事件标志位值:等待事件标志位成功,返回等待到的事件标志位

    其他值:等待事件标志位失败,返回事件组中的事件标志位

十、任务通知

什么十任务通知?

FreeRTOS从版本V8.2.0开始提供任务通知这个功能,每个任务都有一个32位的通知值。

按照FreeRTOS官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快45%,并且更加省内存(无需创建队列)。

在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件标志组,可以替代长度

为1的队列(可以保存一个32位整数或指针值),并且任务通知速度更快、使用的RAM更

少!

任务通知值得更新方式

FreeRTOS提供以下几种方式发送通知给任务:

  • ·发送消息给任务,如果有通知未读,不覆盖通知值
  • ·发送消息给任务,直接覆盖通知值
  • ·发送消息给任务,设置通知值的一个或者多个位
  • ·发送消息给任务,递增通知值

通过对以上方式的合理使用,可以在一定场合下替代原本的队列、信号量、事件标志组等。

任务通知的优势和劣势
任务通知的优势
  1. 使用任务通知向任务发送事件或数据,比使用队列、事件标志组或信号量快得多。
  2. 使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体。
任务通知的劣势
  1. 只有任务可以等待通知,中断服务函数中不可以,因为中断没有**TCB(**在任务中开辟一个空间)。
  2. 通知只能一对一,因为通知必须指定任务。
  3. 等待通知的任务可以被阻塞,但是发送消息的任务,任何情况下都不会被阻塞等待。
  4. 任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。
任务通知相关API函数
  1. 发送通知

    cpp 复制代码
    BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify,
    uint32_t ulValue,
    eNotifyAction eAction );

    参数:
    xTaskToNotify:需要接收通知的任务句柄;
    ulValue:用于更新接收任务通知值,具体如何更新由形参eAction决定;
    eAction:一个枚举,代表如何使用任务通知的值;

    返回值:
    如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回
    pdFALSE,而其他情况均返回pdPASS。

    cpp 复制代码
    BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
    uint32_t ulValue,
    eNotifyAction eAction,
    uint32_t *pulPreviousNotifyValue );

    参数:

    xTaskToNotify:需要接收通知的任务句柄;

    ulValue:用于更新接收任务通知值,具体如何更新由形参eAction决定;

    eAction:一个枚举,代表如何使用任务通知的值;

    pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为NULL,则不需要回传,这个时候就等价于函数xTaskNotify( )。
    返回值:

    如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回

    pdFALSE,而其他情况均返回pdPASS。

    cpp 复制代码
    BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify);

    参数:

    xTaskToNotify:接收通知的任务句柄,并让其首身的任务通知值加1。
    返回值:

    总是返回pdPASS。

  2. 等待通知
    等待通知API函数只能用在任务,不可应用于中断中!

    cpp 复制代码
    uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit,
    TickType_t xTicksToWait );

    参数:
    xClearCountOnExit:指定在成功接收通知后,将通知值清零或减1,pdTRUE:把通知值清
    零(二值信号量);pdFALSE:把通知值减一(计数型信号量);
    xTicksToWait:阻塞等待任务通知值的最大时间;
    返回值:
    0:接收失败
    非0:接收成功,返回任务通知的通知值

    cpp 复制代码
    BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry,
    uint32_t ulBitsToClearOnExit,
    uint32_t *pulNotificationValue,
    TickType_t xTicksToWait);

    ulBitsToClearOnEntry:函数执行前清零任务通知值那些位。
    ulBitsToClearOnExit:表示在函数退出前,清零任务通知值那些位,在清0前,接收到的任
    务通知值会先被保存到形参*pulNotificationValue中。
    pulNotificationValue:用于保存接收到的任务通知值。如果不需要使用,则设置为NULL
    即可。
    xTicksToWait:等待消息通知的最大等待时间。

相关推荐
学传打活5 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16812 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心15 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552720 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552721 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝22 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552722 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552723 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552725 天前
Java实用类应用精讲
人工智能·1024程序员节
u0103055271 个月前
Java I/O核心操作实战
人工智能·1024程序员节