任務的相關概念
任務的定義
在嵌入式開發(fā)中,面對的都是單個 CPU 的情況,而在這個開發(fā)過程中,我們會涉及到裸機開發(fā)或者是跑操作系統(tǒng)的開發(fā),在裸機開發(fā)的過程中,整個系統(tǒng)是以模塊的角度來看的,也就是系統(tǒng)在運行完了這個模塊之后,再去運行另外一個模塊。但是在有操作系統(tǒng)的情況下,我們是把系統(tǒng)處理的一件一件事情以任務的角度來進行劃分的,這任務與任務之間是并發(fā)執(zhí)行的。每個任務的運行看起來是獨立的,從宏觀的角度看是多個任務同時在占據(jù)著 CPU 的執(zhí)行,就像是多 CPU 一樣,在真正的多 CPU 系統(tǒng)中,每個 CPU 都有一套自己的寄存器,而為了實現(xiàn)這樣一種多 CPU 運行的機制,那么操作系統(tǒng)就為每個任務用一塊專用的存儲空間構建了一個“虛擬 CPU”,用來保存 CPU 內(nèi)存各個寄存器的信息,這塊專用的存儲器空間就是“任務堆?!保卸嗌賯€任務就會有多少個任務堆棧。
操作系統(tǒng)為了能夠有效地在各個任務之間進行切換,也就是任務之間的調(diào)度,那么就必須掌握各個任務的詳細動態(tài)信息。為此,操作系統(tǒng)為每個任務建立了檔案,用來記錄任務的這些信息,這就是“任務控制塊”。另外任務有各自的內(nèi)容,這就是作為開發(fā)者來編寫的任務函數(shù),來實現(xiàn)這個任務所需要的功能。
綜上,我們知道了每個任務都會具有如下三種特征:
任務函數(shù)
任務堆棧
任務控制塊
任務的特性
任務的基本特性是獨立性、并發(fā)性和動態(tài)性。這也是任務和程序模塊的本質(zhì)區(qū)別,程序模塊通常是用于沒有操作系統(tǒng)的裸機開發(fā)中。
獨立性:
在傳統(tǒng)的程序模塊中,一個模塊是可以調(diào)用另外一個模塊的,但是在操作系統(tǒng)中,每個任務都具有自己的 CPU ,即 CPU 為自己獨占,這樣,一個任務也就不能夠像調(diào)用子程序那樣去調(diào)用另外一個任務了。這是關于獨立性一個體現(xiàn)
關于獨立性的另一個體現(xiàn)就是任務之間傳遞信息時,模塊之間的傳遞信息時主模塊以實參的形式將信息傳遞給模塊的形參,子模塊以返回值的形式將結果傳輸給主模塊。但是在任務之間傳遞信息卻不是這樣的,任務與任務之間的傳遞信息需要借助于第三者,也就是跟操作系統(tǒng)相關聯(lián)的信號量、郵箱和消息隊列等,通過第三者來傳遞信息也就造成了信息傳輸是異步的,這也是任務獨立性的一個體現(xiàn)。
并發(fā)性
任務 A 在時刻 t1 到 t4 之間完成,任務 B 在時刻 t2 到 t3 之間完成,它們的運行時間段有重疊部分,這種運行方式稱為“并發(fā)”運行。在多 CPU 系統(tǒng)中,并發(fā)運行著的任務確實都有自己的 CPU ,它們的運行狀態(tài)就是真正的并發(fā)執(zhí)行,如下圖所示:
在單 CPU 中,操作系統(tǒng)的任務調(diào)度功能解決了這樣一個問題,嵌入式實時操作系統(tǒng)的內(nèi)核都是采用 “可剝奪型”的任務調(diào)度算法,這也就意味著一個已經(jīng)就緒的高優(yōu)先級任務可以剝奪另一個正在運行的低優(yōu)先級任務的運行權而進入運行狀態(tài),如下圖所示:
動態(tài)性
任務的狀態(tài)是動態(tài)變換的,這意味著這些任務并不是隨時都可以運行的,任務具有以下五種不同的狀態(tài)下圖用狀態(tài)圖的形式表示出來。
任務的劃分
對一個具體的嵌入式應用系統(tǒng)進行任務劃分,是基于實時操作系統(tǒng)應用軟件設計的關鍵,任務劃分是否合理將直接影響到軟件設計的質(zhì)量。當任務劃分的合理時,軟件設計將比較簡單高效,否則將可能比較繁雜,甚至失敗。在進行任務劃分時,具備以下幾個原則:
首要目標是滿足實時性指標
即使是系統(tǒng)處于最壞的情況下,系統(tǒng)中對于實時性要求的功能都能夠得到實現(xiàn)。
任務數(shù)目合理
任務數(shù)目合理,當任務數(shù)比較多的時候,每個任務需要實現(xiàn)的功能就簡單一些,任務的設計也簡單一些,但是任務調(diào)度操作和任務之間的通信活動增加,使得系統(tǒng)的效率下降,資源開銷也變大。當任務劃分的數(shù)目比較少的時候,每個任務需要實現(xiàn)的功能就比較復雜一些,但是可以免除不少任務之間的通信工作,減少共享資源的數(shù)量,減輕系統(tǒng)的負擔,減少資源的開銷。因此關于任務數(shù)目的設計是比較關鍵的。
簡化軟件系統(tǒng)
一個系統(tǒng)要實現(xiàn)功能,除了設計其本身的功能以外,還需要其具備相應的時間管理,任務同步,任務通信,內(nèi)存管理等功能。合理地劃分任務,可以降低對操作系統(tǒng)的服務要求,能夠簡化系統(tǒng)軟件設計,減小軟件代碼規(guī)模。
降低資源需求
減少或者簡化任務之間的同步和通信功能,就可以減少相應數(shù)據(jù)結構的內(nèi)存模型,從而降低對系統(tǒng)資源的需求。
因此,為了使得任務劃分更加合理,通常采用以下幾種方法進行任務劃分:
設備依賴性任務劃分
假設現(xiàn)在有如下一個具備輸入輸出功能的系統(tǒng):
通過上述框圖大致可以明白整個系統(tǒng)的工作流程,通過鍵盤輸入數(shù)據(jù),以及攝像頭采集圖片信息,送至 CPU 進行處理,然后系統(tǒng)通過輸出設備液晶屏以及揚聲器輸出相關的信息,圍繞 CPU 為中心,那么我們就可以這樣來進行劃分任務:鍵盤任務,顯示任務,數(shù)據(jù)采集任務,控制輸出任務和通信任務。
關鍵任務的劃分
"關鍵性"是指某種功能在應用系統(tǒng)中的重要性,如果這種功能不能夠正常實現(xiàn),則會造成重大影響,甚至能夠引發(fā)災難性后果。包含關鍵功能的任務稱為“關鍵任務”,關鍵任務必須得到運行機會,即使遺漏一次也是不可行的。
那如何使得關鍵任務能夠準確得到執(zhí)行呢,我們第一時間所想到的就是提升關鍵任務的優(yōu)先級,使其優(yōu)先級為最高,但是這還不夠,我們假設現(xiàn)在有一個火災報警系統(tǒng),火災報警系統(tǒng)大致完成這么幾件事,檢測火警信號,撥打火警電話,啟動噴淋滅火系統(tǒng),生成并保存火警記錄以及打印火警記錄。如果我們把這幾件事都包裝成一個任務,優(yōu)先級設置為最高,在系統(tǒng)運行的過程當中,生成并保存火警記錄以及打印火警記錄時打印機出問題了,這個時候,就會導致當前任務被掛起,而任務被掛起之后,檢測火警信號也不能夠正常工作了,所以整個系統(tǒng)也就癱瘓了。因此,對于關鍵功能來說:必須盡可能和其他功能進行剝離,獨立成為一個任務,然后通過通信方式再觸發(fā)其他任務,完成后續(xù)操作。
除了將關鍵任務和其他功能的任務相剝離,并設置最高優(yōu)先級以外,還有一種方法能夠使得關鍵任務得到準確執(zhí)行,那就是采用中斷的方式,比如說,在火警的報警系統(tǒng)中,讓傳感器的火警信號觸發(fā)一個外部中斷,中斷發(fā)生便完成了信號檢測功能,再由中斷服務函數(shù)使用某種通信機制通知其他任務。下面是示意圖:
我們知道為了提高系統(tǒng)的實時性,中斷服務函數(shù)應該盡可能地短,所以,我們可以進一步進行劃分,將與任務通信這部分的程序剝離出來成為一個任務專門用于通信,這樣, ISR 負擔就更小了,下圖是示意圖:
由上圖我們可以知道多出了一個任務,消息分發(fā)任務,消息任務的存在要不能干預到關鍵任務的運行,但是同時呢,又必須能夠及時地通知到其他任務的運行,因此,消息分發(fā)任務的優(yōu)先級也就確定了,其優(yōu)先級要低于所有關鍵任務,優(yōu)先級要高于所有的操作任務。
還有一種情況,就是關鍵任務不能由中斷啟動,則可以將該關鍵功能用一個獨立的任務來實現(xiàn),如下圖所示:
這個時候,已經(jīng)不能用中斷的方式來檢測報警信號了,那么就需要不停的查詢煙霧報警器的狀態(tài),防止漏掉了重要的信息。當查詢到了報警信息的時候,在通過通信機制通知其他任務完成相應的操作。
最后,要指出的一點是,如果關鍵任務有嚴格的實時性要求,那么必須賦予它足夠高的優(yōu)先級,以便及時獲得運行權,如果沒有實時性要求,那么高優(yōu)先級并不是必須的,關鍵是將其他非關鍵的操作進行剝離,以免受其拖累。
緊迫任務的劃分
”緊迫性“是指某種功能必須在規(guī)定的時間內(nèi)得到運行權(及時運行),并在規(guī)定的時刻前執(zhí)行完畢(按時完成),可見這類功能有嚴格的實時性要求,大多數(shù)緊迫任務是由異步事件觸發(fā)的,這些異步事件一般能夠引發(fā)某種中斷。在這種情況下,將緊迫任務安排在相應的 ISR 中是最有效的方法。如果緊迫任務不能夠安排在 ISR 中,那么為它安排盡可能高的優(yōu)先級是解決“及時性”的有效方法。要達到按時完成的目的,必須使得緊迫任務需要執(zhí)行的時間盡可能的短。辦法就是對緊迫任務進行瘦身,盡可能地剝離不太緊迫的任務,只剩下必須立刻做的操作,將被剝離的不太緊迫的操作另外封裝成一個任務。
下圖是一個數(shù)據(jù)采集任務,數(shù)據(jù)采集時一個緊迫任務,通過峰值檢測電路觸發(fā)中斷,在中斷里完成 A/D 轉換,下圖是整個數(shù)據(jù)采集系統(tǒng)的示意圖:
數(shù)據(jù)處理任務的劃分
用戶應用程序中消耗時間最多的就是各種數(shù)據(jù)處理單元,這種單元通常不止一個,他們通常為不同的功能服務。應該將這些單元劃分出來,分別包裝成不同的任務。由于這類任務需要消耗較多的時間,那么他們的優(yōu)先級必須安排的比較低,除此之外的方法,如果操作系統(tǒng)支持將多個任務安排相同優(yōu)先級的機制,那么當有多個數(shù)據(jù)處理任務時,可安排相同的優(yōu)先級,采用時間片輪轉的方式運行,如果操作系統(tǒng)不支持多個任務具有相同的優(yōu)先級,那么可以將多個需要并行的數(shù)據(jù)處理任務分成多個數(shù)據(jù)處理任務,原理如下圖所示:
功能聚合任務的劃分
正如標題的意思所示,功能聚合任務的劃分,也就是將關系緊密的任務組合成一個任務,達到功能聚合的效果,那什么樣的任務才能稱之為是關系緊密的任務呢,一般滿足以下兩點要求:
數(shù)據(jù)關聯(lián)緊密
時序關聯(lián)緊密
至于要將其組合成一個任務的原因也很簡單,是因為如果將關系密切的功能分別用不同的任務來實現(xiàn),那么就需要進行大量的數(shù)據(jù)通信和同步通信,這對于系統(tǒng)而言是一個很大的負擔。
觸發(fā)條件相同任務的劃分
如果若干功能由相同的事件觸發(fā),則可以將這些功能組合成為一個任務,從而免除將事件分發(fā)給多個任務的工作量。但是這也必須有一個條件,就是當以某種次序順序執(zhí)行這些功能的時候,各個功能的實時性要求仍然可以得到滿足,這是關鍵。同時,這里說的觸發(fā)條件相同的任務,通常外部觸發(fā)的任務一般是關鍵任務或者緊迫任務,需要按照前文所述的方法來進行任務的劃分,符合本類任務的觸發(fā)條件通常是內(nèi)部事件,比如說一個時鐘事件,也就是說到了指定時間就觸發(fā)這個任務,或者說是某個任務運行之后得到一個結論,這結論又觸發(fā)了一個任務。如下圖示意圖所示:
另外,需要注意的是,在任務內(nèi)部,各個功能的執(zhí)行順序要盡可能安排的合理一些:
如果各個功能之間存在有因果關系。則按因果關系安排執(zhí)行順序,如先計算,后輸出結果
如果各個功能之間完全獨立,則按照實時性要求的強弱安排執(zhí)行順序。
運行周期相同任務的劃分
將周期相同的功能組合在一起封裝成一個任務,就能可以避免一個時間觸發(fā)幾個任務,省略去事件分發(fā)操作和他們之間的通信,能夠減輕系統(tǒng)的負擔。
順序操作的任務的劃分
如果若干功能按照固定的順序進行流水作業(yè),相互之間完全沒有并發(fā)性,那么應該將這些功能組合成為一個任務。
總結
通過上述的論述,我們知道了在一個 RTOS 中應該如何進行任務的劃分,在最后,再進行精煉一下,總結為如下幾點:
以 CPU 為中心,將與各種輸入/輸出相關的功能劃分為獨立的任務
將關鍵功能剝離出來用一個獨立的任務或者是 ISR 去完成,剩余的部分用另外一個任務實現(xiàn),兩者之間通過通信機制進行溝通
將緊迫功能剝離出來用一個高優(yōu)先級的任務或者 ISR 去完成,剩余部分用另外一個任務實現(xiàn),兩者之間通過通信機制進行溝通
對于既關鍵又緊迫的功能,按照緊迫功能的處理方法對齊進行處理
將消耗 CPU 時間較多的數(shù)據(jù)處理功能劃分出來,封裝成低優(yōu)先級的任務
將關系密切的若干任務組合成一個任務,達到功能聚合的效果
將由相同事件觸發(fā)的若干功能組合成為一個任務,從而免除事件分發(fā)機制
將運行周期相同的任務組合成為一個任務,從而免除時間事件分發(fā)機制
將若干按固定順序執(zhí)行的功能組合成為一個功能,從而免除同步接力通信的麻煩
參考資料:
《基于嵌入式實時操作系統(tǒng)的程序設計技術》
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!