ucos隊列的實現--源碼分析

來源:互聯網
上載者:User

標籤:

   之前說到事件,講了事件,訊號量和互斥訊號量,還有一個隊列沒說,今天說說隊列.

   隊列是用在任務之間傳送多個訊息的時候,a任務發送訊息,b任務發送訊息,然後c任務可以依次去提取出b和a傳遞的訊息,不會造成系統的阻塞,他的實現結構如下

在隊列的實現中,也是使用事件ecb,OSEventType為OS_EVENT_TYPE_Q類型,而其OSEventPtr指向一個QS_Q結構的指標,該結構的定義如下

typedef struct os_q {                   /* QUEUE CONTROL BLOCK                                         */

    struct os_q   *OSQPtr;              /* 指向下一個隊列控制塊 */

    void         **OSQStart;            /* 指向訊息指標數組的起始地址*/

    void         **OSQEnd;              /* 指向訊息指標數組的下一個單元,構成迴圈數組緩衝區 */

    void         **OSQIn;               /*指向插入訊息的位置,其與OSQEnd相等時,調整到指向數組的起始單元*/

    void         **OSQOut;              /*指向被取出訊息的位置,其與OSQEnd相等時,調整到指向數組的起始單元 */

    INT16U         OSQSize;             /*數組的長度*/

    INT16U         OSQEntries;          /*以存放訊息指標的元素數目*/

} OS_Q;

   我們可以稱呼這種結構叫做QCB,隊列控制快.在系統初始化的時候會有很多個隊列控制快,系統初始化的時候將隊列控制快串連成一個鏈表,如下

OS_EXT  OS_Q              OSQTbl[OS_MAX_QS];      

   隊列控制快數量為OS_MAX_QS,該參數在os_cfg.h檔案中指定

#define OS_MAX_QS                 5u 

   系統存放的空閑隊列控制塊鏈表指標為

OS_EXT  OS_Q             *OSQFreeList;            

   在系統初始化的時候os_init函數中調用OS_QInit函數,該函數中有如下代碼

for (ix = 0u; ix < (OS_MAX_QS - 1u); ix++) {     /* Init. list of free QUEUE control blocks        */

    ix_next = ix + 1u;

    pq1 = &OSQTbl[ix];

    pq2 = &OSQTbl[ix_next];

    pq1->OSQPtr = pq2;

}

pq1         = &OSQTbl[ix];

pq1->OSQPtr = (OS_Q *)0;

OSQFreeList = &OSQTbl[0];

   可以看到,這一段類似於tcb和ecb的初始化,將OSQTbl結構串連成鏈表,鏈表頭為OSQFreeList,之後,當建立隊列的時候從空閑鏈表中取出鏈表頭作為隊列事件,如下

if (pq != (OS_Q *)0) {                 

    OSQFreeList            = OSQFreeList->OSQPtr;

    OS_EXIT_CRITICAL();

    pq->OSQStart           = start;             

    pq->OSQEnd             = &start[size];

    pq->OSQIn              = start;

    pq->OSQOut             = start;

    pq->OSQSize            = size;

    pq->OSQEntries         = 0u;

    pevent->OSEventType    = OS_EVENT_TYPE_Q;

    pevent->OSEventCnt     = 0u;

  pevent->OSEventPtr     = pq;

    可以看到第二句話裡面就是講空閑隊列控制塊鏈表的鏈表頭後移動到下一個元素,然後將start元素進行賦值,這個start元素師建立的時候給定的,參數如下

OS_EVENT  *OSQCreate (void    **start,INT16U    size)

   第一個參數為一個指標數組,第二個參數為指標數組大小,也就是說,start指向一個指標數組的第一個元素地址,而數組裡面存放的是指向具體的訊息的指標,我們可以形象的說,start相當於一個messagetable的首地址.

   系統發送訊息佇列的時候使用函數OSQPost函數,其中核心代碼為

*pq->OSQIn++ = pmsg;                             

pq->OSQEntries++;                                

if (pq->OSQIn == pq->OSQEnd) {                    

  pq->OSQIn = pq->OSQStart;

   這段代碼向列表中添加一個元素,然後當添加的元素超過end的時候迴圈到頭上,一般來說,隊列取出元素會分為先進先出和後進先出兩種,我們先來看看申請隊列的函數就能明白ucos採用了什麼方式,申請隊列的函數為OSQPend函數

if (pq->OSQEntries > 0u) {                 

  pmsg = *pq->OSQOut++;                   

  pq->OSQEntries--;                       

  if (pq->OSQOut == pq->OSQEnd) {         

     pq->OSQOut = pq->OSQStart;

  }

   這段代碼需要和上面兩段結合起來看,初始化的時候OSQIn和OSQOut都指向start頭,插入的時候OSQIn++,取出的時候OSQOut++,當插入第三個元素之後, OSQIn指向了start+3,但是OSQOut依然是指向start的,取出元素的時候取出的是最早添加到隊列中的元素,因此可以認為,系統的隊列維護方式是先進先出, OSQEntries標識系統中該隊列含有的訊號數量,只有當數量不為0的時候,才能從隊列中取出元素

   另外,為了系統靈活性,ucos提供了函數可以發送訊息到隊列開頭,函數為OSQPostFront,實現如下

pq->OSQOut--;

*pq->OSQOut = pmsg;                              

pq->OSQEntries++;  

   可以看到,這個函數的實現和OSQPost的實現方式並不同, OSQPost的實現依靠的是OSQIn,而OSQPostFront依靠的是OSQOut,原因仔細想想也很簡單,因為OSQIn和OSQOut是相關聯的,我們來打個比方,如果此時OSQOut和OSQIn都指向start+1的位置,此時OSQPost三個元素,那麼OSQIn為start+4,但是OSQOut依然是start+1,這個時候我們要在隊列的頭部插入一個元素,那麼選擇有兩種,第一個是將之前插入的元素每一個都往後移動,使得OSQOut指向剛剛插入的元素,這樣需要迴圈移植3個元素,時間不可測,犯了作業系統的大忌,所以不可取,不如直接將元素排入佇列, OSQOut往前移動一位,此時OSQOut為start,到OSQIn距離為四個元素,很好的實現了目標

  但是,實現這個的前提是我們實現了迴圈隊列,而訊號隊列正好是迴圈隊列.

說到這裡隊列的原理基本講清楚了,接下來總結一下

建立訊息佇列

QSQCreate

請求訊息佇列

OSQPend

向訊息佇列發送訊息

OSQPost

發送訊息到隊列頭部

OSQPostFront

清空訊息佇列

OSQFlush

刪除訊息佇列

OSQDel

查詢訊息佇列

OSQQuery

訊息佇列使用了訊息佇列控制塊qcb,隊列控制塊構成空閑鏈表,建立隊列每次從空閑鏈表中去取出一個元素,訊息控制塊內部擁有一個迴圈鏈表,over

ucos隊列的實現--源碼分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.