從零開始學習UCOSII操做系統15--總結篇

前言:在大學的時候,咱們班級上面都有不少人以爲學習UCOSII(包括UCOSIII)是沒什麼厲害的,由於不少人都喜歡去學習Linux操做系統,可是,可是,真實的對整個UCOSII操做系統進行學習,我能夠保證,若是你是基於源碼級別的閱讀的話,絕對是不簡單的。僅僅是調用幾個API的話,是永遠用很差UCOSII的操做系統的。還有你真正學通了UCOSII操做系統的話,那麼你對Linux操做系統的內核也不會有太大的難度。html

參考:嵌入式實時操做系統UCOSII原理與應用編程

一、UCOSII操做系統是怎麼管理任務的?
用圖是最能表現的:
(1)任務控制塊是來管理任務的。
(2)其中UCOSII把全部的任務都是經過雙向鏈表來鏈接到一塊兒的,爲何?我難道不能使用數組來分配空間嗎?數組

關鍵緣由:在整個操做系統中,由於咱們不知道用戶到底須要多少個任務,因此使用鏈表的話,在編譯後才確認的話,數組的方式優秀不少。函數

我我的認爲這張圖實際上是有一些錯誤的:
好比裏面寫了指向任務的指針,我以爲是應該放置在任務堆棧裏面的,由於建立任務的時候,是將任務的函數名,傳遞給任務堆棧,而後任務堆棧再傳到CPU的SR寄存器中,實現任務切換的。學習

所謂的指向任務的指針:其實就是任務的函數的函數名。操作系統

二、UCOSII操做系統是怎麼運行的?
(1)睡眠態:首先咱們的任務是按需分配的,你想要多少個任務的話,那麼咱們就能夠建立多少個任務。剛剛建立的任務是處於睡眠的狀態的。指針

(2)就緒狀態:若是系統爲任務配備了任務控制塊而且在任務的就緒表中進行了就緒登記的話,則任務就具有了運行的充分條件,這時候任務的狀態就叫作就緒態。htm

(3)運行狀態:處於就緒狀態的任務若是通過UCOSII的位圖機制,判斷爲處於最高優先級的任務的話,那麼它就能夠得到CPU的使用權,這時候就是運行狀態。對象

(4)中斷服務狀態:這個真的就沒有什麼好說的了,連先後臺系統都會存在的狀態,觸發到中斷的條件,就會進入中斷態,並且無論你是否處於運行態仍是怎麼樣?blog

以上的4個狀態是我認爲UCOSII操做系統中必不可少的狀態的。

(5)等待狀態:這個狀態的話,是能夠經過裁剪UCOSII內核去掉的,其實這個狀態就是爲了知足任務之間的通信和任務與中斷服務子程序通訊產生的一種狀態。

三、UCOSII操做系統任務之間是經過什麼進行通訊的?
總所周知,UCOSII的任務是一個特殊的函數,沒有類型,沒有返回值。
裏面是一個死循環。

那麼爲何它可以跳出來執行別的任務?
它之因此可以跳出來跟別的任務進行通訊的話,在下面的用戶須要添加的代碼中必定是有一個任務切換的函數調用的。實質上是CPU的SR寄存器中的任務堆棧的切換的過程。

那麼它怎麼跟別的任務進行通訊?
常考題:Linux的進程間通訊的方式:
信號量(互斥型信號量)、消息隊列、共享內存、消息郵箱、事件標誌組

其中UCOSII任務之間進行通訊的方式除了共享內存,其他都存在。

其中有好幾個是類型的:
好比信號量和互斥型信號量。使用這個是能夠佔用資源,或者同步任務的運行。

好比消息郵箱和消息隊列,消息隊列也稱爲多個消息郵箱,都是用來在任務之間傳遞數據的。

事件標記組:首先請求事件標記組的時候,經過一個整型數的某幾個位,若是那幾個位都已經置位或者都是爲空的話,那麼請求事件標記組的任務能夠獲得運行。

爲何須要互斥型信號量?
由於會產生任務優先級的反轉問題?

什麼是優先級反轉?高優先級任務被低優先級任務剝脫CPU的使用權。
(1)假設如今有一個低的優先級任務佔有CPU的內核,同時他佔有了一些資源。
(2)此時,來了一個高優先級的任務,它想要獲得這個資源,可是這個資源已經被低優先級的任務佔有了。
(3)在後來來了一箇中等優先級的任務,它由於優先級比低優先級的任務高,可是它的優先級沒有高的優先級高,因此它強佔CPU的使用權,繼續執行。
(4)這時候,造成的狀況就是中等優先級的任務比高優先級的任務更加早的執行,造成優先級反轉的問題。

解決方案1:
若是低優先級任務佔有的那個資源後,後面有更高的優先級任務到來的話,那麼就把本身的優先級提升到那個想要佔有優先級的任務。

解決方案2:
使用互斥型信號量。由於互斥型信號量,只有你本身請求,本身釋放,不能經過別的任務釋放,若是你請求一個已經請求過的互斥性信號量的話,那麼直接跳過執行。

void task1(void * pada)
{
    for(;;)
    {
        //用戶須要添加的代碼
    }
}
四、UCOSII操做系統的內存管理
參考:https://www.cnblogs.com/apollius/archive/2013/03/26/2981429.html
UCOSII中動態內存管理的C語言實現:

嵌入式編程比較關心的就是內存大小,在有限的內存中實現動態和靜態的代碼分配是有學問的,對於像malloc這類在運行的時候從堆中請求內存的函數,諾調用次數太多可能會形成內存的快速消息。

將全部已經分配好的空間計算好,利用全局變量分配到靜態的代碼空間中。
實際使用時調用本身編寫好的內存管理函數從這塊靜態空間中申請內存。

內存的整體大小是受控的,全部涉及到動態內存的地方實際上都已經被預先分配好,在編譯時候寫在靜態代碼區。

INT8U Buff8U [40][32];
INT16U Buff16U[40][32];

每一個內存管理塊中記錄了對應存儲的數據地址(EntryAddr),當前可用的數組的地址(FreeAddr),當內存進行分配時候,這一位會進行偏移操做,指向尚未被分配的存儲數組。而這些管理塊也須要一個總的數組來存儲其位置,不然這些指針也是沒法初始化的指針。而且新建一個指針(*MMUFREE)指向當前還未被分配,能夠用的管理塊數組中位置。

MMUType     MMUPool[MMU_BUFF_MAX];  //Store all the MMUs
MMUType    *MMUFree;                //Pointer to the available MMUType in MMUPool
 
MMUType    *MMUBuff8;            //Controller of Buff8U
MMUType    *MMUBuff16;           //Controller of Buff16U


能夠看出核心思想是,全部須要實際存儲的指針都由數組來保存,全部指針最終指向一個實際的變量,諾要使用這種內存管理,第一步要作的就是初始化MMUPOOL初始化內存池。調用MEMInit()以後將內部全部的成員造成一個鏈表,由MMUFree指向最開頭的一個。

這樣一來就能夠爲內存管理塊分配一個實際的對象了,調用MemCreate()能夠分配一個實際的對象給內存管理塊,而且將內存管理與實際的內存存儲去聯繫在一塊兒。

相關文章
相關標籤/搜索