(学习日记)2024.03.15:UCOSIII第十七节:任务的挂起和恢复

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.03.15

  • 三十一、UCOSIII:任务的挂起和恢复
    • 1、实现任务的挂起和恢复
      • 1. 定义任务的状态
      • 2. 修改任务控制块TCB
      • 3. 编写任务挂起和恢复函数
        • - OSTaskSuspend()函数
        • - OSTaskResume()函数
    • 2、main()函数
    • 3、实验现象

三十一、UCOSIII:任务的挂起和恢复

本章开始,我们让OS的任务支持挂起和恢复的功能,挂起就相当于暂停,暂停后任务从就绪列表中移除, 恢复即重新将任务插入就绪列表。
一个任务挂起多少次就要被恢复多少次才能重新运行。

1、实现任务的挂起和恢复

1. 定义任务的状态

在任务实现挂起和恢复的时候,要根据任务的状态来操作,任务的状态不同,操作也不同。
有关任务状态的宏定义在os.h中实现, 总共有9种状态

/* ---------- 任务的状态 -------*/
#define  OS_TASK_STATE_BIT_DLY               (OS_STATE)(0x01u)/*   /-------- 挂起位          */#define  OS_TASK_STATE_BIT_PEND              (OS_STATE)(0x02u)/*   | /-----  等待位          */#define  OS_TASK_STATE_BIT_SUSPENDED         (OS_STATE)(0x04u)/*   | | /---  延时/超时位      */#define  OS_TASK_STATE_RDY                    (OS_STATE)(  0u)/*   0 0 0  就绪               */
#define  OS_TASK_STATE_DLY                    (OS_STATE)(  1u)/*   0 0 1  延时或者超时        */
#define  OS_TASK_STATE_PEND                   (OS_STATE)(  2u)/*   0 1 0  等待               */
#define  OS_TASK_STATE_PEND_TIMEOUT           (OS_STATE)(  3u)/*   0 1 1  等待+超时*/
#define  OS_TASK_STATE_SUSPENDED              (OS_STATE)(  4u)/*   1 0 0  挂起               */
#define  OS_TASK_STATE_DLY_SUSPENDED          (OS_STATE)(  5u)/*   1 0 1  挂起 + 延时或者超时*/
#define  OS_TASK_STATE_PEND_SUSPENDED         (OS_STATE)(  6u)/*   1 1 0  挂起 + 等待         */
#define  OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED (OS_STATE)(  7u)/*   1 1 1  挂起 + 等待 + 超时*/
#define  OS_TASK_STATE_DEL                    (OS_STATE)(255u)

2. 修改任务控制块TCB

为了实现任务的挂起和恢复,需要先在任务控制中TCB中添加任务的状态TaskState和任务挂起计数器SusPendCtr这两个成员

struct os_tcb {CPU_STK         *StkPtr;CPU_STK_SIZE    StkSize;/* 任务延时周期个数 */OS_TICK         TaskDelayTicks;/* 任务优先级 */OS_PRIO         Prio;/* 就绪列表双向链表的下一个指针 */OS_TCB          *NextPtr;/* 就绪列表双向链表的前一个指针 */OS_TCB          *PrevPtr;/*时基列表相关字段*/OS_TCB          *TickNextPtr;OS_TCB          *TickPrevPtr;OS_TICK_SPOKE   *TickSpokePtr;OS_TICK         TickCtrMatch;OS_TICK         TickRemain;/* 时间片相关字段 */OS_TICK              TimeQuanta;OS_TICK              TimeQuantaCtr;OS_STATE             TaskState;		//(1)#if OS_CFG_TASK_SUSPEND_EN > 0u		//(2)/* 任务挂起函数OSTaskSuspend()计数器 */OS_NESTING_CTR       SuspendCtr;		//(3)
#endif};
  • (1):TaskState用来表示任务的状态,在本章之前,任务出现了两种状态,一是任务刚刚创建好的时候, 处于就绪态,调用阻塞延时函数的时候处于延时态。本章要实现的是任务的挂起态,再往后的章节中还会有等待态,超时态, 删除态等。
  • (2):任务挂起功能是可选的,通过宏OS_CFG_TASK_SUSPEND_EN来控制,该宏在os_cfg.h文件中定义。
  • (3):任务挂起计数器,任务每被挂起一次,SuspendCtr递增一次,一个任务挂起多少次就要被恢复多少次才能重新运行。

3. 编写任务挂起和恢复函数

- OSTaskSuspend()函数
#if OS_CFG_TASK_SUSPEND_EN > 0u
void   OSTaskSuspend (OS_TCB  *p_tcb,OS_ERR  *p_err)
{CPU_SR_ALLOC();#if 0/* 屏蔽开始 */    			//(1)#ifdef OS_SAFETY_CRITICAL/* 安全检查,OS_SAFETY_CRITICAL_EXCEPTION()函数需要用户自行编写 */if (p_err == (OS_ERR *)0){OS_SAFETY_CRITICAL_EXCEPTION();return;}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u/* 不能在ISR程序中调用该函数 */if (OSIntNestingCtr > (OS_NESTING_CTR)0){*p_err = OS_ERR_TASK_SUSPEND_ISR;return;}
#endif/* 不能挂起空闲任务 */if (p_tcb == &OSIdleTaskTCB){*p_err = OS_ERR_TASK_SUSPEND_IDLE;return;}#if OS_CFG_ISR_POST_DEFERRED_EN > 0u/* 不能挂起中断处理任务 */if (p_tcb == &OSIntQTaskTCB){*p_err = OS_ERR_TASK_SUSPEND_INT_HANDLER;return;}
#endif#endif/* 屏蔽结束 */  		//(2)CPU_CRITICAL_ENTER();/* 是否挂起自己 */    		//(3)if (p_tcb == (OS_TCB *)0) {p_tcb = OSTCBCurPtr;}if (p_tcb == OSTCBCurPtr) {/* 如果调度器锁住则不能挂起自己 */if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {CPU_CRITICAL_EXIT();*p_err = OS_ERR_SCHED_LOCKED;return;}}*p_err = OS_ERR_NONE;/* 根据任务的状态来决定挂起的动作 */		//(4)switch (p_tcb->TaskState){case OS_TASK_STATE_RDY:		//(5)OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();p_tcb->TaskState  =  OS_TASK_STATE_SUSPENDED;p_tcb->SuspendCtr = (OS_NESTING_CTR)1;OS_RdyListRemove(p_tcb);OS_CRITICAL_EXIT_NO_SCHED();break;case OS_TASK_STATE_DLY:		//(6)p_tcb->TaskState  = OS_TASK_STATE_DLY_SUSPENDED;p_tcb->SuspendCtr = (OS_NESTING_CTR)1;CPU_CRITICAL_EXIT();break;case OS_TASK_STATE_PEND:		//(7)p_tcb->TaskState  = OS_TASK_STATE_PEND_SUSPENDED;p_tcb->SuspendCtr = (OS_NESTING_CTR)1;CPU_CRITICAL_EXIT();break;case OS_TASK_STATE_PEND_TIMEOUT:		//(8)p_tcb->TaskState  = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;p_tcb->SuspendCtr = (OS_NESTING_CTR)1;CPU_CRITICAL_EXIT();break;case OS_TASK_STATE_SUSPENDED:		//(9)case OS_TASK_STATE_DLY_SUSPENDED:case OS_TASK_STATE_PEND_SUSPENDED:case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:p_tcb->SuspendCtr++;CPU_CRITICAL_EXIT();break;default:		//(10)CPU_CRITICAL_EXIT();*p_err = OS_ERR_STATE_INVALID;return;}/* 任务切换 */OSSched();		//(11)
}
#endif
  • (1)和(2):这部分代码是为了程序的健壮性写的代码,即是加了各种判断, 避免用户的误操作。在μC/OS-III中,这段代码随处可见,但为了讲解方便,我们把这部分代码注释掉, 里面涉及的一些宏和函数我们均不实现,只需要了解即可,在后面的讲解中,要是出现这段代码, 我们直接删除掉,删除掉也不会影响核心功能。
  • (3):如果任务挂起的是自己,则判断下调度器是否锁住,如果锁住则退出返回错误码,没有锁则继续往下执行。
  • (4):根据任务的状态来决定挂起操作。
  • (5):任务在就绪状态,则将任务的状态改为挂起态,挂起计数器置1,然后从就绪列表删除。
  • (6):任务在延时状态,则将任务的状态改为延时加挂起态,挂起计数器置1,不用改变TCB的位置,即还是在延时的时基列表。
  • (7):任务在等待状态,则将任务的状态改为等待加挂起态,挂起计数器置1,不用改变TCB的位置,即还是在等待列表等待。 等待列表暂时还没有实现,将会在后面的章节实现。
  • (8):任务在等待加超时态, 则将任务的状态改为等待加超时加挂起态,挂起计数器置1,不用改变TCB的位置,即还在等待和时基这两个列表中。
  • (9):只要有一个是挂起状态,则将挂起计数器加一操作,不用改变TCB的位置。
  • (10):其他状态则无效,退出返回状态无效错误码。
  • (11):任务切换。凡是涉及改变任务状态的地方,都需要进行任务切换。
- OSTaskResume()函数

OSTaskResume()函数用于恢复被挂起的函数,但是不能恢复自己,挂起倒是可以挂起自己

#if OS_CFG_TASK_SUSPEND_EN > 0u
void  OSTaskResume (OS_TCB  *p_tcb,OS_ERR  *p_err)
{CPU_SR_ALLOC();#if 0/* 屏蔽开始 */			//(1)#ifdef OS_SAFETY_CRITICAL/* 安全检查,OS_SAFETY_CRITICAL_EXCEPTION()函数需要用户自行编写 */if (p_err == (OS_ERR *)0) {OS_SAFETY_CRITICAL_EXCEPTION();return;}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u/* 不能在ISR程序中调用该函数 */if (OSIntNestingCtr > (OS_NESTING_CTR)0) {*p_err = OS_ERR_TASK_RESUME_ISR;return;}
#endifCPU_CRITICAL_ENTER();
#if OS_CFG_ARG_CHK_EN > 0u/* 不能自己恢复自己 */if ((p_tcb == (OS_TCB *)0) ||(p_tcb == OSTCBCurPtr)) {CPU_CRITICAL_EXIT();*p_err = OS_ERR_TASK_RESUME_SELF;return;}
#endif#endif/* 屏蔽结束 */			//(2)*p_err  = OS_ERR_NONE;/* 根据任务的状态来决定挂起的动作 */switch (p_tcb->TaskState) {			//(3)case OS_TASK_STATE_RDY:			//(4)case OS_TASK_STATE_DLY:case OS_TASK_STATE_PEND:case OS_TASK_STATE_PEND_TIMEOUT:CPU_CRITICAL_EXIT();*p_err = OS_ERR_TASK_NOT_SUSPENDED;break;case OS_TASK_STATE_SUSPENDED:			//(5)OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();p_tcb->SuspendCtr--;if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {p_tcb->TaskState = OS_TASK_STATE_RDY;OS_TaskRdy(p_tcb);}OS_CRITICAL_EXIT_NO_SCHED();break;case OS_TASK_STATE_DLY_SUSPENDED:			//(6)p_tcb->SuspendCtr--;if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {p_tcb->TaskState = OS_TASK_STATE_DLY;}CPU_CRITICAL_EXIT();break;case OS_TASK_STATE_PEND_SUSPENDED:			//(7)p_tcb->SuspendCtr--;if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {p_tcb->TaskState = OS_TASK_STATE_PEND;}CPU_CRITICAL_EXIT();break;case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:			//(8)p_tcb->SuspendCtr--;if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;}CPU_CRITICAL_EXIT();break;default:			//(9)CPU_CRITICAL_EXIT();*p_err = OS_ERR_STATE_INVALID;return;}/* 任务切换 */OSSched();			//(10)
}
#endif
  • (1)和(2):这部分代码是为了程序的健壮性写的代码,即是加了各种判断,避免用户的误操作。 在μC/OS-III中,这段代码随处可见,但为了讲解方便,我们把这部分代码注释掉,里面涉及的一些宏和函数我们均不实现, 只需要了解即可,在后面的讲解中,要是出现这段代码,我们直接删除掉,删除掉也不会影响核心功能。
  • (3):根据任务的状态来决定恢复操作。
  • (4):只要任务没有被挂起,则退出返回任务没有被挂起的错误码。
  • (5):任务只在挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为就绪态,并让任务就绪。
  • (6):任务在延时加挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为延时态。
  • (7):任务在等待加挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为等待态。
  • (8):任务在等待加超时加挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为等待加超时态
  • (9):其他状态则无效,退出返回状态无效错误码。
  • (10):任务切换。凡是涉及改变任务状态的地方,都需要进行任务切换。

2、main()函数

这里,我们创建任务1、2和3,其中任务的优先级为1,任务2的优先级为2,任务3的优先级为3。
任务1将自身的flag每翻转一次后均将自己挂起, 任务2在经过两个时钟周期后将任务1恢复,任务3每隔一个时钟周期翻转一次。

int main(void)
{OS_ERR err;/* CPU初始化:1、初始化时间戳 */CPU_Init();/* 关闭中断 */CPU_IntDis();/* 配置SysTick 10ms 中断一次 */OS_CPU_SysTickInit (10);/* 初始化相关的全局变量 */OSInit(&err);/* 创建任务 */OSTaskCreate( (OS_TCB       *)&Task1TCB,(OS_TASK_PTR   )Task1,(void         *)0,(OS_PRIO       )1,(CPU_STK      *)&Task1Stk[0],(CPU_STK_SIZE  )TASK1_STK_SIZE,(OS_TICK       )0,(OS_ERR       *)&err );OSTaskCreate( (OS_TCB       *)&Task2TCB,(OS_TASK_PTR   )Task2,(void         *)0,(OS_PRIO       )2,(CPU_STK      *)&Task2Stk[0],(CPU_STK_SIZE  )TASK2_STK_SIZE,(OS_TICK       )0,(OS_ERR       *)&err );OSTaskCreate( (OS_TCB       *)&Task3TCB,(OS_TASK_PTR   )Task3,(void         *)0,(OS_PRIO       )3,(CPU_STK      *)&Task3Stk[0],(CPU_STK_SIZE  )TASK3_STK_SIZE,(OS_TICK       )0,(OS_ERR       *)&err );/* 启动OS,将不再返回 */OSStart(&err);
}void Task1( void *p_arg )
{OS_ERR err;for ( ;; ) {flag1 = 1;OSTaskSuspend(&Task1TCB,&err);flag1 = 0;OSTaskSuspend(&Task1TCB,&err);}
}void Task2( void *p_arg )
{OS_ERR err;for ( ;; ) {flag2 = 1;OSTimeDly(1);//OSTaskResume(&Task1TCB,&err);flag2 = 0;OSTimeDly(1);;OSTaskResume(&Task1TCB,&err);}
}void Task3( void *p_arg )
{for ( ;; ) {flag3 = 1;OSTimeDly(1);flag3 = 0;OSTimeDly(1);}
}

3、实验现象

进入软件调试,单击全速运行按钮就可看到实验波形,具体见图
在这里插入图片描述
可以看到任务2和任务3的波形图是一样的, 任务1的波形周期是任务2的两倍,与代码实现相符。如果想实现其他效果可自行修改代码实现。

其中,任务二与任务三是靠任务阻塞来完成延时的,只与系统时钟相关。
而任务一每次翻转都会将自己挂起,必须靠任务二将自己恢复才能继续运行。

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

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

相关文章

virtualBox镜像复制

镜像复制 有一个镜像后,图方便,想直接使用这个vdi文件,但vdi有个uuid值,同一个虚拟机中不能同时存在两个同样的uuid的介质的,普通的复制文件所得到的uuid是一样的 ,所以需要用到自带的方法复制vdi文件&…

记录无线通信网站

https://www.rfwireless-world.com/ 包含许多无线知识的一个网站 包含了以上无线通讯协议 2.https://csa-iot.org/https://csa-iot.org/2.https://csa-iot.org/ connectivity standards alliance CSA-IOT 官网 推出的协议有: 如果想查找已认证CSA某种协议的产品…

如何在Ubuntu系统搭建Excalidraw容器并实现公网访问本地绘制流程图

文章目录 1. 安装Docker2. 使用Docker拉取Excalidraw镜像3. 创建并启动Excalidraw容器4. 本地连接测试5. 公网远程访问本地Excalidraw5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Ubuntu系统使用Docker部署开源白板工具Excal…

JavaSE、JavaEE和Jakarta EE的历史、区别与联系

JavaSE、JavaEE和Jakarta EE是Java平台中的三个重要组成部分,它们各自承担着不同的角色,同时也有着密切的联系。在理解它们之间的历史、区别和联系之前,我们首先需要了解它们的基本概念。 JavaSE(Java Standard Edition&#xff…

Linux——进程信号(二)

目录 1、阻塞信号 1.1、信号其他相关常见概念 1.2、在内核中的表示 1.3、sigset_t 1.4、信号集操作函数 2、捕捉信号 2.1、内核如何捕捉信号 5.2、sigaction 1、阻塞信号 1.1、信号其他相关常见概念 实际执行信号的处理动作被称为信号递达(Delivery&#x…

sentinel黑白名单权限控制

黑白名单权限控制 规则配置 规则创建 创建一个 AuthorityRule 规则对象三个关键要素 setStrategy: 黑白名单类型setResource: 规则和资源的绑定关系setLimitApp: 限制的来源 调用 AuthorityRuleManager.loadRules()加载规则 监听器实例化和管理 AuthorityPropertyListener…

【Leetcode】top 100 链表

基础知识补充 单向链表结构:item存储数据 next指向下一结点地址 head保存首地址 class Node(object): # 创建结点def __init__(self, item): self.item item # item存放数据元素self.next None # next是下一个…

【教程】混淆代码保护与优化

在本文中,我们将介绍如何在iOS项目中利用混淆技术来保护源代码安全并实现优化。我们将分别针对Swift和OC项目,详细介绍如何使用脚本和工具进行代码混淆,并解决在混淆过程中可能遇到的问题。随着移动应用市场的不断扩大,iOS应用的安…

使用Pygame做一个乒乓球游戏

项目介绍 使用Pygame做一个乒乓球游戏。左侧为电脑,右侧为玩家。 视频地址-YT 视频搬运-B站 视频教程约90分钟。 代码地址 环境:需要pygame库,可用pip安装:pip install pygame 1. 基础版本 首先进行一些初始化,初始…

java NIO群聊系统

demo要求: 1)编写一个NIO群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞) 2)实现多人群聊 3)服务器端:可以监测用户上线,离线,并实现消息转发功…

python 爬虫 地理空间DEM 制作中国地形

一.配置Python 爬虫 环境 from selenium import webdriver import time # from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import Byfrom selenium.webdriver.common.keys import Keys # from selenium.webdriver.comm…

Langchain-chatchat+ChatGlm3-6b部署

我的环境 升级了下配置,加载知识库成功 内存:16GB 32B 显卡:GTX1060-6G RTX4080 Laptop-12G 1. 基础环境准备 1.1. 安装anaconda,创建环境python版本3.11 conda create -n chatglm3 python3.11 conda activate chatglm3 1.…

如何在CentOS搭建docker compose ui可视化工具并无公网IP远程管理容器

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

蓝桥杯 2023 省A 更小的数

主要思路: 输入一个长度为n的字符串,用二维数组dp[i][j]来记录子串[i, j]是否需要反转一次才能满足条件。使用动态规划自底向上地填充dp数组。根据问题的要求,需要考虑字符串的子串中字符的大小关系来判断是否需要反转。最后统计满足条件的子…

静态扭矩,是用公称扭矩还是最小动态扭矩作为对比?——​suntorque智能扭矩系统​

在机械工程和动力学领域,扭矩是一个至关重要的概念。当我们讨论到扭矩时,常常会遇到静态扭矩和动态扭矩的说法。特别是在实际应用中,工程师们经常需要对比和选择使用哪种扭矩作为参考。那么,静态扭矩,是用公称扭矩还是…

【C/C++】详解 assert() 断言(什么是assert? assert有什么作用?)

目录 一、前言 二、什么是 assert ? 三、assert 的用法 四、assert 案例解析 五、assert 断言的使用原则 六、共勉 一、前言 在编写程序过程中,尤其是调试代码时,往往需要一个提醒代码漏洞/Bug的小助手,以便于程序员及时修改和完善代码…

109 项目整合 spring-quartz 启动自动执行定时任务

前言 项目中使用了 quartz 来支持定时任务的相关基础支撑, 但是 最近添加了一个 资源消耗比较高的定时任务, 发布到测试环境之后, 发现服务突然 起不起来了[资源比较有限] 然后 查看了一下日志, 这个定时任务怎么在执行?, 不是 配置的是 凌晨两点么, 然后 仔细一看 几乎配置…

python课后习题一

题目: 1. 2. 解题过程: 1. """计算年数和天数""" minute int(input("请输入分钟数:")) hours minute // 60 days hours // 24 years days // 365 last_days days % 365 print(f"{minut…

【IEDM2023】背势垒电荷运动诱导GaN HEMT随时间的非稳态击穿

分享一篇2023年IEDM上GaN HEMT(高电子迁移率晶体管)的研究论文,标题为“Charge Movement in Back Barrier Induced Time-Dependent On-State Breakdown of GaN HEMT”。论文讨论了在GaN HEMT中,由于背栅(Back Barrier&…

BigDecimal类的使用,用于精确计算任意精度的数字

BigDecimal类 BigDecimal 是 Java 中用于精确表示任意精度的十进制数的类。在很多情况下,使用基本数据类型(如 double 或 float)进行浮点数计算可能会导致精度丢失或舍入错误。BigDecimal 提供了一种更精确的解决方案,可以处理需要高精度计算的场景,比如财务应用或科学计算…