当前位置: 首页 > news >正文

ucos-ii 的任务调度原理和实现

ucosii 任务调度和原理

1、ucos-ii 任务创建与任务调度

1.1、任务的创建

当你调用 OSTaskCreate( ) 进行任务的创建的时候,会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块(OS_TCB)等的操作;

if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */
        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  *//* ... the same thing until task is created.              */OS_EXIT_CRITICAL();
        psp = OSTaskStkInit(task, p_arg, ptos, 0u);             /* Initialize the task's stack         */
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);if (err == OS_ERR_NONE) {if (OSRunning == OS_TRUE) {      /* Find highest priority task if multitasking has started */OS_Sched();}} else {OS_ENTER_CRITICAL();
            OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */OS_EXIT_CRITICAL();}return (err);}
注意:ucosii不支持两个及以上相同的任务优先级的任务,ucosiii支持时间片轮转。

ucosii 的任务控制块是任务中很重要,它记录了任务的信息,包括优先级、延时时间、状态等信息。控制块定义如下:

typedef struct os_tcb {OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */#if OS_TASK_CREATE_EXT_EN > 0uvoid            *OSTCBExtPtr;           /* Pointer to user definable data for TCB extension        */OS_STK          *OSTCBStkBottom;        /* Pointer to bottom of stack                              */INT32U           OSTCBStkSize;          /* Size of task stack (in number of stack elements)        */INT16U           OSTCBOpt;              /* Task options as passed by OSTaskCreateExt()             */INT16U           OSTCBId;               /* Task ID (0..65535)                                      */
#endifstruct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */#if (OS_EVENT_EN)OS_EVENT        *OSTCBEventPtr;         /* Pointer to          event control block                 */
#endif#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)OS_EVENT       **OSTCBEventMultiPtr;    /* Pointer to multiple event control blocks                */
#endif#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)void            *OSTCBMsg;              /* Message received from OSMboxPost() or OSQPost()         */
#endif#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
#if OS_TASK_DEL_EN > 0uOS_FLAG_NODE    *OSTCBFlagNode;         /* Pointer to event flag node                              */
#endifOS_FLAGS         OSTCBFlagsRdy;         /* Event flags that made task ready to run                 */
#endifINT32U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */INT8U            OSTCBStat;             /* Task      status                                        */INT8U            OSTCBStatPend;         /* Task PEND status                                        */INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */INT8U            OSTCBX;                /* Bit position in group  corresponding to task priority   */INT8U            OSTCBY;                /* Index into ready table corresponding to task priority   */OS_PRIO          OSTCBBitX;             /* Bit mask to access bit position in ready table          */OS_PRIO          OSTCBBitY;             /* Bit mask to access bit position in ready group          */#if OS_TASK_DEL_EN > 0uINT8U            OSTCBDelReq;           /* Indicates whether a task needs to delete itself         */
#endif#if OS_TASK_PROFILE_EN > 0uINT32U           OSTCBCtxSwCtr;         /* Number of time the task was switched in                 */INT32U           OSTCBCyclesTot;        /* Total number of clock cycles the task has been running  */INT32U           OSTCBCyclesStart;      /* Snapshot of cycle counter at start of task resumption   */OS_STK          *OSTCBStkBase;          /* Pointer to the beginning of the task stack              */INT32U           OSTCBStkUsed;          /* Number of bytes used from the stack                     */
#endif#if OS_TASK_NAME_EN > 0uINT8U           *OSTCBTaskName;
#endif#if OS_TASK_REG_TBL_SIZE > 0uINT32U           OSTCBRegTbl[OS_TASK_REG_TBL_SIZE];
#endif
} OS_TCB;

2、任务调度实现

2.1、将任务优先级进行分组

因为ucosii最大优先级数量为64个,所以可以分成8组,每组8个优先级。

当一个任务被创建成功之后,它的组号由优先级的高三位决定(bit5 bit4 bit3),它在组内的编号由优先级的低三位决定(bit2 bit1 bit0),如下:

#if OS_LOWEST_PRIO <= 63u                                         /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)(prio >> 3u);    // 组
        ptcb->OSTCBX             = (INT8U)(prio & 0x07u);  // 组内编号
#else          

2.2、任务就绪表

ucosii对任务优先级的调度管理是通过查询任务就绪表进行的。任务就绪表里面保存着当前所有任务的就绪状态,如下:

OSRdyTbl[8]说明:
1)它是uint8的数据类型。它的长度是8,每一个元素代表一个组,
比如 OSRdyTbl[0]代表第0组, OSRdyTbl[1]代表第1组,OSRdyTbl[2]代表第2组……以此类推。2)每一个元素中的每一个位(bit)代表组内的任务的就绪状态(1为就绪,0为未就绪)。

打个比方:

1)当优先级为12 的任务就绪时,那么对应的OSRdyTbl[1]的第4位bit,绝对等于1
当整个系统中,当只有优先级为12的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[1] 绝对等于0x102)当优先级为01的任务就绪时,那么对应的OSRdyTbl[0]的第0位bit以及第1位bit,都绝对等于1
当整个系统中,当只有优先级为01的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[0] 绝对等于0x03

2.3、任务释放CPU使用权

当任务中调用 OSTimeDly( ) 时,会让任务进入休眠的状态,交出CPU的执行权给到其他就绪任务去执行,这个过程就发生了任务的切换。

简单而言就是会把任务就绪表 OSRdyTbl 中对应的任务优先级在组内的编号状态改变,从而使任务自身进入休眠状态。代码如下:

if (ticks > 0u) {                            /* 0 means no delay!                                  */OS_ENTER_CRITICAL();
        y            =  OSTCBCur->OSTCBY;        /* Delay current task                                 */
        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {
            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}
        OSTCBCur->OSTCBDly = ticks;              /* Load ticks in TCB                                  */OS_EXIT_CRITICAL();OS_Sched();                              /* Find next task to run!                             */}

在上面的代码中发现了一个东西:OSRdyGrp。这个有什么用呢?

OSRdyGrp:管理任务就绪组的

OSRdyGrp是INT8U类型的,它每一个bit代表一个组,只要这个组内有任何一个任务就绪了,那对应的这个bit就会被设置为1,表示这个组内目前有就绪的任务。否者对应的位为0

举个例子,如下:

1)系统中只有任务0就绪了,那么OSRdyGrp 便等于 0x01(二进制00000001)。
2)系统中有任务0和任务63都就绪了,那么OSRdyGrp 便等于 0x81(二进制10000001)

2.4、任务实现调度切换操作

发生一次任务调度是通过 OS_Sched() 进行的。源码如下:

void  OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0u;
#endifOS_ENTER_CRITICAL();if (OSIntNesting == 0u) {                          /* Schedule only if all ISRs done and ...       */if (OSLockNesting == 0u) {                     /* ... scheduler is not locked                  */OS_SchedNew();
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
#if OS_TASK_PROFILE_EN > 0u
                OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
#endif
                OSCtxSwCtr++;                          /* Increment context switch counter             */OS_TASK_SW();                          /* Perform a context switch                     */}}}OS_EXIT_CRITICAL();
}

这里的过程如下:

(1)先通过 OS_SchedNew() 找到当前处于就绪状态的最高优先级的任务,如下:

y             = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);

(2)然后通过 OS_TASK_SW() 进行任务切换,它的过程如下:

1)OS_TASK_SW 只是一个宏,它实际替换的是 OSCtxSw()
#define  OS_TASK_SW()         OSCtxSw()2OSCtxSw()是由汇编实现的
OSCtxSw
		PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL  	;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
		POP     {R4, R5}
        BX      LR

就这样,上下文就完成了一次切换。

 

相关文章:

ucos-ii 的任务调度原理和实现

ucosii 任务调度和原理1、ucos-ii 任务创建与任务调度 1.1、任务的创建 当你调用 OSTaskCreate( ) 进行任务的创建的时候&#xff0c;会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块&#xff08;OS_TCB&#xff09;等的操作&#xff1b; if (OSTCBPrioTbl[prio] (OS_…...

Solon2 开发之容器,七、切面与函数环绕拦截

想要环绕拦截一个 Bean 的函数。需要三个前置条件&#xff1a; 通过注解做为“切点”&#xff0c;进行拦截&#xff08;不能无缘无故给拦了吧&#xff1f;费性能&#xff09;Bean 的 method 是被代理的在 Bean 被扫描之前&#xff0c;完成环绕拦截的注册 1、定义切点和注册环…...

代码随想录第十天(28)

文章目录28. 找出字符串中第一个匹配项的下标看答案KMPnext数组&#xff08;前缀表&#xff09;最长公共前后缀如何计算前缀表前缀表与next数组时间复杂度分析28. 找出字符串中第一个匹配项的下标 莫得思路……好久没做题&#xff0c;都已经忘得差不多了 看答案 其实就是自己…...

循环队列来了解一下!!

笔者在之前的一篇文章&#xff0c;详细的介绍了&#xff1a;队列之单向链表与双向链表的模拟实现&#xff1a;https://blog.csdn.net/weixin_64308540/article/details/128742090?spm1001.2014.3001.5502 感兴趣的各位老铁&#xff0c;可以参考一下啦&#xff01;下面进入循环…...

Idea打包springboot项目war包,测试通过

pom.xml文件 <!--包名以及版本号&#xff0c;这个是打包时候使用&#xff0c;版本可写可不写&#xff0c;建议写有利于维护系统--> <artifactId>tsgdemo</artifactId> <version>0.0.1-SNAPSHOT</version> <!--打包形式--> <packaging&…...

python+django高校师生健康信息管理系统pycharm

管理员功能模块 4.1登录页面 管理员登录&#xff0c;通过填写注册时输入的用户名、密码、角色进行登录&#xff0c;如图所示。 4.2系统首页 管理员登录进入师生健康信息管理系统可以查看个人中心、学生管理、教师管理、数据收集管理、问卷分类管理、疫情问卷管理、问卷调查管理…...

CUDA中的流序内存分配

文章目录CUDA中的流序内存分配1. Introduction2. Query for Support3. API Fundamentals (cudaMallocAsync and cudaFreeAsync)4. Memory Pools and the cudaMemPool_t注意&#xff1a;设备的内存池当前将是该设备的本地。因此&#xff0c;在不指定内存池的情况下进行分配将始终…...

开源、低成本的 Xilinx FPGA 下载器(高速30MHz)

目前主流的Xilinx下载器主要有两种&#xff1a;一种是Xilinx官方出品的Xilinx Platfom Cable USB&#xff0c;还有一个就是Xilinx的合作伙伴Digilent开发的JTAG-HS3 Programming Cable。 JTAG-HS系列最大支持30MHz下载速度&#xff0c;基于FTDI的FT2232方案。 JTAG-HS系列对比…...

Maven专题总结

1. 什么是Maven Maven 是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (POM&#xff1a; Project Object Model)&#xff0c;一组标准集合&#xff0c;一个项目生命周期(Project Lifecycle)&#xff0c;一个依赖管理系统(Dependency Management System)&#xff0c;和…...

谷粒商城--SPU和SKU

目录 1.SPU和SKU概念 2.表的关系理解 3.导入前端代码 4.完善后端接口 5.属性分组详情 6.规格参数详情 7. 销售属性详情 8.分组与属性关联 9.发布商品 10.仓库服务 1.SPU和SKU概念 SPU&#xff1a;standard product unit(标准化产品单元)&#xff1a;是商品信息聚合的…...

二叉树OJ题(上)

✅每日一练&#xff1a;100. 相同的树 - 力扣&#xff08;LeetCode&#xff09; 题目的意思是俩棵树的结构不仅要相同&#xff0c;而且每个节点的值还要相同&#xff0c;如果满足上面2个条件&#xff0c;则成立&#xff01; 解题思路&#xff1a; 从三个方面去考虑&#xff1…...

第一章 PDF语法

第一章 PDF语法PDF ObjectsNull ObjectsBoolean ObjectsNumeric ObjectsName ObjectsString ObjectsArray ObjectsDictionary ObjectsName treesNumber treesStream ObjectsDirect versus Indirect ObjectsFile StructureWhite-SpaceThe Four Sections of a PDFHeaderTrailerBo…...

IntelliJ IDEA 创建JavaFX项目运行

IntelliJ IDEA 创建JavaFX项目运行JavaFX官网文档&#xff1a;https://openjfx.io/openjfx-docs/ JavaFX 2008年12月05日诞生&#xff0c;是一个开源的下一代客户端应用程序平台&#xff0c;适用于基于 Java 构建的桌面、移动和嵌入式系统。这是许多个人和公司的协作努力&#…...

IC封装常见形式

参考&#xff1a;https://blog.csdn.net/dhs888888/article/details/127673300?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-127673300-blog-115610343.pc_relevant_multi_platform_whitelistv4&spm1001.2101.3001.4242…...

Linux通配符、转义符讲解

目录 通配符 通过通配符定义匹配条件 转义符 将所有的逻辑操作符都转换成字符 通配符 通过通配符定义匹配条件 * 任意字符都可以通配&#xff08;也可以匹配空值&#xff09; &#xff1f; 匹配单个字符 [a-z] 匹配单个的小写英文字母 [A-Z] 匹配单个的大写英文…...

[OpenMMLab]提交pr时所需的git操作

git开发流程 准备工作 作为一个开发者&#xff0c;fork一个仓库之后应该先做什么&#xff1f; 1、下载仓库&#xff0c;创建上游代码库&#xff0c;查看当前的分支情况 git clone https://github.com/<your_name>/<repo_name>.git git remote add upstream git…...

pandas——groupby操作

Pandas——groupby操作 文章目录Pandas——groupby操作一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤一、实验目的 熟练掌握pandas中的groupby操作 二、实验原理 groupby(byNone, axis0, levelNone, as_indexTrue, sortTrue, group_keysTrue, squeezeFalse&…...

webpack.config.js哪里找?react项目关闭eslint监测

目录 webpack.config.js哪里找&#xff1f; react项目关闭eslint监测 webpack.config.js哪里找&#xff1f; 在React项目中&#xff0c;当我们需要修改一些配置时&#xff0c;发现找不到webpack.config.js&#xff0c;是我们创建的项目有问题吗&#xff0c;还需新创建项目的项…...

OpenCV 图像梯度算子

本文是OpenCV图像视觉入门之路的第12篇文章&#xff0c;本文详细的介绍了图像梯度算子的各种操作&#xff0c;例如&#xff1a;Sobel算子Scharr算子laplacian算子等操作。 OpenCV 图像梯度算子目录 1 Sobel算子 2 Scharr算子 3 laplacian算子 1 Sobel算子 Sobel算子是一种图…...

Linux c编程之Wireshark

Wireshark是一个网络报文分析软件,是网络应用问题分析必不可少的工具软件。网络管理员可以使用wireshark排查网络问题。程序开发人员可以用来分析应用协议、定位分析应用问题。无论是网络应用程序开发人员、测试人员、部署人员、技术支持人员,掌握wireshark的使用对于分析网络…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...