微型机与应用
MICROCOMPUTER & ITS APPLICATIONS
2000　Vol.19　No.6　P.8-9,24




Windows 9x 准实时通信与控制系统设计
马卫东　王志颖
摘要：在 Windows 9x 中开发设计与底层硬件有关的实时、准实时通信与控制软件系统的方法。对 Windows 9x 设备驱动程序VxD编程、动态连接库接口、Win32 程序设计、任务调度亦进行了较为深入的探讨。
关键词：Windows 9x 　准实时通信　设备驱动程序　事件　线程　任务调度
　　Windows 9x是运行在80386及其后继产品上的通用桌面计算机图形用户界面操作系统。它支持抢先式多任务、多线程、虚存管理、局域网络、TCP／IP协议、Internet等丰富的功能，已成为应用最广泛的桌面操作系统。
　　但Windows 9x是为通用桌面计算机设计的操作系统，并不是为实时任务设计的，因而无法通过简便的程序设计方法直接创建实时通信与控制任务。由于在工业、交通、国防等许多测控部门都要求进行实时任务处理，许多原来在DOS系统开发的实时任务处理程序亦存在如何移植到Windows 9X平台上来或重新实现的问题，本文就这些问题进行了探讨。
1  Windows 9x操作系统结构简述
　　Windows 9x运行在80x86保护模式下，其操作系统核心代码(如线程调度、存储管理、设备驱动等程序)运行在拥有特权级的核心态(Ring 0级)，操作系统的其它代码(如GUI程序等)和用户进程运行在用户态(Ring 3级)。其基本结构如图1所示。

图1  Windows 9x操作系统结构图
　　Windows 9x操作系统能够同时运行MS－DOS程序、Win16程序和Win32程序，彼此间互不干扰，并发执行。这里建议在Windows 9x下开发应用程序，首选Win32程序。Windows 9x为Win32应用程序提供了32位高达4GB的全线性虚拟地址空间，这对一般应用来讲提供了足够大的可用内存(尽管计算机物理内存的容量在一般情况下要小得多)。
　　Windows 9x操作系统由其核心、设备驱动程序和大量的动态链接库及应用程序组成。Windows 9x内核与设备驱动程序运行在保护模式的Ring 0级或称为核心态，而一般应用程序与动态链接库运行在Ring 3级或称为用户态。熟悉80386保护模式体系的人都知道，Ring3代码不能直接调用Ring 0代码。Windows 9x给Win32应用程序调用设备驱动程序提供了一个标准调用，即用设备文件句柄和硬件设备驱动程序通信。设备文件句柄通过标准Win32 API调用CreateFile，然后可以使用ReadFile与WriteFile从设备中读写内容，使用DeviceIoControl控制设备驱动程序的具体操作。
　　在Windows 9x操作系统中与硬件设备打交道的程序代码必须运行在核心态(Ring 0级)。事实上这些代码就是Windows 9x中的设备驱动程序，运行在用户态(Ring 3级)的代码必须通过核心态(Ring 0级)代码才能访问硬件。通常即使在用户态(Ring 3级)执行的所谓输入输出指令(in，out等)实际上也隐含调用了核心态(Ring 0级)代码得以执行的。
　　所以，在Windows 9x中开发设计与底层硬件有关的实时通信与控制软件系统是和如何构造良好性能的设备驱动程序息息相关的。专用的实时通信与控制设备驱动程序当然非常高效方便，然而其编制却是非常困难复杂的。事实上，在许多测控部门并不要求严格的实时控制，而仅需要秒级或毫秒级的响应控制时间，这里称之为准实时通信控制系统。对准实时通信控制系统有一种简便有效的实现途径，即构造一个标准的设备驱动程序VxD及一组通信控制动态链接库API，使得对设备测控代码由运行在用户态的应用程序完成，保证响应时间在毫秒级。
2  准实时通信与控制软件系统设计
2.1 实现原理
　　Windows 9x操作系统是以线程为其基本调度单位，通常以20ms为基本时间片按优先级大小对线程进行调度。当一个进程被创建的同时也创建了1个主线程、0个或多个从线程，每个线程必须从属于一个优先级类，并指定其优先级。优先级0～5属于IDLE＿PRIORITY＿CLASS优先级类，为IDLE程序(如屏幕保护进程)使用；优先级6～10属于NORMAL＿PRIORITY＿CLASS优先级类，为通常应用程序使用；优先级11～15属于HIGH＿PRIORITY＿CLASS优先级类，为内核线程使用；优先级16～31属于REALTIME＿PRIORITY＿CLASS优先级类，为实时任务使用。因此，一个优先级中有几个级别，包括16个实时级别、15个变量级别、1个系统级别和1个空闲级别。
　　Win32提供了若干种同步对象(如临界区、互斥量、信号量和事件)，以便让线程相互之间能够同步。通过将同步对象和优先级配合使用，可以巧妙地设计和实现多个线程的并发操作，其中有一个高优先级线程时刻准备处理外部突发事件，一旦有事件到来(事件由底层的设备驱动程序激活)立刻投入运行。由于Windows 9x支持抢先式多任务，拥有较高优先级的线程优先投入运行，在一个分片周围内，该线程即可投入运行。这样就实现了准实时通信与控制，其实现原理如图2所示。

图2  准实时通信与控制实现原理图
2.2 实现途径
　　准实时通信与控制的实现需要解决几个关键问题，如线程同步调度、事件同步驱动的建立、应用层与核心驱动程序通信、设备驱动程序编制、如何将应用层的事件对象传递给设备驱动程序、如何在设备驱动程序中激活事件以便使等待激励事件的测控线程立刻投入运行等等。在Win32 SDK与Win32 DDK中可以找到相关文档解决这些难题。限于篇幅，下面就几个关键问题作些讨论。
2.2.1 事件对象与线程同步
　　一个线程使自己与其它线程同步的方法就是使自己睡眠。在此之前，它必须告诉操作系统一旦有什么“特殊事件”发生，它必须被唤醒以便继续执行。操作系统在使该线程睡眠后将一直监视这一“特殊事件”是否发生以及何时发生，并在它发生时唤醒该线程并使线程在所有就绪状态线程中按优先级调度得以继续执行。此时，该线程就使得其执行与事件的发生取得了同步。
在Win32中提供了几个API调用以实现该功能，常用的有如下2个函数：
　　DWORD　WaitForSingleObject (HANDLE hHandle，DWORD dwMilliseconds)；
　　DWORD WaitForMultipleObjects(DWORD nCount，CONST HANDLE *lpHandles，BOOL fWaitAll，DWORDdwMilliseconds)；
　　WaitForSingleObject函数的第一个参数为同步对象句柄；第二个参数为等待时间，通常为INFINITE。这里使用事件对象作为同步对象。事件一般使用CreateEvent函数创建，可以采用全局唯一的有名事件或进程内部使用的无名事件，事件一般可用SetEvent等函数触发。
2.2.2 设备驱动程序中触发Win32事件
　　在设备驱动程序中触发Win32事件要考虑许多实现细节并需要采用汇编语言实现。限于篇幅，这里简单介绍其核心调用：
　　VxDcall ＿VWIN32＿SetWin32Event
　　其功能是设置指定的事件对象为发信号状态。如果它是一个手动复位事件，它将保持在发信号状态直到它被明确地复位且当前所有因为该事件而阻塞的线程全部标为非阻塞；如果它是一个自动复位事件，则有一个等待线程被标为非阻塞状态。调用时使用EAX、ECX、EDX和Flags寄存器。如果调用成功，则在EAX寄存器中返回非零值，否则为失败。
　　表示VxD事件对象的句柄存入EAX中，1个VxD句柄是1个由Win32函数OpenVxDHandle创建的ring 0句柄(详见2.2.3节)。
　　注意，该服务仅在当前虚拟机是系统虚拟机时才能够被调用。
2.2.3 Win32与核心对象句柄的转换
　　在Windows 9x提供的kernel32.dll动态链接库中，有一个未公开的API调用即OpenVxDHandle，它的作用就是将在Win32程序中使用的句柄转换为核心设备能够使用的句柄。于是在核心运行的代码与Win32中运行的代码可以操作同一个对象。该函数原型如下：
　　DWORD ＿cdecl OpenVxDHandle（HANDLE hSource）；
　　用如下方法可以获取该API调用：
　　typedef UINT(CALLBACK*LPFNDLLFUNC1)(DWORD)；
LPFNDLLFUNC1 lpfnDllFunc1；／／Function pointer
　　　　　　　　　　　　　／／DWORD dwParam1；
　DWORD uReturnVal；
　DWORD ＿cdecl myOpenVxDHandle（HANDLE hSource)
　｛
　　HINSTANCE hDLL； ／／Handle to DLL
　　hDLL＝LoadLibrary（″Kernel32.DLL″）；
　　if（hDLL!＝NULL)
　　｛
　　　　lpfnDllFunc1＝(LPFNDLLFUNC1)GetProcAd－dress(hDLL，″OpenVxDHandle″)；
　　if(！lpfnDllFunc1){ ／／handle the error
　　　　　　FreeLibrary(hDLL)；
　　　　　　return 0；
　　　　｝
　　else
　　　　｛ ／／call the function
　　　　uReturnVal＝lpfnDllFunc1(hSource)；
　　　　｝
　　｝
　　}
2.2.4 设备驱动程序的编制
　　编制设备驱动程序主要使用Win32 DDK，当然也有一些第三方厂家提供的较为便宜的集成化开发工具。有关设备驱动程序的编制需要较多篇幅来介绍，这里就不细述了。
3  结束语
　　在Windows 9x中开发设计与底层硬件有关的实时、准实时通信与控制软件系统是一项很有意思的工作。在编制测控软件、数据同步传输软件等方面的应用中，该设计思想使我们取得了事半功倍的效果，本文给出的设计思路具有广泛的实用价值。
马卫东（中国工程物理研究院计算机应用研究所　621900）
王志颖（中国工程物理研究院电子工程研究所）
收稿日期：1999-12-28
