RTOS学习笔记

最近在学习实时操作系统(RTOS),故将所学知识罗列出来,以供日后参考。

1.任务的本质

任务-说白点,即是一个永远不会返回的函数。

2.任务切换的本质

即是保存当前运行任务的状态,然后再恢复出下一个要运行的任务的状态。任务状态包括任务自己的栈,堆,数据区,代码区,内核寄存器的值。数据区和代码区由编译器自动分配,故不需要关心。堆目前并未使用,故也不需关心,那么唯一要关心的就是栈和内核寄存器了。而每一个任务我们都会分配给它一个栈空间用于保存自己的状态。

3.任务切换的实现

cortex-m3是通过触发pensv中断来进行任务切换的。故我们可以通过设置NVIC相关寄存器的值触发pendsv中断来进行任务切换。

那么问题来了,第一,我们如何切换进第一个要运行的任务?第二,如何实现两个任务之间的切换?

答案很简单,像是通过设置标志位一样,我们在初始化任务完成后,通过设置psp堆栈指针为0代表着这是第一次进入任务切换的中断函数(pendsv_handler),直接恢复该任务的堆栈值到相关寄存器中,等跳出中断后即进入了第一个要运行的任务;当再次进入任务切换的中断函数时,此时psp不为0,故应知当前进入中断是想要切换任务,则把当前任务的运行状态保存起来,然后再恢复下一个要运行的任务的状态即可。

具体实现代码如下:

__asm void PendSV_Handler ()
{
IMPORT  currentTask              // 使用import导入C文件中声明的全局变量
IMPORT  nextTask                 

MRS    R0, PSP                  // 获取当前任务的堆栈指针
CBZ    R0, PendSVHandler_nosave  // 判断psp是否为0,如果为0,则跳转。
STMDB  R0!, {R4-R11}            // 如果不为0,则先保存当前任务状态
LDR    R1, =currentTask         
LDR    R1, [R1]             
STR    R0, [R1]                // 重置任务栈的栈顶   

PendSVHandler_nosave  
LDR    R0, =currentTask
LDR    R1, =nextTask
LDR    R1, [R1]                
STR    R1, [R0]                  // 交换指针值

LDR    R0, [R1]                  //加载该任务的栈顶指针,用于恢复出任务状态 
LDMIA  R0!, {R4-R11}       // 恢复{R4, R11},其余硬件自动恢复

MSR    PSP, R0                  // 最后,恢复真正的堆栈指针到PSP
ORR    LR, LR, #0x04            // 切换到PSP,使用用户级堆栈
BX     LR                        // 恢复到上次运行停止的位置
}

4 双任务时间片运行原理

可以通过定时器定时触发pendsv中断,实现任务的切换。对于cotex-m3芯片,一般使用内核定时器systick_handler

5 任务的延时原理与空闲任务

由于硬件定时器资源有限,而任务的数量可能很多,所以一般无法给每一个任务都配置一个硬件定时器。所以一般使用软件定时器,即在任务的结构中添加一个变量,表示该任务当前需要延时的周期数。代码如下:

typedef struct _task
 {
    uint32_t *stack;   // 指向任务栈的栈顶指针
    uint32_t delayTicks;   // 任务延时计数器
}Task_t;


但是这种软延时的方法有一个明显的缺陷,便是延时精度可能并不是特别准确,具体情况见下图:

另外,当所有任务都处于延时状态时,CPU应该做什么呢?正确的做法是提供一个空闲任务。

6 临界区保护

临界区指的是一个访问共享资源的程序片段;言而简之,之所以设置临界区保护,是为了防止读-改-写过程被打断,从而导致写回变量时,覆盖了打断过程对变量的改写。具体的实现方法便是关中断,其一,中断关闭后,任务不可能被中断打断,导致共享变量的改写被覆盖;其二,关闭中断后,即关闭了任务切换,所以即便是多任务共享的资源,也只能由当前任务来访问了。
唯一的问题在于当有多层嵌套临界区时,第二层的临界区的开中断操作会使前一层的临界区保护失败,故正确的解决办法是:每次关闭中断前,先保存当前中断的开关状态,退出临界区时,再恢复进入临界区时的中断状态,即可完美解决。
具体实现代码如下:

uint32_t tTaskEnterCritical (void) 
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();        // CPSID I
    return primask;
}

void tTaskExitCritical (uint32_t status)
 {
    __set_PRIMASK(status);
}

7调度锁保护

设置一个变量实现调度保护,当该值大于0时,表示有任务请求禁止调度。

8位图

位图是一组连续的标志位,每一位用于标识一种状态的有无。

9多优先级任务

RTOS维护一个就绪表,每个表项 对应一个任务,对应一种优先级,就绪表指明哪些优先级的任务等待占用CPU运行,说白了其实就是通过将相应优先级对应的位图位置1来实现。

10 任务的延时队列

将所有需要延时的任务放入延时队列中,当发生定时中断时,去扫描该延时队列,依次对队列中各任务的延时时间-1.如果有减到0的,将其从延时队列中移除.

11 同优先级时间片运行

将原先位图一个位对应一个优先级的任务改为对应一个任务队列,并在每个任务中加入自己的时间片变量,用于实现同一优先级对应的多个任务按照时间片方式进行运行.具体实现如下图:

12任务的挂起

在任务的结构中增加一个挂起计数器,仅当计数器值大于0且该任务不处在延时状态时,才对任务进行挂起,如果该任务是当前正在运行的任务,则要对任务进行切换.挂起方式很简单,就是将其从就绪队列中移除.

13任务的删除

一,将任务从其所在延时队列,就绪队列中删除.
二,释放该任务所占用的资源.
设计一种机制,当发现任务要被删除时,释放掉该任务所占用的资源,包括内存空间,硬件设备等.
删除方式1,设置任务删除回调函数,由该函数释放.
删除方式2,设置删除请求标志,由任务自己决定何时删除.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,944评论 6 13
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,117评论 0 23
  • 我知道,其实你从来都不爱我 以前,我总会猜想, 你在做什么? 有没有花一点点时间, 用来思念我? 想我过得好不好?...
    露水恋人阅读 392评论 2 3
  • “我愿意为你,为你。” 我流着眼泪和你说的第一句话,是这句。 你知道吗,我一直在追逐你的脚步,像个傻子,更像疯子。...
    阿黎Aria阅读 639评论 0 5