FreeRTOS 第十一章 通知

从v8.2.0版本开始,FreeRTOS新增了任务通知(Task Notification)功能。可以使用任务通知拉代替信号量、消息队列、事件标志等。使用任务通知效率会高些。

任务通知是一个可选的功能,FreeRTOS的每个任务都有一个32位的通知值。任务控制块的成员变量ulBotifiedValue就是这个值。任务通知是一个事件,假设某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知值可以通过以下方法更新接收任务的通知值。

  • 不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没有被处理)
  • 覆盖接收任务的通知值。
  • 更新接收任务通知值的一个或者多个bit。
  • 增加接收任务的通知值。

任务通知的发送使用函数xTaskNotify()或者xTaskNotifyGive()来完成,这个通知值会一直保存着。直到接收任务调用函数xTaskNotifyWait()或者ulTaskNotifyTake()来获取这个值。

任务通知虽然可以提供速度,并且减少RAM的使用,但是任务通知也是有使用限制的:

1、任务通知只能有一个接收任务。

2、接收任务可以因为接收任务通知而进入阻塞状态,但是发送任务不会因为任务通知发送失败而阻塞。

发送通知

xTaskNotify():发送通知,带有通知值并且不会保留接收任务的通知值。

xTaskNotifyGive():发送通知,不带通知值并且不保留接收任务的通知值,此函数会在接收任务的通知值加一。

xTaskNotifyAndQuery():发送通知,带有通知值并且保留接收任务的通知值。

xTaskNotify:

#define xTaskNotify( xTaskToNotify, ulValue, eAction ) \xTaskGenericNotify( ( xTaskToNotify ), ( tskDEFAULT_INDEX_TO_NOTIFY ), ( ulValue ), ( eAction ), NULL )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, //要通知的任务句柄UBaseType_t uxIndexToNotify, //task支持多个通知,默认使用index0uint32_t ulValue, //通知值eNotifyAction eAction, //通知的类型uint32_t * pulPreviousNotificationValue ) //先前的通知值{TCB_t * pxTCB;BaseType_t xReturn = pdPASS;uint8_t ucOriginalNotifyState;traceENTER_xTaskGenericNotify( xTaskToNotify, uxIndexToNotify, ulValue, eAction, pulPreviousNotificationValue );configASSERT( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES );configASSERT( xTaskToNotify );//任务句柄就是任务pcb。pxTCB = xTaskToNotify;taskENTER_CRITICAL();{if( pulPreviousNotificationValue != NULL )//如果先前值指针不为NULL,就将先前值赋值指针,供返回使用。{*pulPreviousNotificationValue = pxTCB->ulNotifiedValue[ uxIndexToNotify ];}//获取任务通知状态。ucOriginalNotifyState = pxTCB->ucNotifyState[ uxIndexToNotify ];//新的状态位接收pxTCB->ucNotifyState[ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED;//任务通知的动作类型switch( eAction ){case eSetBits://或上以前的值pxTCB->ulNotifiedValue[ uxIndexToNotify ] |= ulValue;break;case eIncrement://以前的通知值加1( pxTCB->ulNotifiedValue[ uxIndexToNotify ] )++;break;case eSetValueWithOverwrite://重写以前的通知值pxTCB->ulNotifiedValue[ uxIndexToNotify ] = ulValue;break;case eSetValueWithoutOverwrite://不覆盖的方式写通知值。if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )//如果以前的状态不是接收,那么就将通知值,直接覆盖。{pxTCB->ulNotifiedValue[ uxIndexToNotify ] = ulValue;}else{//如果已经是接收状态了,说明不能重写通知值。因此什么都不做/* The value could not be written to the task. */xReturn = pdFAIL;}break;case eNoAction://通知任务,不更新通知值/* The task is being notified without its notify value being* updated. */break;default:/* Should not get here if all enums are handled.* Artificially force an assert by testing a value the* compiler can't assume is const. */configASSERT( xTickCount == ( TickType_t ) 0 );break;}traceTASK_NOTIFY( uxIndexToNotify );/* If the task is in the blocked state specifically to wait for a* notification then unblock it now. *///如果task以前的状态是等待通知阻塞if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ){listREMOVE_ITEM( &( pxTCB->xStateListItem ) );//将任务添加到就绪列表prvAddTaskToReadyList( pxTCB );/* The task should not have been on an event list. *///task现在没有因为事件而阻塞configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );#if ( configUSE_TICKLESS_IDLE != 0 ){/* If a task is blocked waiting for a notification then* xNextTaskUnblockTime might be set to the blocked task's time* out time.  If the task is unblocked for a reason other than* a timeout xNextTaskUnblockTime is normally left unchanged,* because it will automatically get reset to a new value when* the tick count equals xNextTaskUnblockTime.  However if* tickless idling is used it might be more important to enter* sleep mode at the earliest possible time - so reset* xNextTaskUnblockTime here to ensure it is updated at the* earliest possible time. */prvResetNextTaskUnblockTime();}#endif/* Check if the notified task has a priority above the currently* executing task. *///如果解除阻塞态的任务优先级比当前任务优先级高,就执行一次任务切换。taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxTCB );}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();traceRETURN_xTaskGenericNotify( xReturn );return xReturn;}

xTaskNotifyGive()其实没有什么特别之后,也是调用xTaskGenericNotify()只不过参数传递的不一样而已。 eIncrement表示只通知任务,不改变通知值。

#define xTaskNotifyGive( xTaskToNotify ) \xTaskGenericNotify( ( xTaskToNotify ), ( tskDEFAULT_INDEX_TO_NOTIFY ), ( 0 ), eIncrement, NULL )

获取通知

xTaskNotifyTake():获取任务通知,可以设置在退出此函数的时候将任务通知值清0或者减1.当任务通知用作二值信号量的时候使用此函数来获取信号量。

xTaskNotifyWait():等待任务通知,功能更强大。

#define ulTaskNotifyTake( xClearCountOnExit, xTicksToWait ) \ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ), ( xClearCountOnExit ), ( xTicksToWait ) )
uint32_t ulTaskGenericNotifyTake( UBaseType_t uxIndexToWaitOn, //index索引值BaseType_t xClearCountOnExit, //返回的时候是否清通知值TickType_t xTicksToWait )//最大等到时间{uint32_t ulReturn;BaseType_t xAlreadyYielded;traceENTER_ulTaskGenericNotifyTake( uxIndexToWaitOn, xClearCountOnExit, xTicksToWait );configASSERT( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );taskENTER_CRITICAL();/* Only block if the notification count is not already non-zero. */if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] == 0UL )//如果没有通知值{/* Mark this task as waiting for a notification. *///将task状态设置成等待状态pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION;//最大等待时间if( xTicksToWait > ( TickType_t ) 0 ){traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWaitOn );/* We MUST suspend the scheduler before exiting the critical* section (i.e. before enabling interrupts).** If we do not do so, a notification sent from an ISR, which* happens after exiting the critical section and before* suspending the scheduler, will get lost. The sequence of* events will be:* 1. Exit critical section.* 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the*    task to the Ready list.* 3. Suspend scheduler.* 4. prvAddCurrentTaskToDelayedList moves the task to the*    delayed or suspended list.* 5. Resume scheduler does not touch the task (because it is*    not on the pendingReady list), effectively losing the*    notification from the ISR.** The same does not happen when we suspend the scheduler before* exiting the critical section. The sequence of events in this* case will be:* 1. Suspend scheduler.* 2. Exit critical section.* 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the*    task to the pendingReady list as the scheduler is*    suspended.* 4. prvAddCurrentTaskToDelayedList adds the task to delayed or*    suspended list. Note that this operation does not nullify*    the add to pendingReady list done in the above step because*    a different list item, namely xEventListItem, is used for*    adding the task to the pendingReady list. In other words,*    the task still remains on the pendingReady list.* 5. Resume scheduler moves the task from pendingReady list to*    the Ready list.*/vTaskSuspendAll();{taskEXIT_CRITICAL();//将task放到延时列表里。prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );}xAlreadyYielded = xTaskResumeAll();if( xAlreadyYielded == pdFALSE )//是否需要调度一次{taskYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}else{taskEXIT_CRITICAL();}}else{taskEXIT_CRITICAL();}taskENTER_CRITICAL();{traceTASK_NOTIFY_TAKE( uxIndexToWaitOn );//任务得到运行,可能是超时时间到了,也可能是收到了通知ulReturn = pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ];if( ulReturn != 0UL )//收到了通知{if( xClearCountOnExit != pdFALSE )//离开后清掉通知{pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] = 0UL;}else{    //通知值减1.pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] = ulReturn - ( uint32_t ) 1;}}else{mtCOVERAGE_TEST_MARKER();}//任务状态设置为等待状体pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskNOT_WAITING_NOTIFICATION;}taskEXIT_CRITICAL();traceRETURN_ulTaskGenericNotifyTake( ulReturn );return ulReturn;}

xTaskNotifyWait()流程和xTaskNotifyTake()基本一样,就是多了一些功能:比如进入函数就可以清掉标记位,可以返回上一次的通知值。

BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t * pulNotificationValue,TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
#define xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ) \xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY, ( ulBitsToClearOnEntry ), ( ulBitsToClearOnExit ), ( pulNotificationValue ), ( xTicksToWait ) )

 

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

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

相关文章

图的表示(利用边结构描述的图来构建图结构)

#include<iostream> #include<vector> #include<map> #include<set> using namespace std;//边结构的描述 class Edge { public://边的起始节点Node from;//边的终点节点Node to;//边的权重int weight; public:Edge(Node from, Node to, int weight){t…

52岁「豹嫂」代夫尽孝送花畀奶奶被赞

歌手胡蓓蔚与「豹哥」单立文相爱28年&#xff0c;两人曾上节目分享婚姻之道&#xff0c;指婚姻最紧要有忍耐力&#xff0c;要抗拒引诱。其实除了忍耐力&#xff0c;胡蓓蔚和奶奶相处都有一套。 早前单立文带胡蓓蔚及妈妈到米芝连一星餐厅叹美食&#xff0c;庆祝奶奶89岁生日&am…

macOS Sonoma 14.5(23F79)发布

系统介绍 黑果魏叔5 月 14 日快报&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14.5 正式版更新&#xff08;内部版本号&#xff1a;23F79 同 RC&#xff09;。这是去年 9 月发布的 macOS Sonoma 操作系统的第五次更新&#xff0c;距离上一次的 macOS Sonoma 14.4 更新已…

Mysql 隔离级别

MySQL的事务隔离级别是指在处理并发事务时&#xff0c;为保证数据的一致性和事务的独立性&#xff0c;数据库系统提供的不同级别控制策略。根据ACID特性中的隔离性&#xff08;Isolation&#xff09;&#xff0c;MySQL支持四种标准的事务隔离级别&#xff0c;每种级别有不同的并…

RustGUI学习(iced)之小部件(十):如何使用tooltip部件来制作文字提示?

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述 这是本专栏的第十篇,主要讲述tooltip部件的使用,会结合实例来…

osdoc开源文档(最好用的手册地址,包括 Markdown 等手册)

文章目录 osdoc开源文档&#xff08;最好用的手册地址&#xff0c;包括 Markdown 等手册&#xff09;前言地址Markdown 手册地址 osdoc开源文档&#xff08;最好用的手册地址&#xff0c;包括 Markdown 等手册&#xff09; 前言 最近在看md手册&#xff0c;无意间发现这个网站…

如果你要开发一个中小学生学习数学的软件,你应该找谁去做用户调研?

&#xff08;学校作业&#xff09; 1、学生家长&#xff1a;学生家长是最清楚学生的一个群体之一&#xff0c;他们也是这个软件的潜在使用者。软件设计时可能会考虑到家长监督学生的学习情况来设计其中的功能。 2、教师&#xff1a;教师最清楚学生的学习习惯、思维方式&#xf…

AcWing166. 数独-DFS剪枝与优化

题目 思路 思考问题&#xff1a;搜索顺序->考虑剪枝搜索顺序&#xff1a;先随意选择一个空格子&#xff0c;枚举该格子可填写的数字&#xff0c;当所有格子都填完的时候&#xff0c;说明可以退出了剪枝&#xff1a; 优化搜索顺序&#xff1a;随意选择一个空格子&#xff1a…

今日总结2024.5.14

今日复习了分组背包的用法 P1064 [NOIP2006 提高组] 金明的预算方案 题目描述 金明今天很开心&#xff0c;家里购置的新房就要领钥匙了&#xff0c;新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是&#xff0c;妈妈昨天对他说&#xff1a;“你的房间需要购买哪些物…

机器学习-12-sklearn案例02-集成学习

总结 参考 菜菜的sklearn课堂——随机森林 傻子都能看懂的——详解AdaBoost原理 算法使用过程 #导入数据集模块 from sklearn import datasets #分别加载iris和digits数据集 iris datasets.load_iris() #鸢尾花数据集 # print(dir(datasets)) # print(iris_dataset.keys…

76岁林子祥升级做爷爷,亲自为孙女取名

林子祥与前妻吴正元的儿子&#xff0c;现年39岁的林德信入行以来绯闻不少&#xff0c;自与圈外女友Candace拍拖后便修心养性&#xff0c;去年他已经低调与拍拖5年多Candace完婚&#xff0c;正式步入人生另一阶段。 昨日&#xff08;5月12日&#xff09;林德信借母亲节这个温馨日…

C++ 并发编程指南(11)原子操作 | 11.4、通过内存序实现顺序模型

文章目录 一、通过内存序实现顺序模型1、Relaxed Ordering2、Sequencial Consistent Ordering3、Acquire Release Ordering 前言 前文介绍了六种内存顺序&#xff0c;以及三种内存模型&#xff0c;本文通过代码示例讲解六种内存顺序使用方法&#xff0c;并实现相应的内存模型。…

【MySQL数据库开发设计规范】之索引设计规范

欢迎点开这篇文章&#xff0c;自我介绍一下哈&#xff0c;本人姑苏老陈 &#xff0c;是一名JAVA开发老兵。 本文收录于 《MySQL数据库开发设计规范》专栏中&#xff0c;该专栏主要分享一些关于MySQL数据库开发设计相关的技术规范文章&#xff0c;定期更新&#xff0c;欢迎关注&…

【综述】人工智能、机器学习、深度学习

文章目录 前言 概念 算法 训练 性能 应用 参考资料 前言 见《初试人工智能》 概念 人工智能系统&#xff08;artifieial intelligence system&#xff09;&#xff0c;针对人类定义的给定目标&#xff0c;产生诸如内容、预测、推荐或决策等输出的一类工程系统。该工程系…

【C++】string|迭代器iterator|getline|find

目录 ​编辑 string 1.string与char* 的区别 2.string的使用 字符串遍历 利用迭代器遍历 范围for遍历 反向迭代器 字符串capacity 字符串插入操作 push_back函数 append函数 运算符 ​编辑 insert函数 substr函数 字符串查找函数 find函数 rfind函数 …

Go 处理错误

如果你习惯了 try catch 这样的语法后&#xff0c;会觉得处理错误真简单&#xff0c;然后你再来接触 Go 的错误异常&#xff0c;你会发现他好复杂啊&#xff0c;怎么到处都是 error&#xff0c;到处都需要处理 error。 首先咱们需要知道 Go 语言里面有个约定&#xff0c;就是一…

灵活的静态存储控制器 (FSMC)的介绍(STM32F4)

目录 概述 1 认识FSMC 1.1 应用介绍 1.2 FSMC的主要功能 1.2.1 FSMC用途 1.2.2 FSMC的功能 2 FSMC的框架结构 2.1 AHB 接口 2.1.1 AHB 接口的Fault 2.1.2 支持的存储器和事务 2.2 外部器件地址映射 3 地址映射 3.1 NOR/PSRAM地址映射 3.2 NAND/PC卡地址映射 概述…

GPT搜索鸽了!改升级GPT-4

最近OpenAI太反常&#xff0c;消息一会一变&#xff0c;直让人摸不着头脑。 奥特曼最新宣布&#xff1a;5月13日开发布会&#xff0c;不是GPT-5&#xff0c;也不是盛传的GPT搜索引擎&#xff0c;改成对ChatGP和GPT-4的升级&#xff5e; 消息一出&#xff0c;大伙儿都蒙了。 之…

运维别卷系列 - 云原生监控平台 之 02.prometheus exporter 实践

文章目录 [toc]exporter 简介常用的 exporternode-exporter 实践创建 svc创建 daemonsetprometheus 配置服务发现 exporter 简介 随着 Prometheus 的流行&#xff0c;很多系统都已经自带了用于 Prometheus 监控的接口&#xff0c;例如 etcd、Kubernetes、CoreDNS 等&#xff0c…

PuLID: 图像背景、光线、风格等均保持高度一致图像生成工具,附本地一键包

PuLID是一种无需调优的ID定制方法。PuLID保持了高的ID保真度&#xff0c;同时有效地减少了对原始模型行为的干扰。 只需要提供一张照片&#xff0c;就可以生成高还原度的各种风格的图像。 使用方法&#xff1a;解压一键包&#xff0c;双击一键启动 点击ID图像&#xff08;主…