---
title: rtos-freertos-06-task-notify
date: 2020-06-22 15:49:29
categories:
tags:
- ipc
- freertos
- rtos
---

章节概述:

如何使用任务通知实现轻量级同步。

概述

每个RTOS任务都有一个32位的通知值,任务创建时,这个值被初始化为0。RTOS任务通知相当于直接向任务发送一个事件,接收到通知的任务可以解除因等待通知而引起的阻塞状态。

相比于使用信号量解除任务阻塞,使用任务通知可以快45%、使用更少的RAM。

发送通知的同时,也可以可选的改变接收任务的通知值。

可以通过下列方法向接收任务更新通知:

  • 不覆盖接收任务的通知值
  • 覆盖接收任务的通知值
  • 设置接收任务通知值的某些位
  • 增加接收任务的通知值

虽然RTOS任务通知速度更快并且占用内存更少,但它也有一些限制:

  • 只能有一个任务接收通知事件。
  • 接收通知的任务可以因为等待通知而进入阻塞状态,但是发送通知的任务即便不能立即完成通知发送也不能进入阻塞状态。

相对于用前必须分别创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。更好的是,

RTOS任务通知功能默认是使能的,可以通过在文件FreeRTOSConfig.h中设置宏configUSE_TASK_NOTIFICATIONS为0来禁止这个功能,禁止后每个任务节省8字节内存。

发送通知

  1. BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
  2. uint32_t ulValue,
  3. eNotifyAction eAction);
  4. BaseType_t xTaskNotifyGive( xTaskToNotify );
  5. // 中断保护等价函数
  6. BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
  7. uint32_t ulValue,
  8. eNotifyAction eAction,
  9. pxHigherPriorityTaskWoken );
  10. void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
  11. BaseType_t *pxHigherPriorityTaskWoken );

描述:使用API发送通知,在接收RTOS任务调用API函数xTaskNotifyWait()或ulTaskNotifyTake()之前,这个通知都被保持着。

xTaskNotify

  1. BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
  2. uint32_t ulValue,
  3. eNotifyAction eAction);

描述:向指定任务发送指定的通知值。如果打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数xTaskNotifyGive()来代替本函数。

参数解析:

  • xTaskToNotify:被通知的任务句柄。
  • ulValue:通知更新值
  • eAction:枚举类型,指明更新通知值的方法
枚举值 描述
eNoAction 发送通知,但不更新值(参数ulValue未使用)
eSetBits 被通知任务的通知值按位或ulValue。(某些场景下可代替事件组,效率更高)
eIncrement 被通知任务的通知值增加1(参数ulValue未使用),相当于xTaskNotifyGive
eSetValueWithOverWrite 被通知任务的通知值设置为 ulValue。(某些场景下可代替xQueueOverwrite,效率更高)
eSetValueWithoutOverwrite 如果被通知的任务当前没有通知,则被通知的任务的通知值设为ulValue。

如果被通知任务没有取走上一个通知,又接收到了一个通知,则这次通知值丢弃,在这种情况下视为调用失败并返回pdFALSE

(某些场景下可代替xQueueSend,效率更高)

返回值:参数eAction为eSetValueWithoutOverwrite时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

注意:此函数不可以在中断服务例程中调用,中断保护等价函数为xTaskNotifyFromISR()

xTaskNotifyGive

  1. BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );

描述:本质上相当于xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )

其实这是一个宏,使用该API函数代替二进制或计数信号量,但速度更快。

参数解析:

xTaskToNotify:被通知的任务句柄。

注意:

应该使用API函数ulTaskNotifyTake()来等待通知,而不应该使用API函数xTaskNotifyWait()。

此函数不可以在中断服务例程中调用,中断保护等价函数为vTaskNotifyGiveFromISR()

例子:

  1. staticvoid prvTask1( void *pvParameters );
  2. staticvoid prvTask2( void *pvParameters );
  3. /* 保存任务句柄 */
  4. staticTaskHandle_t xTask1 = NULL, xTask2 = NULL;
  5. /* 创建两个任务,它们之间反复发送通知,启动RTOS调度器*/
  6. voidmain( void )
  7. {
  8. xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 );
  9. xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 );
  10. vTaskStartScheduler();
  11. }
  12. /*-----------------------------------------------------------*/
  13. staticvoid prvTask1( void *pvParameters )
  14. {
  15. for( ;; )
  16. {
  17. /*向prvTask2(),发送通知,使其解除阻塞状态 */
  18. xTaskNotifyGive( xTask2 );
  19. /* 等待prvTask2()的通知,进入阻塞 */
  20. ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
  21. }
  22. }
  23. /*-----------------------------------------------------------*/
  24. staticvoid prvTask2( void *pvParameters )
  25. {
  26. for( ;; )
  27. {
  28. /* 等待prvTask1()的通知,进入阻塞 */
  29. ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
  30. /*向prvTask1(),发送通知,使其解除阻塞状态 */
  31. xTaskNotifyGive( xTask1 );
  32. }
  33. }

获取通知

  1. uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,
  2. TickType_t xTicksToWait );

描述:专门为使用更轻量级更快的方法来代替二进制或计数信号量而量身打造的。

如果RTOS任务的通知值为0,使用xTaskNotifyTake()可以指定任务进入阻塞状态的时间(可为0),直到该任务的通知值不为0。

参数解析:

  • xClearCountOnExit:如果该参数设置为pdFALSE,则API函数xTaskNotifyTake()退出前,将任务的通知值减1;如果该参数设置为pdTRUE,则API函数xTaskNotifyTake()退出前,将任务通知值清零。

两种方法处理任务的通知值:

  • 一种方法是在函数退出时将通知值清零,这种方法适用于实现二进制信号量;
  • 另外一种方法是在函数退出时将通知值减1,这种方法适用于实现计数信号量。
  • xTicksToWait:因等待通知而进入阻塞状态的最大时间。时间单位为系统节拍周期。可用pdMS_TO_TICKS将指定的毫秒时间转化为相应的系统节拍数。

返回值:返回任务的当前通知值,为0或者为调用API函数xTaskNotifyTake()之前的通知值减1。

可以用来代替FreeRTOS获取信号量的API函数xSemaphoreTake()。

当一个任务使用通知值来实现二进制或计数信号量时,其它任务或者中断要使用API函数xTaskNotifyGive()或者使用参数eAction为eIncrement的API函数xTaskNotify()。推荐使用xTaskNotifyGive()函数(其实是个宏,我们这里把它看作一个API函数)。另外需要注意的是,如果在中断中使用,要使用它们的中断保护等价函数:vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。

例子:

  1. /* 中断处理程序。*/
  2. voidvANInterruptHandler( void )
  3. {
  4. BaseType_txHigherPriorityTaskWoken;
  5. prvClearInterruptSource();
  6. /* xHigherPriorityTaskWoken必须被初始化为pdFALSE。如果调用vTaskNotifyGiveFromISR()会解除vHandlingTask任务的阻塞状态,并且vHandlingTask任务的优先级高于当前处于运行状态的任务,则xHigherPriorityTaskWoken将会自动被设置为pdTRUE。*/
  7. xHigherPriorityTaskWoken = pdFALSE;
  8. /*向一个任务发送通知,xHandlingTask是该任务的句柄。*/
  9. vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken );
  10. /* 如果xHigherPriorityTaskWoken为pdTRUE,则强制上下文切换。这个宏的实现取决于移植层,可能会调用portEND_SWITCHING_ISR */
  11. portYIELD_FROM_ISR(xHigherPriorityTaskWoken );
  12. }
  13. /*---------------------------------------------------------------------------------------------------*/
  14. /* 一个因为等待通知而阻塞的任务。*/
  15. voidvHandlingTask( void *pvParameters )
  16. {
  17. BaseType_txEvent;
  18. for( ;; )
  19. {
  20. /*等待通知,无限期阻塞。参数pdTRUE表示函数退出前会清零通知值。这显然是用于替代二进制信号量的用法。需要注意的是,真实的程序一般不会无限期阻塞。*/
  21. ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
  22. /* 当处理完所有事件后,仍然等待下一个通知*/
  23. do
  24. {
  25. xEvent = xQueryPeripheral();
  26. if( xEvent != NO_MORE_EVENTS )
  27. {
  28. vProcessPeripheralEvent( xEvent);
  29. }
  30. } while( xEvent != NO_MORE_EVENTS );
  31. }
  32. }

等待通知

如果打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数ulTaskNotifyTake()来代替本函数。

  1. BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
  2. uint32_t ulBitsToClearOnExit,
  3. uint32_t*pulNotificationValue,
  4. TickType_t xTicksToWait );

描述:进入阻塞状态,等待通知;当接收到通知后,任务解除阻塞并清除通知。

参数解析:

  • ulBitsToClearOnEntry:在使用通知之前,先将任务的通知值与参数ulBitsToClearOnEntry的按位取反值按位与操作。设置参数ulBitsToClearOnEntry为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。
  • ulBitsToClearOnExit:在函数xTaskNotifyWait()退出前,将任务的通知值与参数ulBitsToClearOnExit的按位取反值按位与操作。设置参数ulBitsToClearOnExit为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。
  • pulNotificationValue:用于向外回传任务的通知值。这个通知值在参数ulBitsToClearOnExit起作用前将通知值拷贝到*pulNotificationValue中。如果不需要返回任务的通知值,这里设置成NULL。
  • xTicksToWait:因等待通知而进入阻塞状态的最大时间。时间单位为系统节拍周期。可用pdMS_TO_TICKS将指定的毫秒时间转化为相应的系统节拍数。

返回值:如果接收到通知,返回pdTRUE,如果API函数xTaskNotifyWait()等待超时,返回pdFALSE。

例子:

  1. /*这个任务使用任务通知值的位来传递不同的事件,这在某些情况下可以代替事件组。*/
  2. voidvAnEventProcessingTask( void *pvParameters )
  3. {
  4. uint32_tulNotifiedValue;
  5. for( ;; )
  6. {
  7. /*等待通知,无限期阻塞(没有超时,所以不用检查函数返回值)。其它任务或者中断设置的通知值中的不同位表示不同的事件。参数0x00表示使用通知前不清除任务的通知值位,参数ULONG_MAX 表示函数xTaskNotifyWait()退出前将任务通知值设置为0*/
  8. xTaskNotifyWait( 0x00, ULONG_MAX,&ulNotifiedValue, portMAX_DELAY );
  9. /*根据通知值处理事件*/
  10. if( ( ulNotifiedValue & 0x01 ) != 0)
  11. {
  12. prvProcessBit0Event();
  13. }
  14. if( ( ulNotifiedValue & 0x02 ) != 0)
  15. {
  16. prvProcessBit1Event();
  17. }
  18. if( ( ulNotifiedValue & 0x04 ) != 0)
  19. {
  20. prvProcessBit2Event();
  21. }
  22. /* ……*/
  23. }
  24. }

任务通知并查询

  1. BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
  2. uint32_tulValue,
  3. eNotifyActioneAction,
  4. uint32_t*pulPreviousNotifyValue );

描述:此函数与任务通知API函数xTaskNotify()非常像,只不过此函数具有一个附加参数,用来回传任务当前的通知值,然后根据参数ulValue和eAction更新任务的通知值。

参数解析:

  • xTaskToNotify:被通知的任务句柄。
  • ulValue:通知更新值
  • eAction:枚举类型,指明更新通知值的方法,枚举变量成员以及作用见xTaskNotify()一节。
  • pulPreviousNotifyValue:回传未被更新的任务通知值。如果不需要回传未被更新的任务通知值,这里设置为NULL,这样就等价于调用xTaskNotify()函数。

返回值:参数eAction为eSetValueWithoutOverwrite时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

注意:此函数不能在中断服务例程中使用,在中断服务例程中使用xTaskNotifyAndQueryFromISR()函数。

Freertos学习:06-任务通知的更多相关文章

  1. 【FreeRTOS学习06】深度解剖中断与任务之间同步的具体使用场景

    嵌入式系统中中断是必不可少的一部分: [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 1 前言 2 中断特点 3 延迟中断处理 3.1 信号量的使用 3.2 ...

  2. JavaScript学习06 JS事件对象

    JavaScript学习06 JS事件对象 事件对象:当事件发生时,浏览器自动建立该对象,并包含该事件的类型.鼠标坐标等. 事件对象的属性:格式:event.属性. 一些说明: event代表事件的状 ...

  3. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  4. ThinkPhp学习06

    原文:ThinkPhp学习06 一.简单学习修改用户信息模块 1.编写UserAction.class.php <?php class UserAction extends Action{ pu ...

  5. 【FreeRTOS学习05】深度解剖FreeRTOSConfig.h实现对系统的自定义剪裁

    ROM/RAM太小,因此要对系统进行剪裁: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 系统的剪裁 2 FreeRTOSConfi ...

  6. vue学习06 v-show指令

    目录 vue学习06 v-show指令 v-show指令是:根据真假切换元素的显示状态 原理是修改元素的display,实现显示隐藏 指令后面的内容,最终都会解析为布尔值(true和false) 练习 ...

  7. 深度学习-06(PaddlePaddle体系结构与基本概念[Tensor、Layer、Program、Variable、Executor、Place]线性回归、波士顿房价预测)

    文章目录 深度学习-06(PaddlePaddle基础) paddlePaddle概述 PaddlePaddle简介 什么是PaddlePaddle 为什么学习PaddlePaddle PaddleP ...

  8. 【FreeRTOS学习03】小白都能懂的Task Management 任务管理基本概念介绍

    在FreeRTOS中,线程的术语又可以被称之为任务,或许这样更加合适,本文将介绍任务的创建/删除,任务参数的使用,以及任务优先级: 1 软实时和硬实时 硬实时系统的任务运行正确性与响应时限是紧密相关的 ...

  9. FreeRTOS学习笔记——FreeRTOS 任务基础知识

    RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...

  10. 【freertos】013-任务通知及其实现细节

    前言 参考: https://www.freertos.org/RTOS-task-notifications.html 原文:https://www.cnblogs.com/lizhuming/p/ ...

随机推荐

  1. 四:海思Hi3516CV500/Hi3516DV300

    Hi3516CV500 和 Hi3516DV300 均是海思推出的 IP Camera  SoC [System-on-a-Chip:SoC芯片是一种集成电路的芯片] 芯片. 针对海思 HI3516D ...

  2. Zeppelin未授权访问 getshell

    Zeppelin未授权访问 getshell 1.漏洞简介 Apache Zeppelin是一个让交互式数据分析变得可行的基于网页的notebook.Zeppelin提供了数据可视化的框架. Zepp ...

  3. 原生微信小程序

    new Date 跨平台兼容性问题 在 Andriod 使用 new Date("2018-05-30 00:00:00")木有问题,但是在ios 下面识别不出来.因为 IOS 下 ...

  4. pageoffice6 版本在线打开word 文件,实现多用户同时编辑

    总体来说,各种Web系统中的Word文档在线处理大体可以分为以下四种流转处理方式: A用户编辑完,流转给B用户修改,再流转给C用户修改,直到最后.每个用户都是针对全文修改的,如果需要在这一篇文档中能区 ...

  5. text/event-stream协议

    客户端接收 text/event-stream html <!DOCTYPE html> <html> <head> <meta charset=" ...

  6. 🐬记一次MySQL执行修改语句超时问题

    异常问题 原因分析 这个问题发生在开发环境,怀疑是提交事务时终止项目运行,没有提交该事务,造成死锁 调试该事务时时间太长,为什么说有这个原因呢,因为通过查找日志显示 The client was di ...

  7. swagger 的配置

    1,开启swagger : c.IncludeXmlComments(GetXmlCommentsPath()); protected static string GetXmlCommentsPath ...

  8. 阿里巴巴 MySQL 数据库之建表规约(一)

    建表规约 强制部分 [强制] 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否). 说明:任何字段如果为非负数,必须是 ...

  9. 【论文笔记】R-CNN系列之代码实现

    代码源码 前情回顾:[论文笔记]R-CNN系列之论文理解 整体架构 由三部分组成 (1)提取特征的卷积网络extractor (2)输入特征获得建议框rois的rpn网络 (3)传入rois和特征图, ...

  10. openstack考试需要的部署操作

    openstack操作大全 一,keystone 用户 1.创建用户 openstack user create --password 密码 --email邮箱 --domain 域名 用户名字 2. ...