ucOS- II中設計了五種通訊機制
4.2.4 OSMboxPost:往郵箱發送消息: 首先檢查是否有任務正在等待郵箱消息的到來,如果有的話就通過OS_EventTaskRdy找到優先級最高的任務,然后重新調度,注意,這時候要發送的消息會放到優先級最高任務的TCB中!如果沒有任務在等待該郵箱消息的到來,就直接把消息放到郵箱中。
5 隊列的實現
隊列的實現類似于郵箱,也是用來從一個任務向其他任務發送消息,不過,隊列更為復雜,之所以稱之為隊列,它可以發送多個消息,可以把郵箱看成是只發送一個消息的隊列。
5.1 數據結構的設計:
由于隊列可以發送多個消息,所以僅僅用ECB不能滿足要求,于是作者引入了另外一個數據結構QS_Q,用來描述隊列代表的多個消息,但是這里與 郵箱不同的是,QS_Q本身并不包含消息本身,而是隊列代表的一系列消息的描述。當然,真正的消息放在一個系統的消息緩沖區MsgTbl,這個緩沖區是預 先定義好的,其大小根據實際的應用而定制。所以對于隊列來說,用到三個數據結構,ECB, QS_Q, MsgTbl,其中ECB和QS_Q是每個隊列都有一個,而MsgTbl是系統中所有隊列共享的!
QS_Q由ECB的變量OSEventPtr引出,ECB的OSEventCnt沒有用到,其他的變量用法同信號量。對于QS_Q來說,和ECB一樣是從系統QS_Q緩沖區中申請的。
5.2 核心函數為五個,其中四個類似于前面的信號量,互斥體和郵箱,此外還多了一個清空隊列的函數:
5.2.1 OSQCreate:創建一個隊列:首先申請一個ECB,然后申請一個QS_Q,最后初始化申請到的ECB和QS_Q,其中用到OS_EventWaitListInit初始化等待任務表。
5.2.2 OSQDel:刪除一個隊列:實現和信號量的OSSemDel基本一樣,不同的是,由于隊列引入了QS_Q,必須加歸還申請到的QS_Q到系統QS_Q緩沖區的操作。
5.2.3 OSQPend:等待一個消息:注意這個函數只是等待一個消息,而這個消息是不是想要的它并不知道!首 先通過QS_Q判斷該隊列是不是有消息,如果有的話更新QS_Q然后返回;如果該隊列沒有消息,那么更新當前任務的TCB以表明當前任務正在等待該隊列的 消息,然后通過OS_EventTaskWait掛起當前任務,然后重新調度——OS_Sched!這個時候當前任務會等到消息到來或者超時才會得以繼續 執行。。。當繼續執行的時候,判斷是得到消息才執行,還是超時,如果是前者的話,直接更新當前任務的TCB;如果是后者的話,通過OS_EventTO更 新狀態。
5.2.4 OSQPost:發送一個消息:這個函數放一個消息到隊列。首先檢查是不是有任務在等待該隊列的消息,如果有的話,就通過OS_EventTaskRdy 找到正在等待該隊列消息的任務中優先級最高的那個,然后重新調度——OS_Sched!如果沒有的話,更新該隊列的QS_Q,也就是加一個消息進該隊列。
5.2.5 OSQFlush:刷新該隊列,其實就是簡單的重置QS_Q,系統消息緩沖區MsgTbl是不需要改動的!
前面對信號量,互斥體,郵箱,隊列做了一個簡單的總結,這四個通訊機制的核心都是ECB,而這里總結的事件組(evnet flag),作者沒有用ECB,而是重新設計了兩個單獨的數據結構來實現。下面對事件組這最復雜的通訊機制做一總結,呵呵
6 事件組
事件組的用途主要是把多個事件和多個任務能夠聯系起來,使通訊機制更加靈活,它有兩部分組成:一是表示了各個事件的狀態;二是等待這些事件的任務列表。
6.1 數據結構設計:
如上面提到的,事件組用到了全新的兩個數據結構:OS_FLAG_GRP和OS_FLAG_NODE——OS_FLAG_GRP有三個變 量:OSFlagType(和ECB中的OSEventType一樣,用來標識這是一個事件組),OSFlagWaitList(負責引出等待事件組的任 務列表)和OSFlagFlags(標識當前事件狀態);OS_FLAG_NODE有六個變量:OSFlagNodeNext和 OSFlagNodePrev(用來將OS_FLAG_NODE構成雙向列表),OSFlagNodeTCB(正在等待事件組的任務 TCB),OSFlagNodeFlagGrp(該變量反向指到OS_FLAG_GRP,用來記錄事件組),OSFlagNodeFlags(標識任務和 該節點關聯的任務正在等待的事件標志)和OSFlagNodeWaitType(標識該節點相關聯任務正在等待的方式:是全部等到,還是只等其中一個)。 從上面不難看出,OS_FLAG_GRP其實相當于ECB中的除了等待任務表的其他三個變量,而OS_FLAG_NODE相當于等待任務表,不同的是,由 于等待的任務不是僅僅等待一個事件,而是等待一系列事件,這樣,等待任務表就不能勝任了——因為等待任務表只能標明哪些個任務正在等待,但是等待的目標是 唯一的,而這里等待的目標可能會是多個!
6.2 核心功能函數:
由于用到了不同的數據結構,OS_EventWaitListInit,OS_EventTaskRdy,OS_EventTaskWait和 OS_EventTO就必須重新設計,作者在這里設計了另外的核心功能函數,OS_FlagBlock,OS_FlagRdy和 OS_FlagUnlink。
6.2.1 OS_FlagBlock:其作用相當于OS_EventTaskWait:將當前任務從就緒任務表中移走,更新當前任務的TCB,不同的是,在 OS_EventTaskWait中將當前任務加入等待任務表,而這里由于沒有用到等待任務表,而是創建一個OS_FLAG_NODE,換句話說,只要有 OS_FLAG_NODE就表明有任務在等待事件組,其實原理上和等待任務表是一樣的。
6.2.2 OS_FlagRdy:其作用相當于OS_FlagTaskRdy:將OS_FLAG_NODE所指向的任務的TCB更新以表明等到了事件組,如果該任務 不在等待其他的目標,將其加入就緒任務表中。然后用OS_FlagUnlink將此任務的OS_FLAG_NODE刪除。
6.2.3 OS_FlagUnlink:該函數主要是把特定的OS_FLAG_NODE從等待任務列表中刪除。
6.3 核心函數和信號量類似,有四個,其實現比較簡單:
6.3.1 OSFlagCreate: 創建一個事件組:從系統事件組緩沖區中申請一個OS_FLAG_GRP,然后初始化該OS_FLAG_GRP。
6.3.2 OSFlagDel:刪除一個事件組:和信號量的OSSemDel幾乎完全一樣,不同的是用OS_FlagRdy而不是OS_EventTaskRdy。
6.3.3 OSFlagPend:等待一個事件組:這里的等待有兩種情況:等待所有的事件到來,等待任何一個事件到來。不管哪種情況,都是先判斷需要的標識是不是已 經到來,如果到來的話就更新事件組,然后返回;如果沒有到來的話,就會用OS_FlagBlock為當前任務產生一個OS_FLAG_NODE,并將其加 進雙向鏈表里。
6.3.4 OSFlagPost:標識一個事件組一些標識已經到來:先更新OS_FLAG_GRP,然后遍歷OS_FLAG_NODE的雙向鏈表,用OS_FlagRdy使那些正在等待這些標識的任務不再等待。
7 各種通訊機制的比較
綜合以上五種通訊機制可以看出:信號量是最普通的通訊機制,當需要一般的同步或者資源保護的話,用信號量就可以了;互斥體主要用來解決優先級反 轉的問題,當需要在任務間同步資源的時候,用互斥體;郵箱主要用來將一個消息從一個任務發送到另一個任務;隊列可以看作是擴展的郵箱,隊列可以發送多個消 息;事件組是最復雜的一個通許機制,但最靈活,可以在任務間用多個事件標識來同步,因此用起來需要特別注意!
關鍵詞:
ucOS-I通訊機
評論