Qsys与uC/OS-II学习笔记4:任务状态与工作机制
前面一个笔记我们已经可以轻松的使用EDS提供的HAL构建一个uC/OS-II的模板工程,在这个工程里,所有和移植有关的问题都不用我们操心,我们只要放心的去设计我们的应用程序便可。而一个最简单的uC/OS-II工程也已经呈现在我们面前,三个最基本的步骤就可以完成一个我们曾经以为多么神奇的操作系统。但是,虽然我们能够构建两个最基本的任务,但说实在话,我们还没搞懂它到底如何工作的,依葫芦画瓢没有错,若能够搞清楚它的工作机理就更好了。
本文引用地址:http://www.amcfsurvey.com/article/279415.htm先来回顾一下两个task,如下代码:
/* Prints "Hello World" and sleeps for three seconds */
void task1(void* pdata)
{
while (1)
{
printf("Hello from task1n");
OSTimeDlyHMSM(0, 0, 3, 0);
}
}
/* Prints "Hello World" and sleeps for three seconds */
void task2(void* pdata)
{
while (1)
{
printf("Hello from task2n");
OSTimeDlyHMSM(0, 0, 3, 0);
}
}
两个task的代码几乎如出一辙,他们都有自己的主循环while(1),而在while(1)里面都是先打印一串字符,然后调用uC/OS-II的任务延时函数。在打印结果上看,task1和task2的打印信息是不断的交错打印,没有哪个task会连续得到打印的机会,其奥秘就在于他们的任务延时是一致的。关于任务延时这里先不做文章,下篇笔记再详细探讨,这里我们只做一个和任务延时有关的小小测试,将task2的任务延时函数注释,如下修改task2的函数:
/* Prints "Hello World" and sleeps for three seconds */
void task2(void* pdata)
{
while (1)
{
printf("Hello from task2n");
//OSTimeDlyHMSM(0, 0, 3, 0);
}
}
重新编译软件工程,然后在硬件上在线运行,此时我们看到在Console中打印的字符串信息如图1所示。是不是很出乎我们的意料,没错,这个测试中我们就是要拿优先级低的task2来说事,在没有任务延时函数的task2中,虽然它的优先级没有task1高,但它却一直占有着CPU的控制权,这到底怎么回事?确实是任务延时函数在作怪,本笔记先不深入,只要大家先记住:任务延时的主要作用便是先把当前任务的CPU控制权释放,交给其他的优先级最高的就绪任务控制。该测试中,其实task1只是在刚启动系统的时候执行了一次,然后它调用任务延时函数将CPU控制权交出,这一交不要紧,task2就赖着不还了,因为task2在运行过程中自始至终没有调用任务延时,所以它将一直占用着CPU,当然了,这种状况可不是我们希望看到的。
图1
当前两个task,每个task通常也都要有自己的while(1),如同大多数裸奔的MCU一样,这又是为什么?裸奔着的MCU通常都只有一个main函数中的while(1)控制着CPU的使用权,CPU的寄存器也供它独享。而uC/OS-II却要改变这一状况,如图2所示,每个任务都有自己的堆栈和任务控制块,而CPU的控制权通常是轮流着使用的,话说“风水轮流转”嘛,也有这么点味道。当某个任务占用CPU使用权时,CPU的寄存器自然也是它独自享用,它可以将当前堆栈里面的数据对应搬移到CPU寄存器中执行,而其他的任务无论在此之前处于何种状态,都要把他们的数据存储中他们自家的堆栈中;一旦当前任务完成工作或者因为某种系统允许的任务切换情况出现,那么它就得乖乖的交出CPU使用权,把CPU寄存器中的当前数据搬回到自己的堆栈中。到底何时切换任务,何时抢占任务,这都由每个任务自己的任务控制块把持着,他们不会越权抢占别人的CPU控制权,当然也不会允许他人随意的抢走属于自己的CPU控制权。uC/OS-II内部的任务切换说白了就是CPU控制权的切换以及相应的入栈出栈操作,但是这其中涉及到的诸如任务优先权的轮换或者说任务仲裁等问题的处理机制就是非常体现功力的地方,后续有机会也要好好探讨下这方面的议题。
图2
前面我们谈到任务的切换,在同一时刻不同的任务都处于不同的状态,运行着的任务肯定只有一个,那么其他任务的状态都如何?如图3所示,uC/OS-II把任务的状态划分为5种:即睡眠态任务、就绪态任务、运行态任务、被中断态任务和等待状态任务。这里我们先简单的将这5种状态罗列,并没有将他们之间的转换关系示意处理,但各个不同状态之间的变化也都是通过一定的事件触发或者函数调用引起的。
图3
作者原著的《嵌入式实时操作系统uC/OS-II》一书中对这5种状态有如下描述:就绪态意味着任务已经准备好,可以运行,但由于该任务的优先级比正在运行的任务优先级低,还暂时不能运行;运行态是指任务掌握了CPU的使用权,正在运行;挂起态也称作等待状态任务,指任务在等待某一事件的发生(例如等待某外设I/O操作,等待某共享资源由暂不能使用变成能使用状态,等待定时脉冲的到来,或等待超时信号的到来以结束目前的等待,等等);发生中断时,CPU提供相应的中断服务,原来正在运行的任务暂不能运行,就进入了被中断任务。
就拿我们前面列举的实例来讲,当task1运行时,它处于运行态,task2就处于就绪态。而其他几种状态我们暂时还没有接触,后面遇到了再逐一谈论。
评论