周春華
(解放軍理工大學 野戰(zhàn)工程學院,南京 210007)
一種事件驅(qū)動型嵌入式軟件框架設(shè)計
周春華
(解放軍理工大學 野戰(zhàn)工程學院,南京 210007)
提出了一種事件驅(qū)動型嵌入式軟件設(shè)計框架,抽象并實現(xiàn)了嵌入式軟件程序中包括基于優(yōu)先級的任務(wù)調(diào)度、基于消息隊列的任務(wù)間通信、發(fā)行-訂閱服務(wù)、共享資源訪問和系統(tǒng)定時器服務(wù)等在內(nèi)的公共功能,簡化了嵌入式軟件的應(yīng)用程序設(shè)計。
嵌入式軟件;事件驅(qū)動;軟件框架
嵌入式軟件程序通常采用面向過程方式開發(fā),然而隨著芯片成本的降低和需求的日益提高,嵌入式軟件程序規(guī)模越來越來大,這種開發(fā)方式越來越難以駕馭日漸復雜的嵌入式軟件程序,軟件工程中的面向?qū)ο笤O(shè)計思想和應(yīng)用程序框架設(shè)計理念開始逐漸成為嵌入式軟件開發(fā)的重要方向。
本文提出了一種事件驅(qū)動型嵌入式軟件框架,該框架抽象并實現(xiàn)了嵌入式軟件程序的大量公共服務(wù)任務(wù),包括基于優(yōu)先級的任務(wù)調(diào)度、基于消息隊列的任務(wù)間通信、發(fā)行-訂閱模式、共享資源訪問模式和系統(tǒng)定時服務(wù)等。在基于框架的程序設(shè)計中,嵌入式軟件框架控制系統(tǒng)的運行,用戶任務(wù)僅以被框架回調(diào)的方式運行,不僅簡化了程序開發(fā),而且使程序設(shè)計更加安全,不易出錯。
事件驅(qū)動型嵌入式軟件框架的工作原理如圖1所示,框架包括一個消息循環(huán)、一個任務(wù)就緒表、一個基于優(yōu)先級的任務(wù)調(diào)度器和一個消息隊列。
圖1 事件驅(qū)動型框架原理框圖
中斷到任務(wù)的通信,或是任務(wù)間的通信都通過消息隊列進行。當中斷或任務(wù)要向其他任務(wù)發(fā)送通知信息時,它會向消息隊列發(fā)送一條消息,并同時在任務(wù)就緒表中將目標任務(wù)激活,這個消息包含了目標任務(wù)的 ID、消息碼以及其他附加的消息內(nèi)容。
任務(wù)調(diào)度器會不斷檢查任務(wù)就緒表,并查找其中優(yōu)先級最高的任務(wù)(任務(wù)ID越小,優(yōu)先級越高),當找到一個被激活的優(yōu)先級最高的任務(wù)時,任務(wù)調(diào)度器會根據(jù)其ID檢查消息隊列發(fā)送給該任務(wù)的消息。因為任務(wù)是在消息發(fā)送的同時被激活的,因此這個時候隊列中一定存在發(fā)給該任務(wù)的消息。任務(wù)調(diào)度器找出這個消息后分發(fā)給相應(yīng)任務(wù)的消息處理函數(shù)進行處理。當隊列為空時,任務(wù)就緒表中也必然僅僅剩下一個空閑任務(wù)(空閑任務(wù)始終激活),這時任務(wù)調(diào)度器會調(diào)用空閑任務(wù)的處理函數(shù)進行一些系統(tǒng)空閑處理(通常將空閑函數(shù)設(shè)為空,即什么也不做)。
在事件驅(qū)動型系統(tǒng)開發(fā)中,用戶應(yīng)用系統(tǒng)被劃分為一個個獨立的任務(wù),每個任務(wù)都具有一個唯一的ID號來標識它們的優(yōu)先級和任務(wù)自身。每個任務(wù)都具有一個消息處理函數(shù),這個消息處理函數(shù)在系統(tǒng)初始化時被注冊到框架,這樣當框架查找到存在發(fā)送給該任務(wù)的消息時,會回調(diào)任務(wù)的消息處理函數(shù)進行消息處理。
基于優(yōu)先級的任務(wù)調(diào)度算法可以采用參考文獻[1]中描述的算法,該算法中的任務(wù)就緒表如圖2所示。
圖2 任務(wù)就緒表
任務(wù)就緒表包括一個字節(jié)的優(yōu)先級分組變量taskpriogroup和一個優(yōu)先級變量數(shù)組taskprio[N],N最大為8,即數(shù)組taskprio[N]最多可包含8個字節(jié)。
taskprio[N]中的每一個位都表示一個任務(wù)的就緒狀態(tài),位的位置與任務(wù)ID的映射關(guān)系見圖2,這樣8個字節(jié)的taskprio[N]最多可以表達共 64個任務(wù) ID(1~64)的就緒狀態(tài)。當某一個任務(wù)被激活時,對應(yīng)其 ID的位被置為1,當任務(wù)未激活時,對應(yīng)的位被置為 0。
taskprio[0]中的任意一個位被置為1時,taskpriogroup的0位被置1,否則該位被清零;taskprio[1]中的任意一個位被置為1時,taskpriogroup的1位被置為1,否則該位被清零,以此類推。
這種算法的優(yōu)勢在于它的任務(wù)查找算法(在當前任務(wù)就緒表中查找被激活的優(yōu)先級最高的任務(wù))執(zhí)行時間短而且具有確定的執(zhí)行時間,算法細節(jié)可參見參考文獻[1]。
圖 2 中的就緒表最多可以管理 64 個任務(wù),對于一般的嵌入式軟件來說已經(jīng)足夠了。也可以通過擴充優(yōu)先級分組變量 taskpriogroup和優(yōu)先級變量數(shù)組 taskprio[N]來擴大框架管理的任務(wù)數(shù)。
不同于一般面向過程的嵌入式程序設(shè)計,事件驅(qū)動型系統(tǒng)的主任務(wù)循環(huán)由框架控制(如圖3所示),框架會不斷地在任務(wù)就緒表中查找最高優(yōu)先級的任務(wù),若無任務(wù)被激活,則框架會執(zhí)行空閑處理函數(shù),之后繼續(xù)在就緒表中查找最高優(yōu)先級的任務(wù),周而復始;若在就緒表中查找到被激活的任務(wù),則框架會去消息隊列查找發(fā)給被激活的最高優(yōu)先級任務(wù)的消息,并回調(diào)該任務(wù)的消息處理函數(shù)進行消息處理。從這里可以看到,當使用嵌入式軟件框架進行編程時,應(yīng)用程序設(shè)計者不必關(guān)注整個大循環(huán)的實現(xiàn),大循環(huán)和任務(wù)的調(diào)度由框架控制,程序員所有的工作就是設(shè)計好消息處理函數(shù),程序設(shè)計工作被簡單化了。
圖3 主任務(wù)循環(huán)流程圖
圖4 消息鏈表
為了便于消息的插入、刪除與查找操作,消息隊列采用單向鏈表實現(xiàn),消息隊列結(jié)構(gòu)如圖4所示。通常情況下,單向鏈表僅維護一個隊列頭指針就可以了,其他元素都可以通過遍歷得到,圖中的鏈表與通常的單向鏈表相比,消息隊列多維護了一個尾指針,目的是減少在隊列中插入新元素的時間。
消息幀結(jié)構(gòu)如圖5所示,消息幀內(nèi)容必須包括指向下一個消息節(jié)點的指針,目標任務(wù)ID和一個消息碼,附屬內(nèi)容是可選的。
圖5 消息幀結(jié)構(gòu)
這里的目標任務(wù)ID是一個多字節(jié)數(shù)組,長度與優(yōu)先級變量數(shù)組taskprio的長度相同,其中的每一個位表示一個任務(wù)ID,這樣做的目的是支持嵌入式軟件設(shè)計中的發(fā)行-訂閱模式,也就是面向?qū)ο笾械挠^察者模式[2],即多個任務(wù)可以向某個任務(wù)訂閱消息,這個任務(wù)需要向多個訂閱其消息服務(wù)的多個任務(wù)同時發(fā)送消息,此時,消息的發(fā)送不是單點的,而是群發(fā)的。
共享資源的訪問控制是嵌入式軟件設(shè)計中的常見問題,例如一個串口正在進行通信時,另外的任務(wù)可能也會需要使用串口,就出現(xiàn)了資源的共享問題。在操作系統(tǒng)支持的搶占式多任務(wù)環(huán)境下,這個問題通常通過互斥型信號量來解決,在非搶占式多任務(wù)情況下,通常有以下幾種策略:
① 在頂層任務(wù)規(guī)劃時,確保不同任務(wù)對資源的使用時間錯開,不會發(fā)生資源競爭的情況,這種設(shè)計雖然很好,但有時很難做到。
② 在調(diào)用資源時,允許資源返回忙狀態(tài)。當任務(wù)發(fā)現(xiàn)當前要使用的資源為忙狀態(tài)時,它等待一段時間再重試,這種設(shè)計的缺點是不像前述的互斥型信號量一樣用一個統(tǒng)一的方法解決問題,每個調(diào)用任務(wù)都需要編寫超時等待函數(shù),工作量比較大。
③ 共享資源內(nèi)嵌一個緩存機制。這正是本框架采取的方法,框架維護一個消息緩存隊列,當共享資源正在處理一個消息,而另外一個消息不期而至時,共享資源可以將這個后到的消息放入緩存隊列,待當前任務(wù)處理完畢后,再將這個緩存的消息轉(zhuǎn)移到主消息隊列,一旦被轉(zhuǎn)移到主消息隊列,這個消息就會被調(diào)度器檢查到并再次交給資源任務(wù)進行處理。
嵌入式系統(tǒng)中會有大量的定時需求,從毫秒級、秒級、甚至到分鐘級不等,操作系統(tǒng)通常會有一個時基為應(yīng)用程序提供定時服務(wù),這個時基的周期通常為10~100 ms。本文的嵌入式軟件框架也提供了一個定時服務(wù),當用戶程序需要使用定時服務(wù)時,只需要調(diào)用框架提供的定時服務(wù)訂閱函數(shù)接口,通知框架定時的時間長度、單次還是周期定時以及定時時間到時框架發(fā)給任務(wù)的定時消息的消息碼。訂閱完成后框架就會按照指定的時間間隔和發(fā)送模式(單次還是周期)定時給任務(wù)發(fā)送消息。
框架的這個功能比通常的操作系統(tǒng)做得更好,通常的操作系統(tǒng)會提供一個固定的時基,當任務(wù)需要更大的時基時,需要自己維護一個累加變量以累計時間。而框架可以直接提供任務(wù)所需要的任意長度的時間,進一步簡化用戶程序的設(shè)計??蚣軆?nèi)部為任務(wù)維護了虛擬定時器[3],當任務(wù)向框架訂閱定時服務(wù)時,框架會為其維護一個虛擬定時器,這個虛擬定時器的時鐘源來自于系統(tǒng)的固定硬件定時器,在虛擬定時器的內(nèi)部會為任務(wù)維護時鐘累加變量,這樣框架僅在到達用戶指定的任務(wù)時間間隔時,才會向任務(wù)發(fā)送通知消息。
本文詳細描述了嵌入式軟件框架設(shè)計中的任務(wù)調(diào)度優(yōu)先級算法以及任務(wù)通信隊列、發(fā)行-訂閱模式、共享資源的延遲訪問和系統(tǒng)定時服務(wù)等的實現(xiàn)方案,根據(jù)本文方案所設(shè)計的嵌入式軟件框架在多個工業(yè)產(chǎn)品中獲得應(yīng)用,取得了良好的應(yīng)用效果,采用框架進行程序設(shè)計不僅簡化了程序員的編程工作,而且使編程更加安全。
[1] Jean J,Labrosse.Micro C/OS-II,TheReal-TimeKernel,Second Editio[M].邵貝貝,譯.北京:北京航空航天大學出版社,2003.
[2] 秦曉波.設(shè)計模式之禪[M].北京:機械工業(yè)出版社,2015.
[3] 李云.專業(yè)嵌入式軟件開發(fā)[M].北京:電子工業(yè)出版社,2012.
周春華(博士),主要研究方向為機電工程。
Event-driven Programming Frame Design for Embedded System
Zhou Chunhua
(Field engineering college,PLA Univ. of Sci&Tech,Nanjing 210007,China)
A kind of event-driven programming frame for embedded systems is proposed in this paper.The public functions in embedded software are abstracted and realized,which includes task schedule based on priority,communications based on message queue,publish-subscribe service,access of share-resources and timer services.So the application programming of embedded software is simplified.
embedded software;event-driven;software frame
TP336
A
士然
2016-11-17)