首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

一种实时多任务系统软件设计方法(1)

一种实时多任务系统软件设计方法(1)

摘要:从进程和线程调度的角度出发,介绍了一种规范化的实时多任务系统软件设计方法,提出了“前向分支”的设计原则,给出了完整的系统模型。
关键词:线程拆分 前向分支 实时多任务 单片机
在机电产品研制开发中,经常要涉及到基于嵌入式系统或基于单片机系统的程序设计。实时多任务是这类系统最基于的要求之一。在实践中通常采用以下两种解决方案:

一是在商业化时操作系统的基础上进行二次开发;二是用户自动设计系统软件。前者设计工作量小,设计周期短,系统的设计质量也容易得到保证。但由于商业实时操作系统往往较多地考虑通用性,缺乏灵活性,对于一些特定的应用场合,其性能往往不能令人满意。同时,这种方案还存在着成本高,依赖于特定硬件等缺点。第二种方案可以从系统的实际要求和硬件的实际情况出发灵活地进行系统设计,易于满足一些特定场合的性能要求,成本也较低。但是,由于缺乏系统化、规范化的设计方法,缺少高层次抽象工具,使得系统的设计质量不容易得到保证,你严重地依赖于程序员的水平和经验。
本文针对上述第三种方案的高限,从进程和线程调度的角度出发,介绍了一种系统化、规范化和易于工程化实施的实时多任务系统软件设计方法,提出了“前向分支”的设计原则,并给出了完整的系统模型。
1 进程的划分
对复杂的系统需求进行模块化和层次化的划分是软件设计的基本方法。在实践中复杂的系统需求通常被划分为一些功能相对独立的任务模块,每个任务模块被视作一个进程(process)。系统中如有多个进程并发(concurrent)运行,该系统就是一个多任务的系统。在图1所示的例子中,n个任务模块构成了宏观上并发运行的一组进程(即Proc_1~Proc-n)。Proc_5和 Proc_9是两个具有代表性的进程结构。Proc_5是断续进行的进程,表示了某一顺序逻辑控制的流程。Proc_9是LCD汉字显示程序,其结构是典型的多重循环。其功能是将数组aDisplay中所描述的24×24点阵中文字符串送至LCD显示屏。ADisplay的结构参几图3(e)。

Proc_9 的基本工作原理如下:当cDispiay不为0时,依次从aDlsplay中取出每个待显示汉字的点阵位置及其在LCD内部显存中的地址,根据这两个参数将一个汉字的点阵顺序发送到LCD内部显存中。直至全部汉字显示完,cDisplay减为0,Proc_9转入空档状态,等待新的显示请求。
系统程序的主要任务之一就是对进程进行调度,包括启动和终止进程、管理进程之间的通讯、处理进程之间的优先级等。但是如果按图1的结构顺序调度进程、以进程为基本单位分配CPU时间的话,显然存在严重的问题。例如在Proc_5中,当程序处于等待K1闭合的状态时,其它任何进程都无法得到服务,尤其当K1出现故障时,系统将处于“挂起”状态。如果一个进程过多地占据了CPU时间,其他进程将不能得到公平、均匀的服务,响应时间无法得到保证,系统效率会降低。总之,只有将CPU时间的分配单位减小,才能解决上述问题。
2 线程的拆分
线程(Thread)是CPU的基本执行单位。一个进程可以由一个或多个线程构成。如前所述,单一线程的进程可能会存在诸多问题,而将一进程拆分为多个线程是解决上述问题的有效手段。由图1的Proc_5和Proc_9可以看出,一个进程过多地占据CPU时间,是因为其中含有次数不确定的等待循环、纯延时和较为耗时的多重循环。其中,纯延时可以用软件延和中断定时两种方法实现,这两种方法在进程中又都可以归结为循环。因此,在拆分线程时应尽量遵循“前向分支”原则,使线程中不含有或少含有循环。
循环结构本质上是由一个分支判断和一个“反向”转跳构成的。所谓“前向分支”原则是指:在一次调度中,当程序发生雪支时,应使程序跳向一段未被执行过的代码,而不得重复运行已运行过的代码。如果严格按“前向分支”原则拆分线程,循环结构将被完全消除。图2和图3分别是Proc_5和Proc_9严格按“前向分支”原则拆分为线程的结果。
如果进程设计遵循结构化程序思想,那么在对某一进程严格按“前向分支”原则进行线程拆分时,最小拆分数量可按如下方法确定:进程入口至第一个循环返回节点之间如无程序代码,最小拆分数量等于循环返回节点数Nback;进程入口至第一个循环返回节点之间如有程序代码,最小拆分数量等于Nback+1。实际拆分数量可以大于最小拆分数量,但不应小于该数,
否则必然有一个以上的线程中含循环。两个循环返回节点之间(或入口到第一个循环返回节点之间、最后一个循环返回节点到出口之间)的代码就构成了一个线程的对待。如果原进程中无循环,可将该进程当做单一线程对等。在图1中,Proc_9中共有4个循环返回节点(①~④),Nback=4。按最小拆分数量拆分中循环返回节点数也为4,但其入口至第一个循环返回节点之间有代码,所以,Proc_5按最小拆分数量拆分为5个线程。
线程号变量tProc_n是系统中实现线程调度、在各相关线程间建立联系的核心。按“前向分支”原则进行线程拆分时,凡是遇到构成循环的“反向”分支时,就将该分支转向当前线程的出口,并在出口前为所在进程的线程号变量赋一新值指向要转去的线程。如果所要转去的线程与当前所在线程一致时,线程号变量赋值可以省略。
在按“前向分支”原则设计的线程中,“结构上”的循环可以完全消除,但进程设计中“逻辑上”的循环仍然是存在的,否则进程的原有功能将不能正确地实现。事实上,线程号变量中包含有“逻辑循环”的信息。只要在主循环中按图4的方法设度各线程就可以实现进程的“逻辑循环”。
为实现中断定时,Proc_5中设置了两个定时计数器cTimerAct_1和cTimerAct_2(以下称之为“动作定时器”),在启动定时器设置好其初值,由一个基础定时中断程序按一定的时间间隔(本例为1ms)减1。当动作定时器减为0时表示定时结束。
对于继续运行的进程(如Proc_5),结束任务时应将线程号为量指向任意一个不用的空线程。为统一和方便起见,本文约定所有进程的0号线程均为空线程,进程结束时线程号变量应置为0。
返回列表