UCOS-III 任务管理

01. 分配任务优先级与RMS调度

1.1. RMS调度算法

RMS(单调速率调度算法)是一种静态优先级调度算法,是经典的周期性任务调度算法。RMS的基本思路是任务的优先级与它的周期表现为单调函数的关系,任务的周期越短,优先级越高;任务的周期越长,优先级越低。如果存在一种基于静态优先级的调度顺序,使得每个任务都能在其期限时间内完成。

 

113dc4b6b9f0a013bfbbda14c3b26b6e.png

基于RMS 的一个基础理论公式

 

1.2 RMS调度实例

任务

执行时间

任务周期

TASK1

1

10

TASK2

1

5

TASK3

2

10

1)系统CPU使用率: 1/10+1/5+2/10 = 0.5

2) 3个任务时,RMS可实时调度率为:

 

bdf921cf4ccc7cc80a2c0d39aa6d52d3.png

实例结论: CPU占用率0.5 小于可实时调度率0.77, 所以这3个任务理论上是可以实时调度的。

1.3 基于RMS算法的任务优先级分配原则:

任务频率越高,优先级越高;任务执行时间越长,优先级越低

1.4. 最大任务优先级配置

最大任务优先级,影响查询最高优先级就绪任务时间, 任务最大优先级最好配置为32
OS_PRIO  OS_PrioGetHighest (void) //获取最高优级就绪任务
{
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;


    prio  = (OS_PRIO)0;
    p_tbl = &OSPrioTbl[0];
    while (*p_tbl == (CPU_DATA)0) {                         /* Search the bitmap table for the highest priority       */
        prio += DEF_INT_CPU_NBR_BITS;                       /* Compute the step of each CPU_DATA entry                */
        p_tbl++;
    }
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);              /* Find the position of the first bit set at the entry    */
    return (prio);
}

02. 任务堆栈管理

2.1 如何确定任务堆栈的大小

1) 手动计算任务堆栈大小

任务内所有函数调用嵌套所需的所有内存,每个函数调用一个返回地址的指针,每个函数调用中传递的所有参数,以及每个函数分配的局部变量,得到一个大约数后再乘以1.5~2的安全系数。

2) 通过uc/probe 监控运行时任务堆栈占用情况,根据实际情况调整。

3)任务函数设计的注意事项

a. 任务内避免函数的多层嵌套调用 
b. 任务内避免递归函数 
c. 避免分配大的局部变量

2.2 检测任务堆栈溢出

1)UCOS-III 监测任务运行时的最大堆栈: OS_StatTask()->OSTaskStkChk

 

a495a1f112f1e9655b097511541352c1.png

2) 堆栈溢出检测: OSRedzoneHitHook

 

d7c8f5789e14d95cdf8524a6933d53b3.png

03. 任务状态切换图

 

84d6b7d795c5def96269307a8aba3e65.png

04. 任务抢占式调度

 

 

任务抢占式调度过程分析:

(1) 低优先级任务正在执行,发生中断。

(2) 如果开启了中断,则CPU跳转到中断服务ISR中。

(3) ISR处理数据,向更高优先级的任务发出信号或消息,高优先级任务就绪

(4) 当 ISR 完成后, 触发任务调度

(6) 执行较高优先级的任务

(8) 较高优先级的任务执行完成后, 进入阻塞状态并触发任务调度

(10)切换回原始任务(被中断的任务)

(11) 被中断的任务在它被中断的地方恢复执行。

05. 任务时间片轮调度

时间片轮调度: 当两个或多个任务具有相同的优先级时,以设定好的时间片循环调度

时间片轮调度的时序图

fbc508b76947633a36760f43b5712c2f.png

 

(1) 任务#3正在执行,在此期间发生TICK中断,但任务 #3 的时间量尚未到期。

(2) 在第4个TICK答中断时,任务#3的时间量到期

(3) µC/OS-III 恢复任务#1,因为它是任务列表中优先级为“X”的下一个准备运行的任务。

(4) 任务#1 执行直到它的时间量到期

(7) 这里任务#3 执行,调用了OSSchedRoundRobinYield()函数放弃它的时间量,任务 #1开始运行

(8) 任务#1 执行直到它的时间量到期

06. 系统空闲任务

系统空闲任务OS_IdleTask()是 µC/OS-III 创建的第一个任务。空闲任务的优先级始终设置为OS_CFG_PRIO_MAX-1, 空闲任务是一个“真正的”无限循环。空闲任务主要用于测量CPU的使用率。

void  OS_IdleTask (void *p_arg)
{
    while (DEF_ON) {                    (1)
        CPU_CRITICAL_ENTER();
        OSIdleTaskCtr++;                (2)  
        OSStatTaskCtr++;
        CPU_CRITICAL_EXIT();
        OSIdleTaskHook();               (3)
    }
}

 

07. 系统统计任务

统计任务用于统计cpu使用率、每个任务cpu使用率、堆栈使用情况等运行时系统信息。

cpu占用率的统计

1)获取只有空闲任务运行(CPU空载)时,OSStatTaskCtrMax的值
OSStatTaskCPUUsageInit
OSStatReset
2)OSStatTaskCPUUsage/100,即cpu使用率

void main (void)                    
{
    OS_ERR  err;
    :
    OSInit(&err);                    
    if (err != OS_ERR_NONE) {
        /* Something wasn't configured properly, µC/OS-III not properly initialized  */
        /* ... 'err' will tell you the cause (see os.h)                              */
    }
    /* (3) Create ONE task (we'll call it AppTaskStart() for sake of discussion)     */
    :
    OSStart(&err);                    
}
  
  
void AppTaskStart (void *p_arg)
{
    OS_ERR  err;
    :
    /* (5) Initialize the tick interrupt                                             */
#if OS_CFG_STAT_TASK_EN == DEF_ENABLED
    OSStatTaskCPUUsageInit(&err);     
    OSStatReset(&err)                
#endif
    :
    /*  Create other tasks                                                        */
    while (DEF_ON) {
        /* AppTaskStart() body                                                       */
    }
}

08. 系统软定时器任务

软定时器与时钟滴答使用相同的中断源,但周期比时钟滴答长

 

b6c0f8250acc4b3202d96fdfe46ea3cb.png

09. 任务控制块详解

struct os_tcb {
    CPU_STK             *StkPtr;   //指向任务当前栈顶的指针
    void                *ExtPtr;   //指向用户定义数据区域的指针 
    CPU_CHAR            *NamePtr;  //任务创建时定义的任务名称
    CPU_STK             *StkLimitPtr;//堆栈溢出检测门限
    OS_TCB              *NextPtr;    
    OS_TCB              *PrevPtr;          //NextPtr, PrevPtr就绪/阻塞队列中的双向链表指针
    OS_TCB              *TickNextPtr;
    OS_TCB              *TickPrevPtr;;    //TickNextPtr, TickPrevPtr 延时到期/挂起超时队列中的双向链表指针
    OS_TICK_LIST        *TickListPtr;     //指向延时到期队列/挂起超时队列            
    CPU_STK             *StkBasePtr;      //指向任务堆栈的起始地址
    OS_TLS               TLS_Tbl[OS_CFG_TLS_TBL_SIZE] //编译器用于线程安全的数组
    OS_TASK_PTR          TaskEntryAddr;    //任务入口地址
    void                *TaskEntryArg;     //任务启动时传递的参数
    OS_TCB              *PendNextPtr;      
    OS_TCB              *PendPrevPtr;      //PendNextPtr,PendPrevPtr 等待列表中内核对象的双向链表指针
    OS_PEND_OBJ         *PendObjPtr;      //指向挂起的内核对象
    OS_STATE             PendOn;          //任务等待的内核对象
    OS_STATUS            PendStatus;      //任务挂起的结果OS_STATUS_PEND_OK,OS_STATUS_PEND_ABORT,OS_STATUS_PEND_DEL,OS_STATUS_PEND_TIMEOUT  
    OS_STATE             TaskState;       //任务状态
    OS_PRIO              Prio;            //任务当前优先级
    OS_PRIO              BasePrio;        //任务创建时的优先级
    OS_MUTEX            *MutexGrpHeadPtr; //指向任务拥有的互斥锁列表
    CPU_STK_SIZE         StkSize;         //任务堆栈大小
    OS_OPT               Opt;             //任务创建时传递的opt
    CPU_TS               TS;              //任务唤醒时的时间戳
    CPU_INT08U           SemID;           //第三方工具TraceAlyzer使用            
    OS_SEM_CTR           SemCtr;          //任务内部信号量计数值
    OS_TICK              TickRemain;      //从延迟或超时列表中删除任务之前剩余的tick
    OS_TICK              TickCtrPrev;     //用于OSTimeDly周期模式时的延时时间重载
    OS_TICK              TimeQuanta;    
    OS_TICK              TimeQuantaCtr;   // TimeQuanta,TimeQuantaCtr用于时间切片片轮调度
    void                *MsgPtr;          // 接收到的消息
    OS_MSG_SIZE          MsgSize;        // 接收到的消息大小
    OS_MSG_Q             MsgQ;           // 任务消息队列
    CPU_TS               MsgQPendTime;   // 最近一条消息传输消耗的时间
    CPU_TS               MsgQPendTimeMax; //消息传输消耗的最大时间
    OS_REG               RegTbl[OS_TASK_REG_TBL_SIZE];//特定寄存器
    OS_FLAGS             FlagsPend;      //任务被哪个事件挂起
    OS_FLAGS             FlagsRdy;       //任务被哪个事件唤醒
    OS_OPT               FlagsOpt;       //挂起任务的事件属于哪种类型
    OS_NESTING_CTR       SuspendCtr;     //任务被OSTaskSuspend()挂起的次数
    OS_CPU_USAGE         CPUUsage;       //任务当前的cpu占用率
    OS_CPU_USAGE         CPUUsageMax;    //任务最大的cpu占用率
    OS_CTX_SW_CTR        CtxSwCtr;       //用于调试器监视任务的执行频率
    CPU_TS               CyclesDelta;    //用于调试器监视任务最近一次执行的时间
    CPU_TS               CyclesStart;    //用于调试器监视任务开始执行的时间
    OS_CYCLES            CyclesTotal;    //用于调试器监视任务运行的总时长
    OS_CYCLES            CyclesTotalPrev;//Snapshot of previous # of cycles
    CPU_TS               SemPendTime;    //任务最近一次接收信号量消耗的时间
    CPU_TS               SemPendTimeMax; //任务接收信号量消耗的最长时间
    CPU_STK_SIZE         StkUsed;        //已使用堆栈的大小
    CPU_STK_SIZE         StkFree;        //剩余堆栈的大小
    CPU_TS               IntDisTimeMax;  //任务关闭中断的最长时间
    CPU                  SchedLockTimeMax;//任务关闭任务调度的最长时间
    OS_TCB               *DbgPrevPtr;     
    OS_TCB               *DbgNextPtr;
    CPU_CHAR             *DbgNamePtr;      
    CPU_INT08U           TaskID;           //用于TraceAlyzer 等第三方工具
};

10. 系统调度相关API

10.1 任务相关API

10.2 任务阻塞相关API

10.3 任务唤醒相关API

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechIoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值