十八、任务通知

news2024/11/29 10:39:49

1、前言

(1)所谓“任务通知”,可以反过来读"通知任务"。我们使用队列、信号量、事件组等等方法时,并不知道对方是谁。使用任务通知时,可以明确指定:通知哪个任务。

(2)使用队列、信号量、事件组时,我们都需要实先创建对应的结构体,双方通过中间的结构体通信:

(3)使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的“通知”:

(4)本文涉及的内容:

  • 任务通知:通知状态、通知值
  • 任务通知的使用场合
  • 任务通知的优势及限制

2、任务通知的特性

2.1、优势及限制

(1)任务通知的优势:

  • 效率更高:使用任务通知来发送事件、数据给某个任务时,效率更高。比队列、信号量、事件组都有优势。
  • 更节省内存:使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体。

(2)任务通知的限制:

  • 不能发送数据给ISR:ISR并没有任务结构体,所以无法使用任务通知的功能给ISR发送数据。但ISR可以使用任务通知的功能,发送数据给任务。
  • 数据只能给该任务独享:使用队列、信号量、事件组时,数据保存在这些结构体中,其他任务、ISR都可以访问这些数据。使用任务通知时,数据存放在目标任务中,只有它可以访问这些数据。在日常工作中,这个限制影响不大。因为很多场合是从多个数据源把数据发给某个任务,而不是把一个数据源发给多个任务。
  • 无法缓冲数据:使用队列时,假设队列深度为N,那么它可以保持N个数据。使用任务通知时,任务结构体中只有一个任务通知值,只能保持一个数据。
  • 无法广播给多个任务:使用事件组可以同时给多个任务发送事件。使用任务通知,只能发给一个任务。
  • 如果发送受阻,发送方无法进入阻塞状态等待:假设队列已经满了,使用 xQueueSendToBack() 给队列发送数据时,任务可以进入阻塞状态等待发送完成。使用任务通知时,即使对方无法接收数据,发送方也无法阻塞等待,只能即刻返回错误。

2.2、通知状态和通知值

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

  • 一个是uint8_t类型,用来表示通知状态
  • 一个是uint32_t类型,用来表示通知值
typedef struct tskTaskControlBlock
{
    ......
    /* configTASK_NOTIFICATION_ARRAY_ENTRIES = 1 */
    volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    ......
} tskTCB;

(2)通知状态有3种取值:

  • taskNOT_WAITING_NOTIFICATION:任务没有在等待通知
  • taskWAITING_NOTIFICATION:任务在等待通知
  • taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为pending(有数据了,待处理)
##define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 )  /* 也是初始状态 */
##define taskWAITING_NOTIFICATION     ( ( uint8_t ) 1 )
##define taskNOTIFICATION_RECEIVED    ( ( uint8_t ) 2 )

(3)通知值可以有很多种类型:

  • 计数值
  • 位(类似事件组)
  • 任意数值

3、任务通知的使用

3.1、两类函数

(1)任务通知有2套函数,简化版、专业版,列表如下:

  • 简化版函数的使用比较简单,它实际上也是使用专业版函数实现的
  • 专业版函数支持很多参数,可以实现很多功能
简化板专业板
发出通知

xTaskNotifyGive

vTaskNotifyGiveFromISR

xTaskNotify

xTaskNotifyFromISR

取出通知ulTaskNotifyTakexTaskNotifyWait

3.2、简化版

(1)在任务中使用xTaskNotifyGive函数,在ISR中使用vTaskNotifyGiveFromISR函数;两个函数都是直接给其他任务发送通知:

  • 使得通知值加1。
  • 并使得通知状态变为“pending”,也就是 taskNOTIFICATION_RECEIVED ,表示有数据了,待处理。

(2)可以使用 ulTaskNotifyTake 函数来取出通知值:

  • 如果通知值等于0,则阻塞(可以指定超时时间)
  • 当通知值大于0时,任务从阻塞状态进入就绪态
  • 在 ulTaskNotifyTask 返回之前,还可以做些清理工作:把通知值减1,或者把通知值清零。

(3)使用ulTaskNotifyTask函数可以实现轻量级的、高效的二进制信号量、计数型信号量。

(4)函数原型如下:

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify ); 
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken ); 
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); 

(5)xTaskNotifyGive函数的参数说明如下:

参数说明
xTaskToNotify任务句柄(创建任务时得到),给哪个任务发通知
返回值必定返回pdPASS

(6)vTaskNotifyGiveFromISR函数的参数说明如下:

参数说明
xTaskHandle任务句柄(创建任务时得到),给哪个任务发通知
xTaskHandle

被通知的任务,可能正处于阻塞状态。
此函数发出通知后,会把它从阻塞状态切换为就绪态。

如果被唤醒的任务的优先级,高于当前任务的优先级,
则" *pxHigherPriorityTaskWoken "被设置为pdTRUE,
这表示在中断返回之前要进行任务切换。

(7)ulTaskNotifyTake函数的参数说明如下:

参数说明
xClearCountOnExit函数返回前是否清零:
pdTRUE:把通知值清零
pdFALSE:如果通知值大于0,则把通知值减1
xTicksToWait

任务进入阻塞态的超时时间,它在等待通知值大于0。

0:不等待,即刻返回;

portMAX_DELAY:一直等待,直到通知值大于0;

其他值:Tick Count,可以用 pdMS_TO_TICKS() 把ms转换为Tick Count

返回值

函数返回之前,在清零或减1之前的通知值。

如果xTicksToWait非0,则返回值有2种情况:

1. 大于0:在超时前,通知值被增加了
2. 等于0:一直没有其他任务增加通知值,最后超时返回0

3.3、专业版

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

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

(2)xTaskNotify() 比 xTaskNotifyGive() 更灵活、强大,使用上也就更复杂。

(3)xTaskNotifyFromISR() 是 xTaskNotify() 对应的ISR版本。

(4)xTaskNotifyFromISR() 和 xTaskNotify() 函数用来发出通知任务,使用 xTaskNotifyWait() 函数来取出任务通知。xTaskNotifyWait() 比 ulTaskNotifyTake() 更复杂:

  • 和 ulTaskNotifyTake() 一样,可以让任务等待(可以加上超时时间),等到任务状态为“pending”(也就是有数据)。
  • 还可以在函数进入、退出时,清除通知值得指定位。

(5)这几个函数的原型如下:

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, 
                        uint32_t ulValue,
                        eNotifyAction eAction );

BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
                               uint32_t ulValue,
                               eNotifyAction eAction,
                               BaseType_t *pxHigherPriorityTaskWoken );

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
                            uint32_t ulBitsToClearOnExit,
                            uint32_t *pulNotificationValue,
                            TickType_t xTicksToWait );

(6)xTaskNotify函数的参数说明如下:

参数说明
xTaskToNotify任务句柄(创建任务时得到),给哪个任务发通知
ulValue怎么使用ulValue,由eAction参数决定
eAction见下表
返回值

pdPASS:成功,大部分调用都会成功

pdFAIL:只有一种情况会失败,当eAction为eSetValueWithoutOverwrite,
并且通知状态为"pending"(表示有新数据未读),这时就会失败。

eAction参数说明:

eAction取值说明
eNoAction

仅仅是更新通知状态为“pending”,未使用ulValue。

这个选项相当于轻量级的、更高效的二进制信号量。

eSetBits通知值 = 原来的通知值 | ulValue,按位或。
相当于轻量级的、更高效的事件组。
eIncrement通知值 = 原来的通知值 + 1,未使用ulValue。
相当于轻量级的、更高效的二进制信号量、计数型信号量。
相当于 xTaskNotifyGive() 函数。
eSetValueWithoutOverwrite

不覆盖。
如果通知状态为"pending"(表示有数据未读),

则此次调用xTaskNotify不做任何事,返回pdFAIL。
如果通知状态不是"pending"(表示没有新数据),

则:通知值 = ulValue。

eSetValueWithOverwrite覆盖。
无论如何,不管通知状态是否为"pendng",
通知值 = ulValue。

(7)xTaskNotifyFromISR函数跟xTaskNotify很类似,就多了最后一个参数pxHigherPriorityTaskWoken 。在很多ISR函数中,这个参数的作用都是类似的,使用场景如下:

  • 被通知的任务,可能处于阻塞状态
  • xTaskNotifyFromISR 函数发出通知后,会把接收任务从阻塞状态切换为就绪态
  • 如果被唤醒的任务的优先级,高于当前任务的优先级,则"*pxHigherPriorityTaskWoken"被设置为pdTRUE,这表示在中断返回之前要进行任务切换。

(8)xTaskNotifyWait 函数列表如下:

参数说明
ulBitsToClearOnEntry

在xTaskNotifyWait入口处,要清除通知值的哪些位?

通知状态不是"pending"的情况下,才会清除。

它的本意是:我想等待某些事件发生,所以先把"旧数据"的某些位清零。

能清零的话:通知值 = 通知值 & ~(ulBitsToClearOnEntry)。

比如传入0x01,表示清除通知值的bit0;
传入0xFFFFFFFF即ULONG_MAX,表示清除所有位,即把值设置为0

ulBitsToClearOnExit

在xTaskNotifyWait出口处,如果不是因为超时退出,

而是因为得到了数据而退出时:

通知值 = 通知值 & ~(ulBitsToClearOnExit)。
在清除某些位之前,通知值先被赋给"*pulNotificationValue"。
比如入0x03,表示清除通知值的bit0、bit1;
传入0xFFFFFFFF即ULONG_MAX,表示清除所有位,即把值设置为0

pulNotificationValue

用来取出通知值。
在函数退出时,使用ulBitsToClearOnExit清除之前,

把通知值赋给"*pulNotificationValue"。
如果不需要取出通知值,可以设为NULL。

xTicksToWait任务进入阻塞态的超时时间,它在等待通知状态变为"pending"。
0:不等待,即刻返回;
portMAX_DELAY:一直等待,直到通知状态变为"pending";
其他值:Tick Count,可以用 pdMS_TO_TICKS() 把ms转换为Tick Count
返回值1. pdPASS:成功
这表示xTaskNotifyWait成功获得了通知:
可能是调用函数之前,通知状态就是"pending";
也可能是在阻塞期间,通知状态变为了"pending"。
2. pdFAIL:没有得到通知。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1348592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++初阶——权限与继承

目录 一、C权限方面的问题 1.访问权限 2.继承机制 二、Cconst引用 const引用有以下几个特点 临时对象引用 常量引用成员变量 二、c引用空间相关问题 三.auto 一、C权限方面的问题 【C入门】访问权限管控和继承机制详解_权限继承功能-CSDN博客文章浏览阅读840次。(2)但…

C#中string.ToUpper()和string.ToLower()的用法

目录 一、关于ToUpper()和ToLower() 1.ToUpper() 2.ToLower() 3.小结 二、实例 三、生成效果 一、关于ToUpper()和ToLower() 1.ToUpper() 使用字符串对象的ToUpper方法可以将字符串中的字母全部转换为大写。 string P_str_book "mingribook".ToUpper()…

简单Diff算法

简单Diff算法 渲染器的核心 Diff算法 解决的问题 比较新旧虚拟节点的子节点,实现最小化更新。 虚拟节点key属性的作用 就像虚拟节点的“身份证号”,在更新时,渲染器会通过key属性找到可复用的节点,然后尽可能地通过DOM移动操…

Spring Boot Admin健康检查引起的Spring Boot服务假死

问题现象 最近在spring boot项目中引入了 spring-boot-starter-actuator 后,测试环境开始出现服务假死的现象, 且这个问题十分怪异,只在多个微服务中的简称A的这个服务中出现,其他服务都没有出现这个问题, 之所以说…

Proxmox Backup Server(PBS)从2.X升级到PBS3

作者:田逸(formyz) 2023年11月31日,Proxmox 官方正式发布Proxmox Backup Server 3.1版本。现在我负责管理的Proxmox Backup Server(以下简称PBS)版本号为2.3,打算将部分PBS升级到PBS 3.1&#x…

微信小程序自定义步骤条效果

微信小程序自定义一个步骤条组件,自定义文字在下面,已完成和未完成和当前进度都不一样的样式,可点击上一步和下一步切换流程状态,效果如下。 这是视频效果: 前端实现步骤条效果 下面我们一步步实现编码,自定…

【拆盲盒02】算法题

题目 : 假设顺序表L中的元素按从小到大的次序排列,编写算法删除顺序表中“多余”的数据元素,即操作之后的顺序表中所有元素的值都不相同,要求时间尽可能的少;并对顺序表A(1,1,2,2&am…

【js】js解析Token:

一、效果: 二、实现: export function getTokenObject(token) {//通过split()方法将token转为字符串数组,数组中的第二个字符进行解析return token ? JSON.parse(decodeURIComponent(escape(window.atob(token.split(".")[1].replace(/-/g &…

在 Spring 中操作 Redis

🧸欢迎来到dream_ready的博客,📜相信您对博主首页也很感兴趣o (ˉ▽ˉ;) 📜redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿 目录 1、引入依赖 2、对 Redis 的配置文件进行书写 3、S…

2022年中职组“网络安全”赛项湖南省B-3——私钥泄漏

B-3:应用服务漏洞扫描与利用 任务环境说明:需要环境有问题可以加q 服务器场景:Server15服务器场景操作系统:未知(关闭链接) 使用命令nmap探测目标靶机的服务版本信息,将需要使用的参数作为FLA…

UIToolKit使用心得

起因 因为那个uitoolkit自己写了一套graphView,所以想着来用用但是用完之后发现也不过如此 怎么构建自己的组件 我在继承Node之后想修改node的样式该怎么办呢是这样的。先用pick点击默认的node节点元素- 在pick默认创建的node节点之后,可以把它的uxml…

【产品设计】信息建设三驾马车:PLM系统拆解

本篇文章将介绍PLM的基础信息、发展及模块功能等内容,让大家对PLM有一个全面、完整地了解,方便在后期的工作中能快速地使用其解决方案,希望本篇文章能对你有所帮助。 PLM系统主要实现产品模块业务,既包含产品的创意设计、样品打样…

阶段十-分布式-docker虚拟化容器

第一章 Docker简介 1.2 节 Docker理念 Docker是基于Go语言实现的云开源项目;通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装&#xf…

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(18)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(17) 1.4 PCI总线的中断机制 1.4.2 中断信号与PCI总线的连接关系 在PCI总线中,INTx信号属于边带信号。所谓边带信号是指这些信号在PCI总线环境…

错题总结五

一. 操作访问字节个数问题 这道题考察的是指针有关的知识,而这种指针的知识我们提到过 指针相关知识(入门)-CSDN博客 指针相关知识(进阶)-CSDN博客 在这里,我们复习一下。在指针里,int有4个字节,short有2个字节,换句…

jsp作用域

jsp四大域对象 page 只在当前页面有效,跳转后无效 request 服务器跳转有效,客户端发生跳转无效,(因为客户端跳转,相当于发生两次跳转) session 保存在浏览器会话中,服务器或客户端跳转均有…

Spring系列:Spring如何解决循环依赖

❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得关注、点赞、收藏、…

【ChatGPT 默认强化学习策略】PPO 近端策略优化算法

PPO 近端策略优化算法 PPO 概率比率裁剪 演员-评论家算法演员-评论家算法:多智能体强化学习核心框架概率比率裁剪:逐步进行变化的方法PPO 目标函数的设计重要性采样KL散度 PPO 概率比率裁剪 演员-评论家算法 论文链接:https://arxiv.org…

万字长文谈自动驾驶occupancy感知

文章目录 prologuepaper listVision-based occupancy :1. [MonoScene: Monocular 3D Semantic Scene Completion [CVPR 2022]](https://arxiv.org/pdf/2112.00726.pdf)2. [Tri-Perspective View for Vision-Based 3D Semantic Occupancy Prediction [CVPR 2023]](https://arxiv…

Android--Jetpack--Paging详解

不尝世间醋与墨,怎知人间酸与苦。 择一业谋食养命,等一运扭转乾坤。 你见过哪些令你膛目结舌的代码技巧? 文章目录 不尝世间醋与墨,怎知人间酸与苦。择一业谋食养命,等一运扭转乾坤。你见过哪些令你膛目结舌的代码技…