時(shí)間觸發(fā)模式下的ProtothreadS設計應用
嵌入式行業(yè)的飛速發(fā)展使得嵌入式芯片的容量和功能都在不斷地提升。以工業(yè)應用最為常見(jiàn)的8位微控制器為例,其ROM和RAM的容量都在不斷擴大,甚至一些高端的8位處理器可以使用簡(jiǎn)單的操作系統(OS)來(lái)進(jìn)行開(kāi)發(fā)。同時(shí),32位處理器的廣泛普及也使得其價(jià)格逐漸逼近8位處理器。所以對很多應用來(lái)說(shuō),開(kāi)發(fā)的簡(jiǎn)化和迅速成為最主要的目標。尤其是當使用一款新的處理器或者硬件電路時(shí),快速的搭建其開(kāi)發(fā)的框架變得尤其重要。在嵌入式系統中,通常會(huì )采用兩種不同的任務(wù)管理和調度方式:事件觸發(fā)和時(shí)間觸發(fā)。事件觸發(fā)方式以事件的發(fā)生為核心,往往會(huì )采用多級中斷的方法來(lái)實(shí)現,其發(fā)生的時(shí)間具有隨機性。所以事件觸發(fā)方式具有較好的實(shí)時(shí)性,但是這樣也意味著(zhù)該系統具有較高的復雜度。而且,事件觸發(fā)方式的開(kāi)銷(xiāo)往往是很大的。Alexander Metzner的研究指出:一個(gè)包含27個(gè)任務(wù)、采用RM(Rate Mono―tonic)調度算法的事件觸發(fā)系統,CPU的實(shí)際利用率僅為18%。
而時(shí)間觸發(fā)方式開(kāi)發(fā)的系統,保證了在同一時(shí)刻只處理一個(gè)事件,雖然犧牲了并發(fā)處理的實(shí)時(shí)性,但是保證了系統的可靠性,并且使得程序員能很好地預測程序的流程。Kopetz就指出:使用基于時(shí)間觸發(fā)的合作式調度器會(huì )使得系統有非常好的可預測性。在本項目中,嵌入式系統的功能主要集中在控制一些具有一定時(shí)隙間隔的外圍設備上面。鍵盤(pán)的掃描、顯示的刷新、數據緩沖的存儲等都是需要定期完成的任務(wù),而這些任務(wù)的實(shí)時(shí)要求也并不高,所以選用時(shí)間觸發(fā)方式的合作式調度器成為系統設計的首選。
Protothrcads利用隱式的return提供了阻塞的功能,經(jīng)過(guò)Protothrcads封裝的任務(wù),其程序的邏輯更加接近處理事件的上層邏輯,大大簡(jiǎn)化了編程。而且使用簡(jiǎn)單的宏就可以實(shí)現Protothrcads,其開(kāi)銷(xiāo)也是很小的。本文就對使用Protothrcads應用于時(shí)間觸發(fā)模式的合作式調度器做一些討論。
2 Protothreads簡(jiǎn)介
Protothrcads是由瑞典計算機科學(xué)研究所的科學(xué)家Adam Dunkels所創(chuàng )的一種新的線(xiàn)程編程方法。按AdamDunkels所說(shuō),Protothreads是專(zhuān)為資源緊張的系統設計的一種耗費資源少,且不使用堆棧的線(xiàn)程模型,它可以不使用復雜的狀態(tài)機機制來(lái)實(shí)現順序流的控制。Proto―thrcads也可以用于操作系統當中。
簡(jiǎn)單地說(shuō),Protothrcads借鑒了用c語(yǔ)言實(shí)現協(xié)同(co―routine)的原理,它應用switch―case語(yǔ)句的直接跳轉功能,實(shí)現了有條件阻塞(conditional block),最終實(shí)現了虛擬的并行處理功能(concurrent)。實(shí)際上,Protothrcads并不是真正的線(xiàn)程,在多任務(wù)的切換中并不會(huì )真正涉及上下文的切換,其線(xiàn)程的調度也僅僅是依靠隱式的return,進(jìn)而退出函數體來(lái)完成的。但是Protothreads的優(yōu)點(diǎn)卻是實(shí)實(shí)在在的。首先它不需要堆??臻g,而正如筆者用宏實(shí)現的那樣,Protothrcads也實(shí)現了很多只有線(xiàn)程編程方法才能實(shí)現的機制,比如阻塞。而用宏進(jìn)行了封裝之后,使用者完全可以像使用線(xiàn)程一樣使用它們,而且其邏輯更加簡(jiǎn)化,這大大增加了程序的清晰度,并降低了開(kāi)發(fā)維護的難度。
在對實(shí)時(shí)性要求比較高或者說(shuō)要求并行處理的場(chǎng)合,往往需要在任務(wù)A執行到一定程度、等待事件C發(fā)生時(shí),退出當前任務(wù)A并轉而執行任務(wù)B;當事件C發(fā)生之后,系統繼續回到任務(wù)A,繼續方才的執行。所以必須將任務(wù)A上次執行到地方的環(huán)境存儲起來(lái),以便重回任務(wù)A后可以接著(zhù)打斷的地方繼續運行。線(xiàn)程的上下文切換可以達到這個(gè)目的,Simon Tatham用C語(yǔ)言實(shí)現的co―routine也可以。Protothreads正是借鑒了這一原理,如以下任務(wù)函數所示:
可以看出,在進(jìn)行了宏擴展之后,下面的程序段和上面的程序段是完全相同的,但是宏封裝很好地構建了一個(gè)上層的邏輯體系。這正是Protothreads的核心所在。同時(shí),這也決定了Protothreads具有一定的局限:
①Protothreads中使用的必須是靜態(tài)變量或者全局變量;
②避免與switch語(yǔ)句的合用(Protothreads的實(shí)現已經(jīng)用了switch語(yǔ)句);
③因為編譯器會(huì )將__LINE__解釋為當前所在的行號,所以不能將多個(gè)“返回”置于同一行。
3 調度器設計
時(shí)間觸發(fā)方式的嵌入式系統是根據定時(shí)器產(chǎn)生的恒定間隔的中斷來(lái)觸發(fā)和管理任務(wù)的。系統依靠一個(gè)基準的時(shí)間中斷,以此中斷為任務(wù)處理的節奏和“節拍”,任務(wù)的調度發(fā)生在“節拍”規定的時(shí)刻。中斷服務(wù)子程序也同樣占用這個(gè)時(shí)間間隔,為了系統的穩定性,一方面要使中斷服務(wù)子程序盡可能短,以節省任務(wù)的執行時(shí)間;另一方面,執行的任務(wù)也應該盡可能短,一些比較耗時(shí)的任務(wù)可以細分為若干個(gè)子任務(wù)加以調度。同時(shí),這也要求調度器的設計盡可能簡(jiǎn)單。本文的設計思想就是對于系統僅僅定義一個(gè)任務(wù)控制塊(TCB)隊列,每個(gè)任務(wù)對應于隊列中的一個(gè)節點(diǎn),由中斷服務(wù)子程序更改TCB隊列中的記錄,調度函數根據此TCB來(lái)進(jìn)行調度??梢月晕⑿薷腜roto―threads中的結構體pt,以滿(mǎn)足作為T(mén)CB隊列節點(diǎn)的需要。當然,此結構也需要聲明為全局變量或者靜態(tài)變量。其數據結構如下所示:
評論