天天看點

消息隊列在RTOS的應用

版權聲明:本文為半吊子子全棧工匠(wireless_com,同公衆号)原創文章,未經允許不得轉載。 https://blog.csdn.net/wireless_com/article/details/79544020

傳說網際網路應用有兩大利器,一個是緩存,另一個就是消息隊列。 一直相對消息隊列做一下梳理,希望早日另有成文。 一葉知秋,實際上消息隊列在嵌入式系統中同樣有着廣泛的應用。 近來緻力于IoT和智能硬體,現學習一下消息隊列在RTOS中的應用場景。

RTOS是一個管理CPU的軟體, 即微處理單元(MPU) , 還可能管理高效的DSP。 大多數 RTOS 核心是用 c 語言編寫的, 同時需要用彙編語言編寫一小部分代碼來适應不同的 CPU 架構。一個 RTOS 核心為開發者提供了許多有用的服務, 如多任務處理、中斷管理、通過消息隊列、信号量、資源管理、時間管理、記憶體分區管理等等。

應用程式或者最終地産品基本上會劃分為多個任務, 每個任務負責應用程式的一部分。 一個任務就是一個簡單的程式, 它有自己的 CPU使用時間。 根據任務的重要性, 每個任務都被賦予了優先級。

RTOS中的消息隊列

圖1 消息隊列是用于将内容傳遞給任務的核心對象

如圖1所示, 消息隊列是一個核心對象(即資料結構) , 通過這個對象, 消息從中斷服務例程(ISR)或任務發送到另一個任務。 應用程式可以有任意數量的消息隊列, 每一個都有自己的目的和用途。 例如, 消息隊列可以用來将從通信接口 ISR 接收到的資料包傳遞給一個任務, 而 ISR 則負責處理資料包。 另一個隊列可以用來将内容傳遞給顯示任務, 該任務将負責正确地更新顯示的内容。

消息通常是指向包含實際消息存儲區域的void指針。 這些指針可以指向任何東西, 甚至可以指向接收任務執行的函數。 是以, 它的實際含義取決于應用程式。 每個消息隊列都可以根據它将儲存的存儲量進行配置。 消息隊列可以配置為儲存單個消息或者 n 個消息。 隊列的大小取決于應用程式以及消費者的處理速度。

如果一個任務等待一條消息, 并且隊列中沒有消息, 則該任務将被挂起, 直到有消息發送到隊列中。 等待任務不消耗 CPU 時間, RTOS 可以運作其他任務。 如圖1所示, 挂起的任務可以指定逾時。 如果在指定時間内未收到消息, 則當該任務成為最高優先任務時, 将允許任務恢複執行(即 unblock)。 當任務執行時, 基本上會被告知它恢複的原因是因為逾時。

消息隊列通常作為先入先出(FIFO)實作, 這意味着收到的第一個消息将是從隊列中提取的第一個消息。 然而, 有些核心允許發送被認為比其他核心更重要的消息, 進而排在隊列的首位。 換句話說, 在"先入先出"順序中, 使該消息成為任務提取的第一條資訊。

消息隊列的另一個重要方面是, 消息本身需要保持從發送到處理的時間範圍。 這意味着不能将指針傳遞給棧變量等等。 為了将消息保持在作用域中, 通常會填充一個結構, 并從這些消息池中擷取, 如圖2所示。 

圖2 消息池的存儲區域

發送消息的 ISR 或任務将從池中擷取結構, 填充結構, 并将指針指向隊列的結構。 接收任務将從隊列中提取指針, 處理結構, 完成後将結構傳回到池中。 當然, 發送方和接收方都需要使用相同的池, 除非資料結構中的字段訓示使用了哪個池。

在 RTOS 中的許多消息隊列實作中, 如隊列已滿, 則發送到隊列的消息将被丢棄。 通常這不是一個問題, 應用程式的邏輯可以從這種情況中恢複。 然而, 如圖3所示, 實作一個發送任務會發送消息的機制是相當容易的:

圖3 如果隊列已滿, 則阻止發送

  1. 計數信号的初始化值與隊列可接受的最大條目數相對應
  2. 發送任務在允許将消息發送到隊列之前檢查信号量。 如果信号量值為零, 則發送方等待。
  3. 如果值為非零, 則信号量減少, 發送方将消息發送到隊列中
  4. 消息的接收方像往常一樣将消息隊列分隔開來
  5. 當收到消息時, 接收這将指針從隊列中取出并向信号量發出信号, 表示隊列中的條目已被釋放

如圖所示, 這個機制隻适用于兩個任務, 因為 ISR 不允許在信号量上配置設定信号。

消息隊列的典型用法

圖4顯示了消息隊列的不同用法:

1-4. 消息隊列通常用于從 ISR 發送消息或将任務發送到另一個任務, 如前面所讨論的那樣

5.但是, 如果消息符合指針的大小, 則不必發送實際消息及配置設定存儲區域。 例如, 如果一個32位指針, 那麼可以将模拟轉換器(ADC)從一個12位 ADC 讀取到一個指針, 并通過消息隊列發送,隻要接收這知道将值傳回整數即可, 這是完全合法的

6-7 一個任務如果知道這些消息将不會發送給它的,可以使用逾時機制在一定的時間内延遲自己。 在這種情況下, 一個能夠儲存單個條目的隊列就足夠了。 事實上, 如果另一個任務或 ISR 發送消息, 那麼延遲将被終止, 這可能也是想要實作的行為。

8 消息隊列可以作為一個信号量來簡單地向事件發生的任務發出信号。 在這種情況下, 資訊可以是任何東西。 隊列的大小取決于應用程式需要緩沖多少信号。

9-10 消息隊列也可以用作二進制信号量或用于資源共享的計數信号量。 對于二進制信号量, 隊列将包含單個消息, 并在隊列中放置消息(任何值)。 為了通路資源, 可以在隊列上配置設定一個任務。 如果隊列中有消息, 則該任務将獲得對資源的通路。 一旦使用了資源, 隊列就會被釋出, 進而根據需要放棄資源, 供其他任務使用。 同樣的機制也适用于使用 n 個資源實作計數信号, 隊列将預先填入n個虛拟消息。

11.消息實際上可以用來模拟事件标志, 其中32位指針大小的變量中,每一位可以代表一個事件

12.消息隊列可以用來實作棧結構,這基本上是 LIFO 機制的另一個用途。

總而言之,消息隊列有許多不同方式的使用場景。 事實上, 通過消息隊列,可以編寫相當複雜的應用程式。 使用消息隊列可以減少代碼的大小, 可以被模拟(信号、時間延遲和事件标志)許多其他的服務。

編譯自http://www.embedded-computing.com/dev-tools-and-os/the-many-uses-of-rtos-message-queues

繼續閱讀