---
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字节内存。

发送通知

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction); BaseType_t xTaskNotifyGive( xTaskToNotify ); // 中断保护等价函数
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
pxHigherPriorityTaskWoken ); void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
BaseType_t *pxHigherPriorityTaskWoken );

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

xTaskNotify

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
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

BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );

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

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

参数解析:

xTaskToNotify:被通知的任务句柄。

注意:

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

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

例子:

staticvoid prvTask1( void *pvParameters );
staticvoid prvTask2( void *pvParameters ); /* 保存任务句柄 */
staticTaskHandle_t xTask1 = NULL, xTask2 = NULL; /* 创建两个任务,它们之间反复发送通知,启动RTOS调度器*/
voidmain( void )
{
xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 );
xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 );
vTaskStartScheduler();
}
/*-----------------------------------------------------------*/ staticvoid prvTask1( void *pvParameters )
{
for( ;; )
{
/*向prvTask2(),发送通知,使其解除阻塞状态 */
xTaskNotifyGive( xTask2 ); /* 等待prvTask2()的通知,进入阻塞 */
ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
}
}
/*-----------------------------------------------------------*/ staticvoid prvTask2( void *pvParameters )
{
for( ;; )
{
/* 等待prvTask1()的通知,进入阻塞 */
ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /*向prvTask1(),发送通知,使其解除阻塞状态 */
xTaskNotifyGive( xTask1 );
}
}

获取通知

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,
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()。

例子:

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

等待通知

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

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t*pulNotificationValue,
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。

例子:

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

任务通知并查询

BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
uint32_tulValue,
eNotifyActioneAction,
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. MindSpore强化学习:使用PPO配合环境HalfCheetah-v2进行训练

    本文分享自华为云社区<MindSpore强化学习:使用PPO配合环境HalfCheetah-v2进行训练>,作者: irrational. 半猎豹(Half Cheetah)是一个基于Mu ...

  2. Node.js 万字教程

    0. 基础概念 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,使用了一个事件驱动.非阻塞式 I/O 模型,让 JavaScript 运行在服务端的开发平台. ...

  3. 从大数据平台CDP的架构看大数据的发展趋势

    CDP(Cloudera Data Platform)是Cloudera 和 HortonWorks 合并后推出的新一代大数据平台 ,并正在逐步停止对原有的大数据平台 CDH 和 HDP 的维护.笔记 ...

  4. 【GUI软件】小红书指定博主批量采集笔记,支持多博主同时采集!

    目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集模块 2.2 软件界面模块 2.3 日志模块 三.获取源码及软件 一.背景介绍 1.1 爬取目标 ...

  5. 简说Python之数字和变量

    目录 Python的运算 Python关于进制的一些描述 十六进制的显示 八进制和二进制的显示 转成二进制,八进制,十六进制的方法 二,八,十六进制转回十进制的方法 Python变量 数字类型 浮点数 ...

  6. ITIL4服务价值系统(SVS)与莫比乌斯环:无限服务优化的拓扑之旅

    莫比乌斯环:单一而无限的象征 莫比乌斯环,这个拓扑学上的奇观,以其独特的一体两面特性,完美地映射了ITIL4服务价值系统的精髓.它象征着无限.统一和连续性,提示我们看待事物时应超越传统二元对立的视角, ...

  7. vue特殊attribute-key

    官方说明:如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地复用相同类型元素的算法.而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在 ...

  8. angular自定义属性指令

    在angular中有三种类型的指令: 组件–拥有模板的指令: 结构性指令–通过添加和移除DOM元素改变DOM布局的指令; 属性型指令–改变元素.组件或其他指令的外观和行为的指令: 组件是这三种指令中最 ...

  9. 一文了解npm install -g和npm install --save-dev的关系

    本文分享自华为云社区<npm install -g 和 npm install --save-dev 的关系>,作者: SHQ5785. 一.npm install 本地安装 将安装包放在 ...

  10. Android 12(S) MultiMedia Learning(七)NuPlayer GenericSource

    本节来看一下NuPlayer Source中的GenericSource,GenericSource主要是用来播放本地视频的,接下来着重来看以下5个方法: prepare,start,pause,se ...