实时操作系统任务间通信的设计与分析
卢燕青 张宇飞
实时操作系统的核心是支持并发任务调度、提供任务同步和通讯机制。在具体实现时,一般应考虑尽可能减少系统本身的开销,任务调度、任务间通信和中断处理等系统公用程序也应精练有效。其任务间的通信,主要涉及共享数据结构的选择、任务间通信机制的实现、临界区域的保护以及死锁的预防等问题。
共享数据结构
在多任务系统中,共享内存是任务间通信最简单、最迅速的方法。特别是在实时操作系统环境下,高优先级任务与低优先级的任务共享同一块内存时,经常会造成共享数据的冲突。因此,在设计任务间的通信时必须考虑特殊的缓冲区数据结构来避免共享数据冲突。
“乒乓”缓冲结构
在传送与时间相关的数据时(例如数据处理速度大于数据的输入速度),一般采用“乒乓”缓冲结构。它由两块缓冲区构成,通过硬件或软件来控制两个缓冲区间的切换。其典型应用有磁盘控制器、图形接口卡等设备。
环缓冲结构
环缓冲结构类似于FIFO表,但它比FIFO表易于管理。在环缓冲结构中,并发的输入和输出可用通过头尾指针来控制。数据从尾指针处写入,从头指针处读出。
环缓冲结构与信号灯一起使用可以控制资源的并发使用。例如在访问内存、打印机等资源时,可以将资源的请求置于尾指针指向的存储区,资源分配程序从头指针中取出数据后按照请求分配资源。
任务间通信的设计
邮箱及其实现
邮箱是大多数多任务操作系统任务间通信的一种方式。它是公认的一块内存区域,由一个集中调度者来控制各任务对其的读写,从而实现任务间传递数据的目的。任务可以通过post操作来写这块内存,或通过pend操作来读取这块内存的数据。这种pend操作与简单轮询邮箱的区别在于:前者在等待数据时处于挂起(suspend)状态,不占用任何CPU资源;后者则是占用CPU,不停地检查邮箱。邮箱传递的数据一般是一个标志(flag)、单个数据,或者是指向链表或队列的指针。在具体实现时,数据一旦从邮箱读出来,邮箱就置成空状态。这样,尽管有多个任务能对同一个邮箱执行pend操作,但只有一个任务能从邮箱中取出数据。
在基于任务控制块模型的任务管理系统中,邮箱是最容易实现的。所谓任务控制块,就是保存有任务的各种信息的数据结构。当任务状态发生改变时,其任务控制块内容相应发生变化。在这种模型中,一般都有一个监管任务和两个列表(任务资源列表和资源状态列表),任务资源列表和资源状态列表保持协调一致。例如,在表1和表2中,存在着的资源有打印机及两个邮箱。打印机正在被任务100使用,邮箱1被任务102使用,邮箱2处于空闲状态。
|
任务id |
资源 |
状态 |
|
100 |
打印机 |
占用 |
|
102 |
邮箱1 |
占用 |
|
104 |
邮箱2 |
pend |
|
资源 |
状态 |
使用者 |
|
打印机 |
忙 |
100 |
|
邮箱1 |
忙 |
102 |
|
邮箱2 |
空闲 |
无 |
|
设备 |
次序号 |
|
磁盘 |
1 |
|
打印机 |
2 |
|
监视器 |
3 |