ucos II 任務間 通訊之五:訊息佇列
如果把郵箱比作是訊號量的升級版,那訊息佇列就是郵箱的升級版。郵箱可以實現從一個任務向另外一個任務發送一個指標變數,訊息佇列則可以實現從一個任務向另外一個任務發送很多個指標變數。而且每個指標指向的資料結構變數也可以有所不同。
使用訊息佇列需要注意的地方是:一個任務或者中斷服務子程式可以調用OSQPost(),OSQPostFront(),OSQFlush(),或者OSQAccept()函數。但是,只有任務可以調用OSQPend()和OSQQuery()函數。
我們知道,每個事件有一個對應事件控制塊,用於記錄有關於這個事件的資訊。訊息佇列也不例外,一個訊息佇列對應著一個隊列控制塊。
相對訊號量,郵箱而言,ucos II多定義了一個資料結構來儲存訊息佇列的資訊。定義如下:
typedef struct os_q {
struct os_q *OSQPtr;
void **OSQStart;
void **OSQEnd;
void **OSQIn;
void **OSQOut;
INT16U OSQSize;
INT16U OSQEntries;
} OS_Q;
.OSQPtr在空閑隊列控制塊中連結所有的隊列控制塊。一旦建立了訊息佇列,該域就不再有用了。
.OSQStart是指向訊息佇列的指標數組的起始地址的指標。使用者應用程式在使用訊息佇列之前必須先定義該數組。
.OSQEnd是指向訊息佇列結束單元的下一個地址的指標。該指標使得訊息佇列構成一個迴圈的緩衝區。
.OSQIn是指向訊息佇列中插入下一條訊息的位置的指標。當.OSQIn和.OSQEnd相等時,.OSQIn被調整指向訊息佇列的起始單元。
.OSQOut是指向訊息佇列中下一個取出訊息的位置的指標。當.OSQOut和.OSQEnd相等時,.OSQOut被調整指向訊息佇列的起始單元。
.OSQSize是訊息佇列中總的單元數。該值是在建立訊息佇列時由使用者應用程式決定的。在μC/OS-II中,該值最大可以是65,535。
.OSQEntries是訊息佇列中當前的訊息數量。當訊息佇列是空的時,該值為0。當訊息佇列滿了以後,該值和.OSQSize值一樣。 在訊息佇列剛剛建立時,該值為0。
Ucos II提供了7個對訊息佇列進行操作的函數
1. 建立一個訊息佇列,OSQCreate()
2. 等待一個訊息佇列中的訊息,OSQPend()
3. 向訊息佇列發送一個訊息(FIFO),OSQPost()
4. 向訊息佇列發送一個訊息(後進先出LIFO),OSQPostFront()
5. 無等待地從一個訊息佇列中取得訊息, OSQAccept()
6. 清空一個訊息佇列, OSQFlush()
7. 查詢一個訊息佇列的狀態,OSQQuery()
訊息佇列最根本的部分是一個迴圈緩衝區,其中的每個單元包含一個指標。隊列未滿時,.OSQIn指向下一個存放訊息的地址單元。如果隊列已滿(.OSQEntries與.OSQSize相等),.OSQIn則與.OSQOut指向同一單元。如果在.OSQIn指向的單元插入新的指向訊息的指標,就構成FIFO(First-In-First-Out)隊列。相反,如果在.OSQOut指向的單元的下一個單元插入新的指標,就構成LIFO隊列(Last-In-First-Out)。當.OSQEntries和.OSQSize相等時,說明隊列已滿。訊息指標總是從.OSQOut指向的單元取出。指標.OSQStart和.OSQEnd定義了訊息指標數組的頭尾,以便在.OSQIn和.OSQOut到達隊列的邊緣時,進行邊界檢查和必要的指標調整,實現迴圈功能。