当前位置:首页 > 嵌入式 > 嵌入式软件
[导读]进程调度是计算机的灵魂。在实时系统里,要使重要紧急的进程一经唤醒使被优先调度运行,系统就必须有基于进程优先级的实时调度策略。通过深入考察和对比μC/OS-II和Nut/O

进程调度是计算机的灵魂。在实时系统里,要使重要紧急的进程一经唤醒使被优先调度运行,系统就必须有基于进程优先级的实时调度策略。通过深入考察和对比μC/OS-II和Nut/OS对实时调度算法的实现,可以深刻理解实时操作系统。

如果说CPU是计算机系统的心脏,那么进程调度就是计算机系统的灵魂,因为它决定了如何使用CPU。例如,Linux是一个多任务操作系统,它的理想状况是保持CPU有效运行。如果某个正在运行的进程转入等待系统资源,操作系统就调度其他进程运行,从而保证CPU的最大利用率。如何使系统能够保证较短的响应时间和较高的吞吐量,使得多个进程竞争CPU时保持公平、高效,是通用操作系统所追求的目标。但对于实时操作系统而言,它的调度算法是基于POSIX规定的基于事件驱动优先级的调度算法,为了及时响应高优先级进程,它宁愿牺牲整体效率。

调度的实现可以分为2步来完成:

①何时启动调度,即解决调度启动时机的问题;

②怎么调度,按优先级调度就是要找到系统当前优先级最高的进程,然后进行上下文切换。

在实时系统中,只有当就绪进程集合发生变动时才有调度的需要,而就绪进程集合的变动只可能发生在几种情况下:

①运行中的进程受阻或自动放弃CPU;

②系统中新建了进程;

③运行中的进程“自杀”或“被杀”;

④运行中的进程唤醒了某个线程;

⑤中断服务子程序结束时唤醒了其他进程。

理想情况下,实时系统在有高优先级的进程转入就绪态时,就应该立即启动调度程序,响应高优先级进程。但实际上却存在着不可调度的时隙,称为不可调度窗口:

①正在进行进程切换,不能进行调度;

②中断响应期间,不能进行调度;

③进入临界区,不能进行调度;

④DMA期间CPU已被挂起,不可能进行调度。

在实时系统里,必须努力缩小不可调度窗口。

在调度启动的时机上,所有的实时操作系统基本一致。

那么接下来要做的就是寻找系统中当前最应该得到运行机会的进程,下面分别看一个最简单的和比较复杂的实现。

1 μC/OS-Il的实现

在μC/OS-II里。只允许有64个优先级且不同进程优先级互不相同。把64个优先级分成8组,数据结构位图OSRdyGrp反映着哪一些进程组中有就绪进程。另外,各个进程组的标志位在位图中的位置也是有规律的,位置靠右边的标志位代表优先级较高的进程组,只要从右到左扫描位图OSRdyGrp,碰到第一个非0的标志位就代表当前优先级最高的就绪进程所在的进程组。这样,就可以预先编制一个对照表,即数组。此数组就是OStJnMapTbl[](该表的详细描述可参阅参考文献的88~90页),以位图OSRdyGrp的数值为下标,就可以直接得到优先级最高者所属组号。

8个标志位共有256种不同组合,所以这个数组大小是256。为了便于与μC/OS-II源代码对照,把以OSRdyGrp的数值为下标,在OSTJnMapTbl[]数组中查得的值称为组号y。知道组号y以后,就可以以此为下标在OSRdyTbl[]中得到相应的组内位图。同理,以这个位图的数值OSRdyThl[y]为下标,又可以在OSUnMapTbl[]内查得该组内优先级最高者进程号。将组号和组内号拼合在一起,就得到了目标进程完整的进程号,即优先级。再以此为下标,就可以从OSTcBPrioTbl[]中得到指向目标进程控制块的OSTCBHighRdy。以下就是进程切换的工作了。

通过上面的分析,不难理解下面这样的语句了:

这个过程如此简洁,其根本原因是μC/OS-II严格按优先级调度,并且每个优先级只有一个进程。如果优先级的使用并非唯一,多个线程可以使用相同的优先级,那就还有个相同优先级的就绪进程之间怎样调度的问题,这就使调度过程复杂化了。一些商品的实时操作系统,例如VxWorks,允许多个进程具有相同的优先级,因为不支持不同进程可以有相同优先级的系统,无法采用优先级继承算法来解决实时系统里令人讨厌的优先级反转现象,但它不公开源代码。下面选择一个公开源代码的实时操作系统Nut/OS进行分析。它有256个优先级且允许不同进程具有相同的优先级。在这样的系统里,是不可能采用类似于位图这样的机制来实现调度的。

2 Nut/OS的实现

为了叙述方便,设计一个完整的进程运行的情景来说明。另外Nut/0S中采用了线程的概念,在不分系统空间和用户空间的系统中,进程等价于线程。而进程和任务本来就是同一个概念的不同叫法。Nut/Os是一个嵌入式实时操作系统,不分系统空间和用户空间,所以以下的叙述中,线程、进程和任务混用,意思完全一样。

在Nut/OS中,可以通过下面的函数创建一个线程:

创建一个线程的过程,实际上就是从堆栈空间中申请一个放置线程控制块的空间,在这个空间中建立线程控制块并完成对控制块的赋值的过程。为了更好地说明线程控制块的作用,下面用一个图表来说明,如图1所示。

如果创建成功,NutThreadCreate()将返回一个指向新创建的线程控制块的指针,新创建的线程控制块将放置在线程控制块链表前面,nutThreadList指针总是指向这个链表的第一个控制快。现在假设某一个应用中只有3个线程,1个隐藏线程、1个主线程和1个应用线程。其中隐藏线程(threads3)中创建了主线程(Threads2),主线程中又创建了应用线程(Threadsl)。由于一开始只有一个隐藏线程,因此nutThreadList链表指向了隐藏线程。当隐藏线程创建了主线程时,主线程控制块添加在隐藏线程控制快链表的前面,因此nutThreadList链表指向主线程。当主线程创建了应用线程,应用线程控制块添加在主线程控制块的前面,因此nutThreadList链表改为指向应用线程。这就组成了一个如图2所示的链表。[!--empirenews.page--]

由图2可知,Nut/OS采用4个链表来管理系统中的全部线程,其中runQuene总是指向全部就绪线程链表,这个链表由td_qnxt指针链成。td_qnxt链表与td_next链表形成机制不同。在td_next链表中,新创建的线程总是简单地放在链表的前面,这个链表包括所有的线程控制块;而td_qnxt链表是根据优先级顺序排序的,一个线程只有处于就绪态(TDs_READY)或者运行态(TDS_RUNNING)才能包括在这个链表中。

隐藏线程的优先级为254,并且总是将该线程的td_next和td_qnxt设为空指针。线程的退出机制就是将要退出的线程的优先级设为255。由于这个线程的优先级比隐藏线程还低,而隐藏线程又没有指向该线程的指针,因此这个退出线程永远也不可能被运行。

按优先级调度是通过mnQuene链表来实现的。Nut/OS提供了2个API来操作这个链表,其中插入操作的代码如下:

该API函数表明,runQuene链表是一个按优先级排序的链表,优先级高的线程控制块总是在最前面,当发现有相同优先级的线程控制快时,总是把后来的插到相同优先级线程控制块的最后面。这就自然实现了对相同优先级线程按先来先服务的算法进行调度。

当就绪进程集合发生变动时,则调用NutThreadRemoveQueue()、NutThreadAddPriQueue()完成链表的更新让runQuene指向更新后的链表头。接下来的事就是上下文切换了。

通过链表这个简单的数据结构,Nut/OS也很简洁地实现了实时调度算法。阅读过Linux源代码的人对链表的重要性可能更是感同身受,虽然Linux操作系统堪称完美,但源代码却并不怎么规范,事实上造成了Linux源代码复杂难懂;而同是开源的Nut/OS,代码却相当规范,给我们提供了非常好的学习资料。笔者在这里感谢该系统的开发人员Harald Kipp和沈文先生等,以及那些热爱开源并热心奉献的工程师。

结语

μC/OS-II的实时性已经通过了非常严格的测试,事实上成了笔者比较其他系统实时性能的一个基准。在这次毕业设计工作中,采用Nut/OS实现8位机接入以太网,运行良好。不妨推测,在一些商品实时操作系统里,对优先级调度算法的实现采用的机制和Nut/OS是类似的。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭