FreeRTOS同步与互斥:(五)任务通知

注:本文摘自韦东山《FreeRTOS完全开发手册》,如有侵权请告知

文章目录

  • 五、任务通知
    • 5.1 优劣
    • 5.2 通知方式
    • 5.3 任务通知函数
      • 5.3.1 简化版
      • 5.3.2 专业版

**同步与互斥的概念:**

  • 同步: A等待B做完某件事

  • 互斥: 某一资源同一时间仅能有一个用户访问

  • RTOS同步与互斥的方式: 任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)等。

五、任务通知

使用队列、信号量、事件组时,我们都要事先创建对应的结构体,双方通过中间的结构体通信;使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"

5.1 优劣

  • 任务通知的优势

    • 效率更高

    • 更节省内存

  • 任务通知的限制

    • 不能发送数据给ISR
    • 数据只能给该任务独享
    • 如果发送受阻,发送方无法进入阻塞状态等待

5.2 通知方式

每个任务都有一个结构体:TCB(Task Control Block),里面有2个成员:

  • 一个是uint8_t类型,用来表示通知状态(三种取值)
    • taskNOT_WAITING_NOTIFICATION:任务没有在等待通知
    • taskWAITING_NOTIFICATION:任务在等待通知
    • taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为pending(有数据了,待处理)
  • 一个是uint32_t类型,用来表示通知值
    • 计数值
    • 位(类似事件组)
    • 任意数值

5.3 任务通知函数

5.3.1 简化版

/* 发出通知
 * xTaskToNotify:任务句柄(创建任务时得到),给哪个任务发通知
 * 返回值:必定返回pdPASS
 */
BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify);

/* 发出通知
 * xTaskHandle:任务句柄(创建任务时得到),给哪个任务发通知
 * pxHigherPriorityTaskWoken:如果被唤醒的任务的优先级,高于当前任务的优先级,        		·	
 * 							  则"*pxHigherPriorityTaskWoken"被设置为pdTRUE
 */
void vTaskNotifyGiveFromISR(TaskHandle_t xTaskHandle, 
                            BaseType_t *pxHigherPriorityTaskWoken);

/* 取出通知
 * xClearCountOnExit:函数返回前是否清零:pdTRUE:把通知值清零
 * 									 pdFALSE:如果通知值大于0,则把通知值减一
 * xTicksToWait:任务进入阻塞态的超时时间;可以设为portMAX_DELAY:一直等待,直到通知值大于0;
 * 返回值:函数返回之前,在清零或减一之前的通知值
 */
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait);

5.3.2 专业版

xTaskNotify 函数功能更强大,可以使用不同参数实现各类功能,比如:

  • 让接收任务的通知值加一:这时 xTaskNotify() 等同于 xTaskNotifyGive()
  • 设置接收任务的通知值的某一位、某些位,这就是一个轻量级的、更高效的事件组
  • 把一个新值写入接收任务的通知值:上一次的通知值被读走后,写入才成功。这就是轻量级的、长
    度为1的队列
  • 用一个新值覆盖接收任务的通知值:无论上一次的通知值是否被读走,覆盖都成功。类似xQueueOverwrite() 函数,这就是轻量级的邮箱。

使用 xTaskNotifyWait() 函数取出通知

  • 可以让任务等待(可以加上超时时间),等到任务状态为"pending"(也就是有数据)
  • 还可以在函数进入、退出时,清除通知值的指定位
/* 发出通知
 * xTaskToNotify:任务句柄(创建任务时得到),给哪个任务发通知
 * ulValue:怎么使用ulValue,由eAction参数决定
 * eAction:见下表
 * 返回值:pdPASS:成功,大部分调用都会成功
 * 		 pdFAIL:只有一种情况会失败:当eAction为eSetValueWithoutOverwrite且有新数据未读时
 */
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, 
                       uint32_t ulValue,
                       eNotifyAction eAction);

/* xTaskNotifyFromISR函数跟xTaskNotify类似 */
BaseType_t xTaskNotifyFromISR(TaskHandle_t xTaskToNotify,
                              uint32_t ulValue,
                              eNotifyAction eAction,
                              BaseType_t *pxHigherPriorityTaskWoken);

/* 取出通知
 * ulBitsToClearOnEntry:函数入口处,要清除通知值的哪些位
 * ulBitsToClearOnExit:函数出口处,要清除通知值的哪些位
 * pulNotificationValue:用来取出通知值
 * xTicksToWait:任务进入阻塞态的超时时间,可设为portMAX_DELAY:一直等待,直到通知状态变为"pending"
 * 返回值:pdPASS:成功
 * 		  pdFAIL:没有得到通知
 */
BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry,
                           uint32_t ulBitsToClearOnExit,
                           uint32_t *pulNotificationValue,
                           TickType_t xTicksToWait);

eNotifyAction参数说明:

eNotifyAction取值 说明
eNoAction 仅仅是更新通知状态为"pending",未使用ulValue。 这个选项相当于轻量级的、更高效的二进制信号量。
eSetBits 通知值 = 原来的通知值 | ulValue,按位或。相当于轻量级的、更高效的事件组。
eIncrement 通知值 = 原来的通知值 + 1,未使用ulValue。 相当于轻量级的、更高效的二进制信号量、计数型信号量。 相当于 xTaskNotifyGive() 函数。
eSetValueWithoutOverwrite 不覆盖。 如果通知状态为"pending"(表示有数据未读),则此次调用 TaskNotify不做任何事,返回pdFAIL。如果通知状态不是"pending"(表示没有新数据),则:通知值 = ulValue。
eSetValueWithOverwrite 覆盖。 无论如何,不管通知状态是否为"pendng", 通知值 = ulValue。

你可能感兴趣的:(FreeRTOS,stm32)