嵌入式RTOS軟體開發理論總結

引言

:軟體開發,大多數人依靠的是經驗,缺乏理論,比如遇到問題知道怎樣改可以修復問題,但不明白深層原因。有些階段,選擇高校的理論教程讀讀,比網紅博主拼湊的技術總結,更能醍醐灌頂,提高水平。

實踐檢驗真理,但理論能指導實踐

1、RTOS的特點

作業系統是計算機中最重要的軟體,類似管家,把不同的軟體任務安排給硬體資源去執行。為保證服務質量,需要對任務進行合理安排,訪問硬體也進行一定的安全維護,保證硬體資源不閒置,不爭搶衝突,但允許合理的插隊。

RTOS的專業的描述:

1、執行時間的可確定性是實時

作系統的基本特性。採用合理的演算法和策略,為多個任務合理地分配資源,以滿足每個任務的實時性要求。

2、多工搶佔式是實時作業系統的基本特性。多個任務共同分享硬體系統資源,每個任務間彼此獨立,根據任務的重要程度給任務分配不同的優先順序,優先順序越高的任務越容易得到 CPU 的使用權,保證任務的實時性和充分地使用硬體資源。

3、對穩定性和可靠性要求髙。

要成為老司機,首先要考駕照,學習如何開車,至於汽車本身各系統工作原理,內部構造暫且不用關注;能上路,在不同路況安全駕駛。達到一定水平了再去深究車的部件組成、故障排查。

基於RTOS的軟體開發,不僅要明白作業系統介面的作用,還要理解其組合的意義。

本文是關於軟體開發的理論,作為有一定RTOS基礎的參考,授人以漁。對任務、公共函式、中斷服務的設計,以及行為同步、資源同步、資料通訊的思想和方法進行說明,基本涵蓋RTOS軟體開發的全部理論。更多資訊請關注微信公眾號

嵌入式系統

2、任務設計

嵌入式系統的設計都是從需求分析開始,在軟體角度,對具體功能進行任務劃分,是實時作業系統應用軟體設計的關鍵。任務(task或thread)劃分是否合理將直接影響軟體設計的質量、執行效率和可擴充套件性。

2。1 任務的特性

“任務”的狀態是動態變化的,簡化就是有執行和等待,而且阻塞等待是必須的,更多狀態可以參考作業系統基礎。

多個任務宏觀上是併發執行,其實對單CPU是分時複用,每個任務執行時獨立的佔有系統資,這也導致任務間資料傳輸的非同步性。

好比三口之家只有一個衛生間,多人分時使用,不需要三人就配三個衛生間,每人使用時完全享有衛生間的設施,其他人有需要時,得排隊或者看家庭地位強迫插隊。

在對一個具體的嵌入式系統進行任務劃分時,不同的角度有不同的方案,一般先考慮需求指標和硬體資源限制。

實時性指標

:在最壞的情況下,系統中對時間要求高的需求能否實現。

任務數目合理

:任務數目多,每個任務只實現單一功能,任務的設計簡單;但任務的排程操作、任務之間的通訊活動增加,資源開銷大,執行效率低。一般按功能型別、時間要求合理地合併一些任務。

降低資源需求

:合理劃分任務,減少任務之間的同步和通訊需求,選擇合適的資料結構,從而降低對硬體資源的需求。

2。2 任務劃分的方法

為了使任務劃分合理,通常採用以下方法。

2。2。1 裝置依賴性任務

系統任務必定是為了實現某些功能,這個功能是主動執行,如讀取資訊、控制外設,還是被動執行,如接收按鍵事件。

根據這個特性,任務可分為“主動型”和“被動型”兩種。主動型任務與其他任務透過通訊機制向該任務發出執行請求執行,被動型任務通常是一箇中斷服務程式(ISR) 和一個與之關聯的任務。在這個基礎上,也可以把多個同類型外設的檢測合併到一個任務。

2。2。2 關鍵任務

“關鍵性”是指某種功能在系統中的重要性,如果該功能異常將會產生嚴重後果,這種關鍵任務必須優先得到執行機會,而且其檢測事件、訊息佇列不能遺漏,特殊情況下控制時間也要及時響應。

這種任務得提高優先順序來保證執行,而且其任務功能必須儘可能與其他功能剝離,獨立成為一個任務,不能因為任務裡面的其他功能阻塞或者異常,影響關鍵功能的實現。

2。2。3 緊迫任務

“緊迫性”是指某種功能必須在規定的時間內得到執行權(及時執行),這類功能有嚴格的實時性要求。大多數緊迫任務是由非同步事件觸發的,這種緊迫任務安排在相應的中斷服務中,或者優先順序儘可能髙的任務。

要達到“按時完成”的目的,必須使“緊迫任務”需要的執行時間儘可能短。儘可能剝離“不太緊迫”的操作,只剩下“必須立刻執行”的操作,將被剝離的“不太緊迫”的操作另外封裝為一個任務。

2。2。4 資料處理任務

使用者應用程式中消耗機時最多的一般是各種資料處理單元,而且通常不只一個,它們分別為不同的功能服務,這些單元劃分出來,分別包裝成不同的任務。由於這類任務需要消耗較多機時,所以優先順序必須較低。

多個不同的資料處理任務時,可安排相同的優先順序,採用時間片輪轉方式執行。

2。2。5 觸發條件相同的任務

如果若干功能由相同的事件觸發,就可以將這些功能合併為一個任務,從而減少事件分發給多個任務的工作量。如檢測到按鍵中斷後要進行相應資料處理、介面顯示、外設控制。

在任務內部,各功能的執行順序需要儘可能按規則設定,如果各個功能之間有因果關係,則按因果關係的順序執行;如果各個功能之間完全獨立,則按實時性要求的強弱順序執行。

2。2。6 執行週期相同的任務

對於需要重複執行的操作,即具有周期性。這類功能組合在一起封裝為一個任務,避免一個時間事件觸發多個任務,省去事件分發操作與它們之間的通訊。

2。2。7 順序操作任務

如果若干功能按固定順序進行流水作業,相互之間完全沒有“併發性”,儘量將這些功能組合為一個任務。

2。3 任務的可排程性分析

任務劃分後,需要評估CPU佔有率,以便確定這些任務是否可以在作業系統的排程下正常執行。簡單的說就是計算在一定週期內,各任務執行的最長時間長和是否小於週期,也可以粗略確認最低優先順序的任務(待機任務)是否有周期執行的機會,否則系統的正常執行可能難以保證。

類似生產流水線,如果某個環節超時,整個產線就沒法持續執行。這種情況需要提高系統時鐘頻率或者換硬體方案,或者最佳化軟體演算法。

2。4 任務型別

任務設計是整個應用程式的基礎,按任務的執行方式可以分為三類:單次執行類、週期性執行類和事件觸發類。

2。4。1 單次執行的任務

這類任務建立後只執行一次,執行結束後即自行刪除。優點一個功能執行完了,立刻銷燬釋放資源,但也正是這樣,缺點也明顯,釋放不乾淨,或者訊號量處理不當導致關聯任務永久阻塞。僅適合不與其他任務進行通訊(除ISR外)的孤立任務。

不過有些RTOS或者二次封裝,可以提供工作佇列(work queue),多個這樣的功能需求,統一到一個固定的任務執行,該固定任務並不銷燬,一直存在,接收其他任務的執行請求。類似共享單車,大家都是用完就還,由指定人負責維護執行。

2。4。2 週期性執行的任務

週期性執行的任務建立一次,使用while 1永久存在,執行任務實體後休眠,再按時喚醒或者超時觸發,再執行再休眠的迴圈操作。需要注意休眠時間和任務執行時間比值越大越好,否則時間間隔會累積誤差。

適用於對週期穩定性要求不高的任務,否則只能採用獨立於作業系統的定時中斷來觸發。

2。4。3 事件觸發執行的任務

這類任務實體程式碼的執行需要等待某種事件的發生,在相關事件發生之前,如獲取佇列訊息或訊號量阻塞中,該任務被掛起等待。相關事件發生一次,該任務實體程式碼就執行一次。

這種任務可以與其他任務進行通訊,也可被動等待時間觸發,一般情況下使用最多。

2。5 任務優先順序

不同RTOS任務優先順序定義的範圍和意義不同,比如有的是數值越小表示優先順序越高,有的相反;最大數值的範圍也與系統配置有關。任務的優先順序安排原則:

中斷關聯性:與中斷服務程式關聯的任務應該安排儘可能高的優先順序,以便及時處理非同步事件,避免第二次中斷髮生時第一次中斷還沒有處理完成,從而產生訊號丟失現象。

緊迫性:因為緊迫任務對響應時間有嚴格要求,所有緊迫任務按響應時間要求排序,越緊迫的任務安排的優先順序越高。

關鍵性:任務越關鍵安排的優先順序越髙,以保障其執行機會。

傳遞性:資訊傳遞的上游任務的優先順序高於下游任務的優先順序,如訊號採集任務的優先順序高於資料處理任務的優先順序。

快捷性:在前面各項條件相近時,耗時短的任務安排的優先順序越高。

3、 公共函式的設計

基於RTOS系統的全域性公共函式,需要考慮多工訪問的衝突。好比你在家如廁,使用私有資源隨心所欲;出門在外上公廁,使用共享資源就得遵守一定規則。

如果某個任務呼叫某個公共函式時,被另一個髙優先順序的任務搶佔,且高優先順序任務也要呼叫該公共函式,為防止破壞原任務的資料,確保這段程式碼即使在多個任務同時且多次呼叫,執行結果表現都是一樣,就必須按一定規則限制訪問,一般採用兩種措施,互斥呼叫和可重入設計。

3。1 互斥呼叫

將公共函式作為一種共享資源看待,以互斥方式呼叫公共函式。如果公共函式比較簡單,執行時間很短,則可採用先關中斷( 或關排程) 再呼叫公共函式,呼叫結束後再開中斷(或開排程),從而避免其他任務打擾。

如果公共函式比較複雜,執行時間較長,以上方案嚴重影響系統的實時性,最好為這個公共函式配備一個互斥訊號量,任何任務在呼叫這個公共函式前必須首先取得對應的互斥訊號量,否則就會被掛起。

3。2 可重入設計

可重入函式允許多個任務巢狀呼叫,各任務的資料相互獨立,互不干擾,這種方式比採用互斥呼叫更直接。

將公共函式設計成為可重入函式的關鍵是不使用全域性資源(如全域性變數),只能使用臨時的區域性變數,區域性變數是呼叫時臨時分配儲存空間,所以不同的任務在不同時刻呼叫該函式時,同一個區域性變數分配的儲存空間是不重疊的,互不干擾。可重入函式呼叫的其他函式也必須是可重入的。

3。3 執行效率

為保證執行效率和實時性要求,函式儘量不要使用輪詢等待機制,可使用任務休眠等待。

4 、中斷服務程式的設計

中斷服務程式(ISR ) 是嵌入式應用系統獲取各種事件的基本手段,ISR的設計質量直接影響到系統的實時性指標和工作效率。

4。1 中斷優先順序

為不同的中斷服務程式安排不同的優先順序,在允許中斷巢狀的情況下,高優先順序的中斷總是能夠得到及時響應。只要沒有關閉中斷,中斷服務程式可以中斷任何任務的執行,故可以將中斷服務程式看成比最高優先順序任務還要優先的特殊任務(視RTOS型別和配置而定)。

4。2 中斷優先順序原則

中斷源是系統及時獲取非同步事件的主要手段,其優先順序規則和任務比較類似,原則如下:

緊迫性:觸發中斷的事件允許耽誤的時間越短,設定的中斷優先順序就越高。

關鍵性:觸發中斷的事件越關鍵( 重要〉,設定的中斷優先順序就越高。

頻繁性:觸發中斷的事件發生越頻繁,設定的中斷優先順序就越高。

快捷性:在前三項條件相近時,ISR 處理越快捷( 耗時短),設定的中斷優先順序就越高。

4。3 中斷與關聯任務的通訊

中斷的主要功能是響應非同步事件,ISR只是觸發事件,本身不做過多處理,將獲取的非同步事件通訊給關聯任務處理。

ISR 與關聯任務的通訊方式有兩種方式,訊號量和訊息:當使用訊號量進行通訊時,ISR 只發送訊號量,表示事件發生,透過訊號量的同步功能觸發關聯任務,所有具體工作均由關聯任務完成。

當使用資料訊息進行通訊時,ISR 需要完成對非同步事件的資訊採集,然後使用訊息郵箱(或訊息佇列) 將資料傳送給關聯任務,由關聯任務完成後續資料處理工作。

哪種方式更合適,需根據實際情況而定:

觸發 ISR 的亊件不包含資料

:不需要對事件進行資料處理,僅僅是一個特殊標記,這種情況 ISR 使用訊號量與關聯任務進行通訊。

觸發 ISR 的事件是包含資料的低頻事件

:將資料採集的工作放在關聯任務中完成,產生的時刻延誤與取樣週期相比可以忽略不計,這種情況下,ISR 使用訊號量與關聯任務進行通訊,從而簡化了ISR。

觸發 ISR 的事件是包含資料的中髙頻事件

:資料採集的工作放在關聯任務中完成,可能因為時刻延誤對取樣資料的質量有影響,在這種情況下,資料採集的工作應該放在 ISR 中完成,再使用訊息郵箱(或訊息佇列)與關聯任務進行通訊,關聯任務從訊息郵箱(或訊息佇列)中得到訊息的資料,並完成後續處理。

觸發 ISR 的事件是包含資料的非週期“高頻”事件

:對於非週期“高頻”事件,其最短事件間隔可能小於事件資料處理的耗時,如果在關聯任務採集資料就可能出現數據丟失問題,在這種情況下,資料採集的工作應該放在 ISR 中完成,由 ISR 使用具有資料緩衝功能的訊息佇列與關聯任務進行通訊,關聯任務從訊息佇列中得到訊息的資料,並完成後續處理工作。

有些晶片平臺的中斷服務不能使用作業系統介面函式,不能直接傳送訊息或者訊號量,需要進行特殊處理。更多細節可關注微信公眾號

嵌入式系統

,獲取更多技能。

5、 行為同步

在實時作業系統的支援下,系統的整體功能是透過各個任務( 包括 ISR )的協同執行來實現的,其中執行步驟的協調就是行為同步。

5。1 行為同步的通訊方式

一個任務的執行過程需要和其他任務的執行配合,才能得到預定的效果,任務之間的協調關係稱為“行為同步”。行為同步的結果體現為任務之間的執行按某種預定的順序來進行。

一般實時作業系統提供了各種的通訊方式來適應不同場合的需求,實現任務之間的行為同步。這裡只是簡要描述,不同RTOS只是介面不同,其作用都一樣。也可以參考《

FreeRTOS及其應用,萬字長文,基礎入門

》。

5。1 1 二值訊號置

可以簡單理解為一個全域性變數只能為0或者1,但其實是基於系統介面實現,支援跨任務讀寫。二值訊號量初始值為0,控制方發出同步訊號(put/give),二值訊號量的值為 1,被控制方在任務的同步點呼叫“等待一個訊號量”的服務函式(get/take),如果二值訊號量的值已經為 1,就將二值訊號量復位( 清零) 並繼續執行下去;如果二值訊號量的值為 0,便使自己掛起等待控制方的訊號。

如果被控制方總能夠及時響應控制方發出的訊號,完成相應處理任務,並在下一次訊號來到之前進入等待狀態,這樣才能保證穩定。如果被控制方獲取訊號量過慢,控制方可能已經發出多個訊號,導致訊號事件被丟失。

把同步資訊視為一個產品,控制方是產品的生產者,被控制方就是產品的消費者。當產品的“最短生產時間”比產品的“最長消費時間”還長時,產品永遠是“供不應求 ”,消費者總是處於等待狀態”,生產出來的產品立即被消費者取走,生產者和消費者達到完全同步,生產一個就立即消費一個。

如果生產過快,消費來不及,出現產品積壓,則表示任務可能需要調整優先順序,或者說二值訊號量不合適,需要使用計數訊號量。

5。1。2 計數訊號量

只要產品的平均生產時間比產品的平均消費時間長,所有的產品就都會被消費掉。但仍然有可能在某個時間段內出現臨時的“產品積壓”。如產品的生產時間為 20-40 秒(平均30秒),產品的消費時間為 10-30秒(平均 20 秒),總體上看是生產慢、消費快,但在某個時間段,生產速度維持在高水平狀態(每20秒生產一個),而消費速度偏偏維持在低水平狀態(每30秒消費一個),這時就會臨時出現產品積壓現象。

二值訊號量不能處理“訊號積壓”現象,未及時響應的訊號將會被遺棄,有效響應次數少於實際發出的訊號次數。在這種情況下,採用計數訊號是一個有效的選擇,在總體上能夠使控制方對被控制方進行同步控制,在特殊情況下也不失去控制,保證每次控制訊號都能夠得到響應,儘管響應時間偶爾會有延誤。

計數訊號最初始值為 0,控制方需要發出同步訊號時,就呼叫“發出一個訊號量”的服務函式,使計數訊號量的值加 1,被控制方在任務的“同步點”呼叫“等待一個訊號量”的服務函式。如果計數訊號量的值不為 0,就將計數訊號量減 1,並繼續執行下去;如果計數訊號量的值為0,便使自己掛起,等待控制方的訊號。

計數訊號量適用於被控制方不能保證在下一次訊號到來之前處理完本次控制方發出的訊號,但總體上可以響應所有訊號。

5。1。3 事件標誌組

需要將兩個以上的訊號進行某種邏輯運算,且用邏輯運算結果作為同步控制訊號時,簡單的通訊方式難以實現,可採用“事件標誌組”來實現,事件標誌組是若干二值訊號的組合,可以實現多個任務(包括 ISR)協同控制一個任務,當各個相關任務(包括ISR)先後發出自己的訊號後,使事件標誌組的對應標誌有效,預定的邏輯運算結果有效,觸發被控制的任務。

事件標誌組的使用方法很靈活,可以將標誌定義為“1 有效”,也可以將標誌定義為“0 有效”,邏輯關係可以為“邏輯與”(全部標誌均有效),也可以為“邏輯或”( 只要任何一個標誌有效)。可以簡單理解為某個變數,多個控制任務共同控制變數的對應的位,被控制任務在全部或者某一位滿足要求時觸發執行。

5。1。4 訊息郵箱

用訊號量進行行為同步時,只能提供同步的時刻資訊,不能提供內容資訊,當控制方對被控制方進行控制,需要向被控制方提供內容資訊時,訊息郵箱是一種有效的方案。

關於郵箱,不同的RTOS其功能定義有一定差異。大多數RTOS的郵箱不支援快取,後面傳送的會覆蓋前面;但有的類似簡化版的訊息佇列,支援快取,只是訊息內容固定為一個指標,可以多次傳送;有的RTOS不支援郵箱。

5。1。5 訊息佇列

訊息佇列是應用比較多,佇列可以存放多個訊息,能夠有效解決訊息的臨時堆積問題,但仍然需要滿足一個條件,訊息的平均生產時間比訊息的平均消費時間長,否則,再長的訊息佇列也會溢位。

特別注意

,當需要傳輸的資料量較大時,傳輸其內容指標,而不是內容本身。

5。1。6 通訊方式的選擇

以上用於行為同步的通訊方式,根據實際情況來選擇:

當同步過程不需要傳輸具體內容時,可選擇二值訊號量、計數訊號量和事件標誌組。

當同步過程需要傳輸具體內容時,可選擇訊息郵箱、訊息佇列。

當“任何時候同步資訊的生產速度都比同步資訊的消費速度慢”時,可選擇二值訊號量 、事件標誌組。

對於非週期性同步資訊,當不能保證“任何時候同步資訊的生產速度都比同步資訊的消費速度慢“時,可選擇有緩衝功能的計數訊號量、訊息佇列。

當同步訊號為多個訊號的邏輯運算結果時,採用事件標誌組作為同步手段

5。2 行為同步

合理安排同步點和任務的優先順序是獲得預期同步效果的關鍵。

5。2。1 ISR 與任務之間的同步

一個任務(或 ISR)為控制方,發出控制資訊,另一個任務為被控制方,獲取控制資訊後即進入就緒狀態,若優先順序足夠高就可以很快進入執行狀態,必要時可在ISR退出前進行一次任務切換。

一個由非同步亊件觸發的ISR 通常與一個任務關聯,它們之間就是單向同步關係,與ISR關聯的任務總是處於等待狀態,每當ISR發出資訊就被觸發,其任務結構為事件觸發型。

5。2。2 兩個任務之間的單向同步

如果單向同步發生在兩個任務之間,同步效果與兩個任務的優先順序有關。當控制方任務的優先順序低於被控制方任務的優先順序時,控制方任務發出資訊,被控制方任務進入就緒狀態,並立即發生任務切換進人執行狀態,瞬時同步效果較好。

當控制方任務的優先順序高於被控制方任務的優先順序時,控制方任務發出資訊後,雖然被控制方任務進入就緒狀態,但並不發生任務切換,只有當控制方呼叫系統服務休眠或其它使自己掛起時,被控制方任務才有執行機會,瞬時同步效果較差。

不過,控制方在發出資訊後立即呼叫延時函式( 延時時間大於被控制方任務的處理時間),主動使自己掛起來,讓低優先順序的被控制方任務儘快得到執行機會,可改善同步效果。

5。2。3 兩個任務之間的雙向同步

在單向同步過程中,必須保證訊息的平均生產時間比訊息的平均消費時間長,否則再長的訊息佇列也會溢位。如果訊息的生產者是外部物理世界,其訊息生產速度是客觀的,為了不遺漏訊息,只能提高系統處理速度來應對。

如果訊息的生產者是系統內部的某個任務,則可以透過協調生產者與消費者的關係來建立一個產銷平衡的理想狀態。

通訊的雙方相互制約,生產者透過“提供訊息”來同步消費者,消費者透過“回覆訊息”來同步生產者,即生產者必須得到消費者的回覆後,才進行下一個訊息的生產,這種執行方式稱為“雙向同步”,這和UART串列埠的流控比較類似,其實現方式是單向同步操作的兩倍。

5。2。4 多工同步一個任務

當需要兩個以上任務同步一個任務時,簡單的通訊方式難以實現,可採用“事件標誌組”來實現。只要被同步任務的執行速度足夠快,其執行次數就可以“等於”各個同步任務發出訊號次數的總和,否則也會遺漏個別訊息。

5。2。5 多個任務相互同步

多個任務的執行頻度保持一致,即一組關聯任務在特定點互相等待,每個相關任務在執行到同步點時都必須等待其他任務,只有相關任務都到達同步點,才可以按優先順序順序依次離開同步點,從而達到相關任務的執行頻度保持一致的目的。類似一組人各自獨立的到達指定集合點,都到齊統一簽到,再各回各家。

多個任務相互同步,理論上事件標誌組可用來實現多工相互同步,每個相關任務執行到同步點時都要“簽到”,即呼叫“傳送標誌函式”將對應標誌置位;然後呼叫“獲取標誌組標誌函式”進入等待狀態,當最後一個相關任務執行到同步點並“簽到”時,透過邏輯運算產生“全部到齊”的訊號(多工同步標誌),並將這個同步訊號分發給各個相關任務( 進入就緒狀態)後,相關任務按優先順序次序先後執行。

但是,因為各個任務的執行情況是動態變化的,每個任務都有可能最後一個到達同步點,只使用事件標誌組無法判斷在最後一個到達同步點的任務清除標誌,導致後續會不斷誤觸發。

其實使用最簡單的全域性變數,記錄當前已經到達同步點任務的數量,這樣數值累加到一定程度,即可判斷出最後一個到達同步點的任務,每個任務再同步點判斷計數值,再將同步訊號分發給各個相關任務。這個全域性變數在多個任務操作,也需進行特殊處理,也就是下一章的資源同步。

6、 資源同步

被兩個以上併發程式單元(任務或1SR )訪問的資源稱為共享資源,共享資源一定是全域性資源。但全域性資源不一定都是共享資源,固定只被一個任務(或 ISR ) 使用的全域性資源並不是共享資源,而是這個任務( 或 ISR )的私有資源,對私有資源的讀寫操作是不受限制的。

任務對共享資源進行訪問的程式碼段落稱為關鍵段落,各個任務訪問同一共享資源的關鍵段落必須互斥,才能保障共享資源資訊的可靠性和完整性。這種使得不同任務訪問共享資源時能夠確保共享資源資訊可靠和完整的措施稱為資源同步。

資源同步有關中斷、關排程、使用互斥訊號量、使用計數訊號量幾種方法,它們都能夠在訪問共享資源時,保障共享資源資訊的可靠性和完整性。

並不是訪問所有共享資源都要採取資源同步措施,如共享資源具有“只讀”特性,其資訊只能讀出,不能改寫。這類共享資源具有天然的完整性和可靠性,各個任務可以任意讀取,如系統內固化的硬體引數資訊。需要採取資源同步措施進行訪問的必定是動態共享資源,至少存一個任務( 或ISR)可以對其進行“寫”操作。

6。1 關中斷

一個任務在對共享資源進行訪問前將中斷關閉,然後執行訪問共享資源的關鍵段落程式碼,操作結束後再開啟中斷。

當中斷被關閉後,系統失去了對所有事件的反映能力,不能進行任務切換,從而保證了對共享資源的獨佔式訪問。(優先順序非常高的硬體中斷不受作業系統關中斷控制,具體與RTOS實現及其配置有關)

當參與訪問共享資源的併發程式單元中包含ISR 時,關中斷是任務訪問共享資源的最簡單方法,也是唯一的方法。

關中斷的優點是簡單,缺點是影響系統的實時性。為了減輕對系統實時性的不利影響,訪問共享資源的關鍵段落程式碼必須儘量簡短,絕對不允許在關鍵段落程式碼中包含有可能使自己掛起的系統服務函式,否則將使系統宕機。

當需要對共享資源進行“寫”訪問時,先將需要“寫入”的資訊提前準備好,存放在自己的區域性資料結構內,這個區域性資料結構與共享資源的被訪問部分的資料結構相同,然後關中斷,在關鍵段落程式碼中只需要完成將區域性資料結構的內容複製到共享資源中的操作即可,複製完畢就可以開中斷;由於兩者資料結構相同,所以執行復制功能的關鍵段落程式碼自然非常簡單、 快捷。

當需要對共享資源進行“讀”訪問時,先準備一個與共享資源被訪問部分的資料結構相同的區域性資料結構,然後關中斷,在關鍵段落程式碼中只需要完成將共享資源的有關內容複製到區域性資料結構中的操作即可,複製完就可以開中斷。退出關鍵段落程式碼後,再對複製到區域性資料結構中的資訊進行相關處理。

由於關中斷直接影響系統的實時性,因此只能用於對簡單共享資源的短暫訪問,一般用於對全域性變數或小規模全域性資料結構的訪問。

6。2 關排程

當共享資源比較複雜或者規模比較大時,關中斷的方式不可取。如果該共享資源的使用者全部是任務( 即不包含 ISR ),就可以採用關排程的方法來訪問共享資源。

關排程的方法使作業系統的任務排程器停止工作,不能進行任務切換,從而保障關鍵段落程式碼的執行不會受到其他任務的干擾。

由於關排程的方法沒有將中斷關閉,故系統對各種非同步事件仍然可以及時響應,並使相關任務進入就緒狀態,但不會立即進入執行狀態。這也是關排程的缺點,導致所有任務受到牽連,即使它們的優先順序足夠高並被ISR 觸發到就緒狀態也無法執行。

在關排程期間,必須儘可能快速完成訪問共享資源的工作,以縮短關排程的時間。如果在關排程期間呼叫系統服務函式而被掛起,其他任務又不能執行,那麼系統將崩潰。關排程的資源同步方法優點不多,缺點不少,儘可能不要使用。

6。3 使用互斥訊號量

當需要訪問的共享資源比較複雜,且訪問過程比較費時時,關中斷、關凋度的措施不可取,它對系統實時性產生了嚴重影響。如果該共享資源的使用者全部是任務( 即不包含 ISR),可採用互斥訊號量的方法來訪問。

但使用訊號量存在一定風險,可能出現

優先順序反轉現象

(優先順序反轉是指一個低優先順序的任務持有一個高優先順序任務所需要的共享資源,高優先任務必須等到低優先順序任務釋放資源才能訪問。如果此時有個優先順序處於兩者之間的任務,並且不需要那個共享資源,則該中優先順序的任務實際執行效果優先順序最高。

如果高優先順序任務等待資源時不是阻塞等待,而是迴圈忙檢測,則低優先順序任務無法執行,一直佔用共享資源,造成的後果就是高優先順序任務無法獲得資源一直處於等待狀態,系統進入假死狀態)。

解決方案有兩種,設定優先順序上限,給臨界區一個高優先順序,進入臨界區的任務都將獲得這個高優先順序,其他試圖進入臨界區的任務的優先順序都低於這個高優先順序,也就不存在優先順序反轉;

另一個方案是優先順序繼承,當一個高優先順序任務等待一個低優先順序任務持有的資源時,低優先順序任務將暫時獲得高優先順序程序的優先級別,在釋放共享資源後,低優先順序任務回到原來的優先級別。

這塊不需要應用程式關注或實現,因為RTOS自帶的互斥訊號量(mutex)具有處理優先順序反轉的功能,特別適合對共享資源的互斥訪問。

互斥訊號量與用於行為同步的二值訊號量不同,互斥訊號量的初始值為 1(unlock),表示共享資源有效( 尚未被使用),一個任務需要訪問某共享資源時,首先獲取該共享資源對應的互斥訊號量(lock),如果已經被其它任務佔用則等待;

若獲取成功,則說明該共享資源尚未被其他任務佔用,就可以對該共享資源進行使用,使用結束後必須及時傳送互斥訊號量,解除對該共享資源的佔用,以便供其他任務使用。可以類比於進公廁,必須確保門未鎖,進入後立刻鎖門,事畢出來再開鎖,其他人才可再進入使用。

使用互斥訊號量訪問共享資源時,對中斷和任務排程沒有限制,系統可以正常響應各種非同步事件,其他與該共享資源無關的高優先順序任務仍然可以及時執行( 即使任務正在執行關鍵段落程式碼),因此,使用互斥訊號量進行共享資源訪問對系統實時性影響最小。

在使用互斥訊號量進行資源同步時,任何任務一旦獲得共享資源就可以一直使用到不需要為止,其他任務優先順序再高也不能奪去使用權。

其原因是獲得共享資源的任務具有臨時的高優先順序(優先順序繼承值),其他需要訪問同一個共享資源的任務均達不到這樣高的優先順序。優先順序繼承值必須高於所有需要訪問這個共享資源的任務的優先順序。

需要注意的是,優先順序繼承值不能與其他任務的優先順序相冋,必須使用一個空閒的、高於全部使用該共享資源的任務的優先順序值,初始定義優先順序時不要將任務的優先順序安排得太緊密,中間留些間隔較好。

6。4 使用計數訊號量

當同一型別共享資源有多個實體,就允許多個任務同時使用這類共享資源,但每個任務所使用的共享資源實體是不同的,即對每一個實體的使用仍然是互斥的。

在嵌入式應用系統中,多個實體,比如多路ADC,多路UART,其實對應不同的硬體資源,並不是完全相同的,不能隨意選擇性使用,也就是感覺計數訊號量管理多實體共享資源沒有實際意義,對於多路ADC或UART,一般是使用多個互斥訊號量或者二值訊號量各自管理其中一路。

7、資料通訊

系統執行過程中,ISR與任務之間、 任務與任務之間必然伴隨資料通訊,可根據實際情況來選擇最合適的通訊方式。

7。1 全域性變數

全域性變數(包括全域性陣列和全域性結構體)可以充當一種共享資源,用來在任務之間傳輸資料,提供資料的任務或ISR對全域性變數進行寫操作,使用資料的任務或ISR對全域性變數進行讀操作,從而實現了資料的的傳輸。這種情況下全域性變數作為共享資源,對其進行的訪問必須遵循資源同步的規則。

全域性變數雖然可以實現資料傳輸,但不能實現行為同步,即新的資料產生之後並不能自動通知相關使用者,使用者也不知道當前資料是何時更新的,因此,全域性變鼂只能用於沒有行為同步要求的任務之間,即每次產生的新資料不要求立即使用,甚至可以不被使用。

在沒有行為同步要求的前提下,且傳輸的資料量不大,採用全域性變數並配合關中斷的資源同步措施是一種最有效的方法。

也有

種特殊情況

,當對共享資源進行寫操作的任務只有一個,且其優先順序高於所有其他進 行讀操作的任務,可以在進行寫操作時不必關中斷,因為低優先順序執行讀操作任務不可能獲取執行權,而低優先順序執行讀操作任務必須使用關中斷措施來訪問全域性變數。

7。2 記憶體資料塊

若需要傳輸的資料量很大時,採用記憶體塊來存放資料是最合適的選擇,也就是記憶體動態管理函式,作業系統一般會適配動態記憶體申請、釋放的介面,且支援重入。

如果申請的記憶體空間地址指標作為全域性變數,其用法和全域性變數一樣,必須遵循資源同步的規則。實際它少獨立使用,一般情況下是用於訊息佇列通訊方式的內容緩衝區,將申請的記憶體塊地址作為臨時變數,作為訊息內容的引數傳輸。

7。3 訊息郵箱

當傳送的資料要求接收方及時接收和處理,在資料通訊的同時發生行為同步,當通訊雙方的執行均具有周期性(且週期相同)時,訊息郵箱是合適的通訊工具。(前提是RTOS支援郵箱,且不帶快取,一次只能傳送一條)。

使用訊息郵箱傳送訊息時,實際上只發送指標( 訊息的地址〉,不管訊息本身的資料型別,傳送的指標都按 void *處理,接收方得到這個訊息指標後,將指標強制型別轉換獲取真正的訊息內容。

郵箱內容可以直接傳送常量(或者資料強制轉為指標型別,因為變數100和指標100,本質都是100這個數字)。如果傳送的是變數的地址,務必確保變數本身不會銷燬,一般是全域性變數或者靜態區域性變數的地址。

7。4 訊息佇列

由於訊息郵箱裡只能存放一條訊息(部分RTOS郵箱訊息功能不同,但訊息佇列,所有RTOS都表現一致)。通訊雙方至少有一方沒有固定的執行週期,無法保證訊息總能在下一個訊息產生之前處理完畢,可能丟失訊息,這種情況應該使用具有緩衝功能的訊息佇列,事實上訊息佇列最常用。

佇列是一種標準線性結構,訊息的傳送、接收就是訊息內容的入隊或出隊。在使用者層面,傳送訊息就是將訊息內容放入佇列,接收訊息時就是從佇列中取出一條訊息。

訊息內容的結構和訊息佇列的長度由使用者自行設定,訊息長度按訊息積壓的最壞情況決定,太短了不保險,太長了浪費記憶體資源。佇列是先進先出,但入隊時可以選擇放入佇列頭部還是尾部,對重要訊息可以小範圍的實現優先處理。

訊息內容的要求和訊息郵箱一樣,必須確保接收訊息的任務還能取出資料,不能使用臨時變數;也不能使用大量資料塊,可以動態申請記憶體,訊息傳遞的是其指標,實現大資料的傳輸。

8 、時間管理

作業系統可以多工間進行切換,就是靠一個系統定時器以一定頻率中斷,為系統提供排程(上下文切換)實現任務切換。而這個定時器,就是系統節拍(tick),任務排程、休眠延時都是基於節拍,一個節拍對應的時間各不相同,一般配置1-10ms。

節拍對應時間數值越小,系統實時性越高,但過小則會導致頻繁切換任務反而影響任務執行效率。

時間管理服務函式以系統節拍為處理單位,最壞的情況下誤差接近一個系統節拍,因此,時間管理服務函式只能用在對時間精度要求不高的場合,或者時間間隔較長的場合。