UCOS學習筆記——消息隊列

消息隊列

消息隊列的基本概念

隊列又稱消息隊列,是一種常用於任務間通信的數據結構,隊列可以在任務與任務間、中斷和任務間傳遞信息
μC/OS中使用隊列數據結構實現任務異步通信工作,具有如下特性:
●消息支持先進先出方式排隊,支持異步讀寫工作方式。
●消息支持後進先出方式排隊,往隊首發送消息(LIFO) 。
●讀消息隊列支持超時機制。
●可以允許不同長度的任意類型消息
●一個任務能夠從任意一個消息隊列接收和發送消息。.
●多個任務能夠從同一個消息隊列接收和發送消息。
●當隊列使用結束後,可以通過刪除隊列函數進行刪除。

消息變量組成:

指向下一條消息的指針、用於表明該消息所指向數據的大小的變量、存放消息最後一次被提交的時間戳的變量、消息中包含一個指向實際數據的指針 ,如下圖所示:
消息發送者和接收者都不知道消息中數據的結構因爲這些都通過uC/OS-III 的 API 隱藏起來了
在這裏插入圖片描述
uC/OS-III 維護一個消息池。消息池的大小通過 OS_CFG_APP.H中的
OS_CFG_MSG_POOL_SIZE 設置。
當 uC/OS-III 被初始化時, 消息就會以單向列表的形式鏈接起來如下圖。注意的是這個列表由結構體 OS_MSG_POOL 管理, 它包含 3 個部分: .NextPtr 指向該消息列表、 .NbrFree 包含了該隊列的空閒消息數、 .NbrUsed 包含了該隊列中已被使用的消息數。
在這裏插入圖片描述
消息的排列由結構體 OS_MSG_Q 控制,如圖
Alt

  • InPtr
  • OutPtr 指向下一個將要被插入到隊列的消息。指向下一個將要被釋放的消息。
  • NbrEntriesSize 包含了該隊列所能接受的最大消息數。隊列滿後再往其中發送消息,消息將不會被插入。
  • NbrEntries 當前隊列中的消息數
  • NbrEntriesMax 記錄了到目前爲止隊列中存放的最大消息數。

消息隊列的工作過程

在UCOS-III中定義了一個數組0SCfg MsgPool[OS_CFG_MSG_ POOL_ SIZE],在系統初始化的時候就將這個大數組的各個元素串成單向鏈表,組成我們說的消息池,而這些元素我們稱之爲消息。
消息隊列是內核對象。事實上,可以分配任意個消息隊列(只要處理器的 RAM 足夠的話)。通過消息隊列用戶可以做很多事情,如下圖所示。然而, ISR 中只能
調用 OSQPost()。
在這裏插入圖片描述
消息隊列是先入先出模式(FIFO)。然而, uC/OS-III 也可以將其設置爲後入先出模式(LIFO)。 若任務或 ISR 發送緊急消息給另一個任務時, 後入先出模式是非常有用的, 在這種情況下, 該緊急消息繞過消息隊列中的其他消息。消息隊列的長度可以在運行時設置。如上圖,接收任務旁的沙漏表示該任務可以設置等待期限。如果任務沒有在規定時間內接收到該消息, uC/OS-III 會返回一個錯誤代
號表示任務被就緒不是因爲接收到消息,而是等待超時。
消息隊列中存放了等待該消息的任務。多個任務可以在消息隊列中等待消息,如圖 下圖所示。當一個消息被髮送到消息隊列時,等待該消息的高優先級任務接收這個消息。 消息發送者可以廣播這個消息給消息隊列中的所有任務。 在這種情況下, 如果接收到消息中有優先級高於消息發送者優先級的任務, uC/OS-III 就會切換到這個高優先級的任務。 注意: 不是每個任務都需要設置等待期限, 有些任務可能需要永遠等待這個消息
在這裏插入圖片描述

消息隊列的常用函數

消息隊列函數總結在這裏插入圖片描述

任務中消息隊列總結在這裏插入圖片描述

消息隊列發送函數OSQPost()
任務或者中斷服務程序都可以給消息隊列發送消息,當發送消息時,如果隊列未滿,就說明運行信息入隊。μC/OS 會從消息池中取出一個消息,掛載到消息隊列
的末尾(FIFO發送方式),如果是LIFO發送方式,則將消息掛載到消息隊列的頭部,然後將消息中MsgPtr成員變量指向要發送的消息(此處可以理解爲添加要發送的信息到消息(塊)中),如果系統有任務阻塞在消息隊列中,那麼在發送了消息隊列的時候,會將任務解除阻塞。
消息隊列獲取函數OSQPend()
當任務試圖從隊列中的獲取消息時,用戶可以指定一個阻塞超時時間,當且僅
當消息隊列中有消息的時候,任務才能獲取到消息。在這段時間中,如果隊列
爲空,該任務將保持阻塞狀態以等待隊列消息有效。當其他任務或中斷服務程
序往其等待的隊列中寫入了數據,該任務將自動由阻塞態轉爲就緒態。當任務
等待的時間超過了用戶指定的阻塞時間,即使隊列中尚無有效消息,任務也會
自動從阻塞態轉爲就緒態。

消息隊列使用注意事項及總結

注意事項

1、使用OSQPend()、OSQPost()等 這些函數之前應先創建需消息隊列隊列讀取採用的是先進先出(FIFO、 LIFO) 模式
2、無論是發送或者是接收消息都是以數據引用的方式進行。
3、隊列是具有自己獨立權限的內核對象,並不屬於任何任務。所有任務都可以向
同一隊列寫入和讀出。
4、消息的傳遞實際,上只是傳遞傳送內容的指針和傳送內容的字節大小,在獲取消息之前不能釋放存儲在消息中的指針內容

總結

  • 當任務或 ISR 發送消息給另一個任務時,通過消息隊列是很有效的方法。 被髮送的消息中的數據必須被存儲, 因爲傳送的是數據地址而不是實際的數據。
  • 任務在等待消息的時候不會佔用 CPU。
  • 使用任務內部的消息堆棧更爲簡單和高效。 當設置 OS_CFG.H 中的 OS_CFG_TASK_Q_EN 爲 1 時使能任務內部消息隊列
  • 如果多個任務等待同一個消息隊列中的消息,分配一個 OS_Q 並讓任務所等待的消息發送到 OS_Q 中。 特別的, 可以廣播消息給所有在消息隊列中等待的任務。設置 OS_CFG.H 中的 OS_CFG_Q_EN 爲1 開啓消息隊列服務。
    -消息通過結構體 OS_MSG(從 uC/OS-III 的消息池中獲得)被髮送。設置消息隊列的大小,和消息池的大小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章