#include"includes.h"int main()
{   TargetInit();//所搭载的硬件板物理初始化OSInit();//操作系统初始化OSTaskCreate(Task0,&StackTask0[Stack_Size-1], Task0Prio,...);//任务0创建OSStart();//操作系统开始运行return 0;
}void Task0(void)
{Uart_Printf("Stort OS/n ")//打印类的代码;OSTaskCreate(Task1,&StackTask1[Stack_Size-1], Task1Prio,...);//任务1创建OSTaskCreate(Task2,&StackTask2[Stack_Size-1], Task2Prio,...);//任务2创建for(;;){Uart_Printf("Task1/n ")     //打印类的代码;OSTimeDly(时间0);//任务切换}
}void Task1(void)
{for(;;){Uart_Printf("Task1/n ")    //打印类的代码;OSTimeDly(时间1);//任务切换}
}void Task2(void)
{for(;;){Uart_Printf("Task2/n ")    //打印类的代码;OSTimeDly(时间2);//任务切换}
}
。。。```

Q1:每个任务的延时时间不同,那么每个任务在延时时间到达后被系统调用的先后顺序是如何执行的?
Answer:OS系统的时钟节拍通常是通过一个硬件定时器定时产生周期性的中断来实现的,在这个中断服务函数(Timer_ISR)中会遍历(使用循环来依次判断每个)所有任务的任务控制块成员_延时时间OSTCBDly,并使其减1,并使延时时间清0的任务进入就绪状态;可参考简易OS设计文档中的开头示例;
Q2:根据简易OS示例,当延时时间到达后重新调用任务0时,为什么只执行死循环内的任务代码,而不执行循环外的也在该任务函数内的代码?【★★★疑惑】
Q3:任务创建时的任务堆栈增长方向(所使用的处理器支持的增长方向)的确认?
Answer:例如PC端的处理器支持向上增长(低→高),假设定义任务堆栈数组Uint16 MyTaskStack[64] (该任务堆栈长度128byte)
所以任务堆栈的栈顶地址是 &MyTaskStack[0] ;
【tips】任务堆栈的栈顶指针指向的定义的堆栈数组元素对应的地址总是最低地址,不管增长方向;栈顶指针SP(cpu内部寄存器)指向人工栈数组的首元素(向上增长(递增栈))或最后一个元素(向下增长(递减栈));

向上:a[0] (sp栈顶指针指向) —> a[2] , 低—>高;
向下:a[0] —>a[2] (sp栈顶指针指向) , 高—>低;
Q4:关于高优先级抢占低优先级调用公共资源时的处理思想?
Answer:对于公共函数采用可重入函数(局部变量)和互斥调用的思想;
Q5:任务控制块两条链表及创建任务时的链表处理,那么链表表头指针如何赋值,以及当前任务控制块指针OSTCBCur的值是多少? 任务调度中对任务控制块指针的处理?
Answer:由于已经定义了任务控制块结构体及所含该任务各个变量,那么在OS系统初始化时(调用OSInit()函数),按照事先配置设置的任务数量进行创建所有的任务控制块,方式是通过一条空白任务控制块链表(都还没分配给任务)和一条任务控制块链表(链表上的任务控制块都已分配任务)来处理;
【tips】1、以后每当系统调用创建任务OSTaskCreate函数创建任务时,系统就通过将空白任务控制块链表表头指针OSTCBFreeList指向的任务控制块分配给该任务,并给该任务控制块各个变量赋值后,再用任务控制块链表表头指针OSTCBList将其链入到任务控制块链表中;这两个链表表头指针指向的数据类型OS_TCB OSTCBFreeList,OSTCBList
2、然后定义个OS_TCB类型的数组OSTCBTbl[任务数+系统任务],然后将 OSTCBList /OSTCBFreeList = &OSTCBTbl[0] ; OSTCBTbl[0].next = &OSTCBTbl[1] ; OSTCBTbl[1].next = &OSTCBTbl[2] ; 。。。依次指向后一个任务控制块结构体类型的数组变量,实现整个链表的连接;
3、假设任务控制块类型定义的数组是:OS_TCB TCBHnb[任务数+系统任务];如果当前正在运行的任务优先级为0,也就是OSTCBCur = &TCBHnb[0] ,一般会直接这么操作;但是μC/OS采用定义另外一个OS_TCB指针类型的数组(该数组通过优先级顺序依次排好,例如该数组为OSTCBPrioTbl [Prio] ,当优先级prio为0时代入,OSTCBPrioTbl [0] = &TCBHnb[0]来获取对应优先级任务的任务控制块指针,也就是对应的定义任务控制块类型数组元素的地址;
4、任务调度需要前后两个任务的任务控制块指针:当前的任务控制块指针已存放于OSTCBCur指针变量中;获取待运行任务的任务控制块指针,可通过查任务就绪表获取任务最高优先级HighPrio(同时判断该优先级跟当前运行任务的优先级不相等,也就不是正在运行的任务,而是将要运行的任务);那么根据3可知OSTCBPrioTbl [HighPrio]中存放的就是待运行任务的任务控制块指针,再定义个指针变量OS_TCB * OSTCBRdy = OSTCBPrioTbl [HighPrio];那么就是OSTCBCur和OSTCBRdy这两个前后任务的任务控制块指针;
5、断点的保护(运行时中止的地方,此时的断点数据(例如CPU内部寄存器组中的控制寄存器PC程序计数器、通用寄存器SP堆栈指针等)要被保护起来;例如:任务1被中止,此时的断点数据保存到任务1的堆栈内;但是要注意的是这个堆栈是任务堆栈,不是内存堆栈(局部变量、函数调用、函数形参等开销),是一个全局变量的数组;
6、正确恢复断点数据的关键:cpu的SP堆栈指针的正确指向;例如:任务1被任务2中止,其中cpu的SP寄存器的值被保存到任务1的任务控制块结构图数组的内部变量OSTCBStkPtr,需要用汇编语句来实现,PC寄存器被保存到定义的任务堆栈内;
7、但是遗憾的是,对于一般处理器并没有对PC指针(PC寄存器)进行操作的出栈和入栈指令,而是靠产生中断,中断向量指向中断服务函数(跳转到ISR时) 时系统自动将断点处原PC指针内容保存到堆栈内,中断结束(中断返回指令)将之前保存原PC指针内容从堆栈内重新赋值给PC指针;
Q6: 任务在切换的时候,SP指针被保存(赋值)到任务的任务控制块中元素OSTCBStkPtr(通过汇编指令),那么PC指针被保存到任务堆栈还是内存堆栈?
【★★★】
Answer:借鉴简易OS设计,在创建任务的时候即调用OSTaskCreate()函数,已将人工定义的任务堆栈栈顶指针(即数组Uint16 MyTaskStack[64] (向上增长))&MyTaskStack[0]赋值给任务控制块元素OSTCBStkPtr;同样的,在进行任务切换时,此时cpu内部寄存器SP保存的堆栈栈顶地址会被保存到被中止的任务的任务控制块元素OSTCBStkPtr中;那么对于每个任务而言,其人工定义的任务堆栈和内存中的堆栈便是同一个堆栈;
1、在创建任务的时候,函数实参主要是三个:任务函数的入口地址、人工堆栈的栈顶地址、任务的优先级;调用后,系统执行到OSTaskStkInit()函数,会根据用户参数初始化任务堆栈;而对于任务在创建时的堆栈初始化内容可参考简易os设计; 当一个任务将要运行时,便通过取得已保存在其任务控制块变量的结构体元素OSTCBStkPtr(已被赋值人工任务堆栈的栈顶地址),将任务堆栈中对应位置赋值(出栈)给cpu内部寄存器组(R0~R12,PC/LR/CPSR),这一段的汇编代码处理可参考简易OS设计p17;
Q7:抢占式调度思想
【tips】最高优先级的任务一旦处于就绪态,立即抢占正在运行的低优先级任务的处理器资源;
1、高优先级任务通过主动挂起/延时,让位低优先级任务执行;
Q8:中断级任务调度思想
1、可剥夺型内核RTOS响应中断的过程,当收到中断请求时,cpu若处于中断允许状态(开中断)会响应中断,中止当前任务,按中断向量(一般为中断服务函数函数名)跳入中断服务函数ISR执行,当ISR执行完后,RTOS会判断情况进行一次任务调度运行优先级最高的就绪任务,不一定返回原断点继续执行被中断的任务;
2、中断嵌套:后产生的高优先级中断会打断低优先级的中断的ISR的执行;中断挂起:被高优先级中断打断的低优先级的ISR会被挂起,等待高优先级中断的ISR执行完继续执行;
3、中断级任务调度的条件:中断嵌套层数= 0、调度器上锁次数 = 0、就绪表最高优先级任务 ≠ 当前正在运行任务的优先级 才会进行任务切换;当仍有中断嵌套时,先执行完所有中断后才能返回到任务中,不满足条件不能进行任务切换,是通过OSIntExit()函数进行判断的,在该函数内满足条件时调用OSIntCtx()函数;
4、cpu的断点保护是放在中断的ISR里处理的;
5、中断的断点保护数据是保存在中断模式下的堆栈中;
6、示例任务1正在执行,被中断打断,这时的现场保护中的PC指针的值(断点地址)入栈到中断模式下的堆栈里,当退出中断后进行任务切换执行函数OSIntCtx(),如果有更高优先级的任务2,不返回原任务1断点处继续执行的话,那么PC指针的值肯定得等于函数名OSIntCtx,所以这时候要有个返回地址的更换(pc寄存器值的更换),这个通过汇编进行操作;当中断结束后,根据PC指针的值便开始执行OSIntCtx()函数进行任务的切换,然后将之前替下来的任务1的PC指针(断点地址),堆栈栈顶指针SP等断点数据入栈到任务1自己的堆栈里进行保存,然后将待执行当前已就绪的最高优先级任务2的SP堆栈栈顶指针赋值给SP寄存器,其他已经在创建任务2时初始换任务堆栈过的PC指针等内容赋值到cpu相关寄存器,进入任务2的运行环境;
【注意】进入中断时的堆栈跟任务里人工定义的堆栈不是一回事,必须等待中断ISR完全结束后才能进行任务切换以及堆栈的操作;刚退出中断时的运行环境的cpu寄存器的值已经由执行中断时的堆栈内容(退出中断其内容释放掉了)切换到任务1的任务堆栈保存的内容
Q9:任务挂起/恢复处理
1、挂起任务就是通过OSTaskSuspend()函数将需要被挂起的任务从任务就绪表中删除,然后再进行任务调度(切换);可以挂自己也可以挂别人;
2、通过OSTaskResume()函数可以将经过OSTaskSuspend()挂起或者OSTimeDly函数延时的任务立即从任务就绪表中置位恢复就绪,并将已被延时任务的延时变量OSTCBDly清0,即恢复任务,然后再进行任务调度(切换);

借用名言:“工程师在选用多任务操作系统前要先看看自己的项目是不是真的需要,如果你的任务可拆分性较差(耦合程度高,业界提倡高内聚低耦合),拆分后各任务间有N多在同步上的问题和复用资源问题,那么算了,还是不要用多任务操作系统;不要有事没事就觉得多任务好,多任务是通过降低实时性来换取软件开发的独立性,不要被实时多任务操作系统的实时给骗了,这个实时是相对于其他非实时性多任务操作系统来讲的,实时性最高的当然是你自己编写的单任务程序。

持续更新中

。。。

RTOS任务调度思想汇总相关推荐

  1. 分布式架构--基本思想汇总

    转载自  分布式架构--基本思想汇总 在互联网大行其道的今天,各种分布式系统已经司空见惯.搜索引擎.电商网站.微博.微信.O2O平台..凡是涉及到大规模用户.高并发访问的,无一不是分布式. 关于分布式 ...

  2. RTOS任务调度流程——基于FreeRTOS在Cortex-m4上的实现

    一. FreeRTOS任务调度流程 RTOS调度流程中主要关注以下几个点:创建任务.开启任务调度.任务调度:下面将以FReeRTOS在Cortex-m4的实现为例,展示一下RTOS任务调度的大体流程. ...

  3. 那些惊艳的算法—时间轮任务调度(sunwind整理)

    从定时任务说起 自然界中定时任务无处不在,太阳每天东升西落,候鸟的迁徙,树木的年轮,人们每天按时上班,每个月按时发工资.交房租,四季轮换,潮涨潮落,等等,从某种意义上说,都可以认为是定时任务. 大概很 ...

  4. 如何快速构建嵌入式全栈知识体系?

    嵌入式是一门交叉学科. 一个嵌入式电子产品(比如手机)从底层到上层,一般会涉及半导体芯片.电子电路.计算机.操作系统.多媒体等不同专业领域的知识. 很多从事嵌入式开发的朋友,通常来自不同的专业(电子. ...

  5. 嵌入式C语言自我修养:从芯片、编译器到操作系统(附送书籍)

    关注+星标公众号,不错过精彩内容 来源 | 宅学部落 最近,阅读了王工(王利涛)赠送的一本由他编著的书籍<嵌入式C语言自我修养>,感觉写的挺不错.今天分享一下这本书籍<嵌入式C语言自 ...

  6. 每日一书丨嵌入式C语言自我修养:从芯片、编译器到操作系统

    最近,阅读了王工(王利涛)赠送的一本由他编著的书籍<嵌入式C语言自我修养>,感觉写的挺不错.今天分享一下这本书籍<嵌入式C语言自我修养>:从芯片.编译器到操作系统. 从芯片.编 ...

  7. 快速构建嵌入式全栈知识体系以及如何进阶

    快速构建嵌入式全栈知识体系以及如何进阶 嵌入式是一门交叉学科.一个嵌入式电子产品(比如手机)从底层到上层,一般会涉及半导体芯片.电子电路.计算机.操作系统.多媒体等不同专业领域的知识.很多从事嵌入式开 ...

  8. Spring中ThreadPoolTaskExecutor的线程调度及问题

    问题现象 原因分析 任务调度逻辑 汇总分析 解决方案 问题现象 在我们的系统中,使用了这样的配置来开启异步操作: spring配置 <task:annotation-driven executo ...

  9. JingRiverOS的自由软件之路

    2019独角兽企业重金招聘Python工程师标准>>> 好久以前就想写一个内核,一直没有动笔.一来是没有很好的一种架构可以借鉴,二来是对RTOS的思想没有完全的领会.随着不断地研究与 ...

最新文章

  1. 向有环的环形链表中插入新节点
  2. MVC5网站部署到IIS7
  3. PyTorch学习(8)-问答系统、文本摘要和大规模预训练语言模型
  4. 什么是E-MapReduce
  5. 从零开始打造数据中心的N道门槛 | 又拍干货分享
  6. 万万没 想到,Redis性能测试还能这样做
  7. 【数据结构笔记36】C实现:基于Median3的快速排序
  8. 租用服务器怎么免去后顾之忧?
  9. Atitit 软件开发方法论 attilax著 艾龙 著 1. 1.3 软件工程方法 软件工程方法论分为软件开发方法论和软件组织方法论两个部分。 1 2. 软件开发方法的演进  SP DOP PAM
  10. python连接mysql代码_Python连接MySQL及基本操作代码
  11. 解决Mac版 snipaste 不在菜单栏显示,无法修改快捷键
  12. STM32CubeMX创建F429/L475 HAL库工程并移植UCOSIII (二)(文末附源码)
  13. 暾盛机器人_移动机器人视觉伺服.pdf
  14. EXCEL函数篇01 按间隔符提取数据,实现分列功能
  15. 2018国内各大互联网公司前端面试题汇总【转:公众号~~高级前端进阶公众号】
  16. 英国将强制互联网公司遏制外国政府发布假信息,违法者或被罚款数十亿美元...
  17. 一个开源经典的MCU菜单框架设计
  18. c语言case套case,switch…case
  19. 2022-2027年中国大理石板材市场竞争态势及行业投资潜力预测报告
  20. 计算机基础0000代表的数字,计算机基础

热门文章

  1. 自定义函数求解一元二次方程(C语言)
  2. Typora PicGo+Github 踩坑
  3. 【深度学习NLP】初识深度学习(DL)与自然语言(NLP)
  4. 日语高考生能报计算机,日语高考生可以报哪些大学?
  5. python数据分析水果_超酷炫的事情,使用python识别出图片里的水果
  6. Flutter 布局Row(水平方向布局)、Column(垂直方向布局)、Wrap(可以自动换行的布局)、Flex(弹性布局)、Stack(叠层布局)、
  7. 记一次mac pro系统升级崩溃事件
  8. 乐迪机器人开热点_乐迪机器人有哪些功能 乐迪机器人怎么样
  9. 用HackRF和Gqrx来听FM广播
  10. 事实抽取与验证研究综述