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事件路由示意圖
評論