作者:魏永明 選擇MiniGUI-Threads 或者 MiniGUI-Lite 自 MiniGUI 從 1998 年底推出以來,越來越多的人開始選擇 MiniGUI 在 Linux 上開發實時嵌入式系統。為了幫助嵌入式軟件開發人員使用 MiniGUI編寫出更好的應用程序,我們將撰寫一系列文章講解基於 Linux 和 MiniGUI 的嵌入式系統軟件開發,並冠名"基於 Linux 和 MiniGUI 的嵌入式系統軟件開發指南"。本文是該系列文章的第一篇,將講述如何針對具體項目選擇使用 MiniGUI-Threads 或者 MiniGUI-Lite 版本,並比較不同版本對系統軟件結構的影響。 1:引言 自 MiniGUI 從 1998 年底推出以來,越來越多的人開始選擇 MiniGUI 在 Linux 上開發實時嵌入式系統。MiniGUI 系統也逐漸成熟,並在各種嵌入式系統中扮演了重要的角色。為了幫助嵌入式軟件開發人員使用 MiniGUI編寫出更好的應用程序,我們將撰寫一系列文章講解基於 Linux 和 MiniGUI 的嵌入式系統軟件開發,並冠名"基於 Linux 和 MiniGUI 的嵌入式系統軟件開發指南"。該系列文章將講述如何在基於 Linux 的系統上利用 MiniGUI 開發具有圖形用戶界面支持的嵌入式系統軟件,其內容不僅僅限於 MiniGUI 的編程,還會涉及到一些 Linux 下嵌入式系統軟件開發的技巧。系列文章的初步規劃如下: 如何針對特定項目選擇 MiniGUI-Threads 和 MiniGUI-Lite 理解消息循環和窗口過程 對話框和控件編程 使用 GDI 函數 MiniGUI 和 Linux 系統調用 MiniGUI-Lite 與進程間通訊 將 MiniGUI 及應用程序移植到特定平台 利用 autoconf 接口編寫跨平台代碼 如何調試 MiniGUI 應用程序 本文是該系列文章的第一篇,將講述如何針對具體項目選擇使用 MiniGUI-Threads 或者 MiniGUI-Lite 版本,並比較不同版本對系統軟件結構的影響。 2:MiniGUI-Threads 和 MiniGUI-Lite 的區別 大家都知道,我們可以將 MiniGUI 編譯成兩個截然不同的版本,一個是 MiniGUI-Threads,一個是 MiniGUI-Lite。這兩個版本適用於不同的應用需求。在選擇到底使用 MiniGUI-Threads 還是 MiniGUI-Lite 之前,我們首先需要了解這兩個版本之間的區別。 MiniGUI-Threads 是 MiniGUI 的最初版本。MiniGUI 最初為一個工業控制系統開發的,該系統功能單一,但卻需要非常高的實時性,因此考慮將 MiniGUI 開發成一個基於多線程的圖形用戶界面支持系統。因為在傳統的 UNIX/Linux 系統上,典型的 GUI 系統(比如 X)采用傳統的基於 UNIX 套接字的客戶/服務器系統結構。在這種體系結構下,客戶建立窗口、繪制等等都要通過套接字傳遞到服務器,由服務器完成實質工作。這樣,系統非常依賴於 UNIX 套接字通訊。而大家都知道,UNIX 套接字的數據傳遞,要經過內核,然後再傳遞到另外一個程序。這樣,大量的數據在客戶/內核/服務器之間傳遞,從而增加了系統負荷,也占用了許多系統資源。這對許多嵌入式系統,尤其是實時性要求非常高的系統來說,是不可接受的。 為了解決這個問題,MiniGUI 首先采用了線程機制(類似Windows CE),所有的應用程序都運行在同一個地址空間,這樣,大大提高了程序之間的通訊效率,並且特別適合於實時性要求非常高的系統。這就是 MiniGUI-Threads。基於 MiniGUI-Threads 的程序,可以具有多個線程,每個線程有不同的功能和任務,並且可以建立各自的窗口,不同的線程之間,可以通過 MiniGUI 提供的消息傳遞機制進行事件傳送和同步。 但顯然,這種基於線程的結構也導致了系統整體的脆弱――如果某個線程因為非法的數據訪問而終止運行,則整個進程都將受到影響。不過,這種體系結構對實時控制系統等時間關鍵的系統來講,還是非常適合的。 為了解決 MiniGUI-Threads 版本因為線程而引入的一些問題,同時也為了讓 MiniGUI更加適合於嵌入式系統,我們決定開發一個 MiniGUI-Lite 版本。這個版本的開發目的是: 保持與原先 MiniGUI 版本在源代碼級 99% 以上的兼容。 不再使用線程庫。 可以同時運行多個基於 MiniGUI-Lite 的應用程序,即多個進程,並且提供前後台進程的切換。 顯然,要同時滿足上述三個目的,如果采用傳統的 C/S 結構對MiniGUI-Threads 進行改造,應該不難實現。但前面提到的傳統 C/S 結構的缺陷卻無法避免。經過對 PDA 等嵌入式系統的分析,我們發現,某些 PDA 產品具有運行多個任務的能力,但同一時刻在屏幕上進行繪制的程序,一般不會超過兩個。因此,只要確保將這兩個進程的繪制相互隔離,就不需要采用復雜的 C/S 結構處理多個進程窗口之間的互相剪切。也就是說,在這種產品中,如果采用基於傳統 C/S 結構的多窗口系統,實際是一種浪費。 有了上述認識,我們對 MiniGUI-Threads 進行了如下簡化設計: 每個進程維護自己的主窗口 Z 序,同一進程創建的主窗口之間互相剪切。也就是說,除這個進程只有一個線程,只有一個消息循環之外,它與原有的 MiniGUI 版本之間沒有任何區別。每個進程在進行屏幕繪制時,不需要考慮其他進程。 建立一個簡單的客戶/服務器體系,但確保最小化進程間的數據復制功能。因此,在服務器和客戶之間傳遞的數據僅限於輸入設備的輸入數據,以及客戶和服務器之間的某些請求和響應數據。 有一個服務器進程(mginit),它負責初始化一些輸入設備,並且通過 UNIX Domain 套接字將輸入設備的消息發送到前台的 MiniGUI-Lite 客戶進程。 服務器和客戶被分別限定在屏幕的某兩個不相交矩形內進行繪制,同一時刻,只能有一個客戶及服務器進行屏幕繪制。其他客戶可繼續運行,但屏幕輸入被屏蔽。服務器可以利用 API 接口將某個客戶切換到前台。同時,服務器和客戶之間采用信號和 System V 信號量進行同步。 服務器還采用 System V IPC 機制提供一些資源的共享,包括位圖、圖標、鼠標、字體等等,以便減少實際內存的消耗。 從傳統 C/S 窗口系統的角度看,MiniGUI-Lite 的這種設計,無法處理達到完整的多窗口支持,這的確是一個結構設計上的不足和缺陷。不過,這實際是 MiniGUI-Lite 不同於其他窗口系統的一個特征。因為處理每個進程之間的互相剪切問題,將導致客戶和服務器之間的通訊量大大增加,但實際上在許多嵌入式系統當中這種處理是沒有必要的。在類似 PDA 的嵌入式系統中,往往各個程序啟動後,就獨占屏幕進行繪制輸出,其他程序根本就沒有必要知道它現在的窗口被別的進程剪切了,因為它根本就沒有機會輸出到屏幕上。所以,在 MiniGUI-Lite 當中,當一個進程成為最頂層程序時,服務器會保證其輸出正常,而當有新的程序成為最頂層程序時,服務器也會保證其他程序不能輸出到屏幕上。但這些進程依然在正常執行著,不過,服務器只向最頂層的程序發送外部事件消息。 表 1 給出了 MiniGUI-Threads 和 MiniGUI-Lite 的區別。從表中總結的區別看來,MiniGUI-Threads 適合於功能單一、實時性要求很高的系統,比如工業控制系統;而 MiniGUI-Lite 適合於功能豐富、結構復雜、顯示屏幕較小的系統,比如 PDA 等信息產品。 表 1 MiniGUI-Threads 和 MiniGUI-Lite 的區別 MiniGUI-Threads MiniGUI-Lite 多窗口支持 完全 不能處理進程間窗口的剪切,但提供進程內多窗口的完全支持 字體支持 支持點陣字體(VBF、RBF)和矢量字體(Adobe Type1 和 TrueType) 目前尚不支持對 Adobe Type1 和 TrueType 等矢量字體的支持 線程間消息傳遞 通過 MiniGUI 的消息函數,可在不同的線程之間傳遞消息 未考慮多線程應用,不能直接通過 MiniGUI 消息函數在不同線程之間傳遞消息 多線程窗口 MiniGUI 能夠處理不同線程之間的窗口層疊 不能處理多線程之間的窗口層疊 其他 基於線程的 C/S 結構,系統健壯性較差,因此要求系統經過嚴格測試 采用 UNIX Domain Socket 的基於進程的 C/S 結構,可建立健壯的軟件架構。並提供了方便的高層 IPC 機制 除上表中列出的不同之外,MiniGUI-Threads 和 MiniGUI-Lite 的 API 是一致的。 3:MiniGUI-Threads 的典型應用和軟件架構 本文介紹的基於 MiniGUI-Threads 典型應用是一個計算機數字控制(CNC)系統。這個系統是由清華大學基於 RT-Linux 建立的機床控制系統。該系統使用 MiniGUI-Threads 作為圖形用戶界面支持系統。圖 1 是該 CNC 系統的用戶界面。 點擊查看大圖 圖 1 清華大學基於 RT-Linux 和 MiniGUI 的數控系統主界面 圖 2 是該系統的架構。在用戶層,該系統有三個線程,一個作為 GUI 主線程存在,另一個作為監視線程監視系統的工作狀態,並在該線程建立的窗口上輸出狀態信息,第三個線程是工作線程,該線程執行加工指令,並通過 RT-Linux 的實時 FIFO 和系統的實時模塊進行通訊。 圖 2 清華大學基於 RT-Linux 和 MiniGUI 的數控系統架構 4:MiniGUI-Lite 的典型應用和軟件架構 這裡介紹的典型應用是一個基於 MiniGUI-Lite 的 PDA。該 PDA 由國內某公司基於 Linux 開發,其上可以運行各種 PIM 程序、浏覽器以及各種游戲程序。圖 3 是該 PDA 的用戶界面。 圖 3 某公司開發的基於 MiniGUI 的 PDA 軟件界面 該系統中的所有應用程序都以 Linux 進程的形式執行,mginit(即 MiniGUI-Lite)提供了輸入法支持和應用程序管理功能。當應用程序之間需要通訊時,可以通過 MiniGUI-Lite 所提供的 request/response 接口實現。圖 4 是該系統的架構。 圖 4 某公司開發的基於 MiniGUI 的 PDA 軟件架構 5:小結 本文講解了 MiniGUI-Threads 和 MiniGUI-Lite 之間的區別,並舉例說明了基於這兩個不同版本的不同軟件架構。嵌入式程序開發人員必須明白這兩個版本之間的區別,並針對具體應用恰當選擇使用哪個版本