VxWorks环境下基于Zinc的通信
d)派生设备
选用共享内存或消息队列作为通信方法时,Zinc需要与该通信方法进行交互,这可以通过派生设备实现。使用派生设备的目的是为了检查是否有来自另一个任务的通信。每当ZafEventManager::Get() 函数被调用,事件管理器轮询该设备,看看是否有新消息。这个派生设备仅仅需要检查共享内存或消息队列。如果有新信息可用,派生设备可以直接调用对象的 Event() 函数在队列上面放置一个新事件,也可以自己处理这个消息。
派生设备还可用于实现从GUI任务到非GUI任务的通信。
ZafEventManager::UnBlock()函数对这种通信方法是非常有用的。在正常的情况下,如果没有需要处理的事件,Zinc会阻塞自己。如果采用一个派生设备监听一个VxWorks消息队列,向该队列发送一个消息后解除事件管理器的阻塞可以更及时地轮询该派生设备。派生设备自身不会阻塞,也不会导致Zinc暂停。
3 选择通信方式的原则
上述关于GUI任务的通信方法各有其优缺点。在选择通信方法的时候,应该以具体的应用场合为依据,一般应遵循如下的原则:
a) 应该尽可能选用简单的通信方式。
在大多数情况下, Zinc入口点足够用。Zinc入口点是最简单的关于GUI任务的通信方式,因为它们不需要Zinc 任务内部的任何专门代码。可用的最简单入口点是ZafEventManager::Put()函数。然而,它有下列缺点:第一,它只允许从非GUI任务到 GUI任务的通信;第二,它是异步的;第三,因为要防止ZafEventManager::Get() 和ZafEventManager::Put()函数同时访问Zinc事件队列以对其进行保护, ZafEventManager::Put() 可能会阻塞。
如果异步通信是可接受的,但是不能接受阻塞,可以采用下列两种方法:第一,使用 ZafEventManager::Put ( )函数,并且另外有一个可被阻塞的任务向Zinc队列中放置事件。这个任务可以监听一个OS消息队列,而原先产生消息的任务正是使用OS消息队列来发送消息; 第二,创建一个设备以监听OS消息队列,产生消息的任务发送一个消息给OS消息队列,然后由派生设备接收并解释。派生设备可以放置一个事件在Zinc队列中,或者自己处理这个事件。只是这两种方法都给应用程序增加了一点复杂性。
b) 如果需要进行同步通信,必须使用函数对ZafApplication::BeginSynchronize() 和ZafApplication::EndSynchronize() 。
调用ZafApplication::BeginSynchronize()之后,可以保证对Zinc对象的任何访问是安全的。该方法很简单,且不需要在GUI任务中添加专门的代码。使用ZafApplication::BeginSynchronize() 的缺点是该函数会阻塞,使用该方法时必须采取预防措施。
c) 采用共享内存进行通信时必须创建保护和同步机制
共享内存是从GUI任务到非GUI任务的两种通信方法之一,其优点是对数据的访问简单而直接。共享内存没有对数据访问进行保护的内在支持,所以必须创建一个对访问进行保护及同步的机制,并且访问共享内存的所有任务都应该使用该机制。采取这种方案的缺点是容易发生阻塞。
d) 在不能接受阻塞的应用场合,最好使用OS消息队列。
OS消息队列是从GUI任务到非GUI任务和从非GUI任务到GUI任务进行通信的另一种方法。使用OS消息队列进行通信的时候,需要在GUI任务和非 GUI任务中编写访问消息队列的代码。在正确进行设置的情况下,消息队列不会引起阻塞的问题。创建消息队列时,必须保证消息队列有足够的消息容量或者建立处理消息队列溢出的机制。
4 Zinc的事件模型
Zinc中的GUI任务与非GUI任务的多种通信方式都与Zinc的事件模型有关,因此在设计和实现GUI任务与非GUI任务之间的通信时,需要对Zinc的事件模型有深入的理解。Zinc具有一个事件驱动的体系结构。输入设备与应用程序之间的交互是通过事件完成的。由于VxWorks本身不是事件驱动的实时操作系统,在VxWorks运行平台中, Zinc主要从输入设备和应用任务获取事件。
然后Zinc以标准的方式将这些事件打包,并且将它们路由给适当的对象以进行进一步的处理。在EGIS中, GSM通讯任务使用了自定义的事件与GUI任务进行异步通信。基于Zinc的EGIS事件模型如图1所示。
图1 基于Zinc的EGIS事件路由示意图
评论