1、信箱
信箱(Mail Box)是一個類似於旗 號的同步原語,線程可以使用信箱來等待某個事件的發生。與旗號不同之處是,信箱還可以在事件發生時被線程用來傳遞一些資料。這些被稱為消息的資料通常是資 料結構的指標,保存在信箱內。產生事件並提供這些消息的線程在其他線程準備好接收消息之前不會被阻塞,對信箱的等待、喚醒、傳遞消息都是原子操作,不可被 其他線程中斷。信箱只有有限的容量,預設配置為10個槽位元。當信箱被填滿時,產生消息的線程將被阻塞,直到信箱空間再次可用。
2、信箱的實現與操作
在使用信箱之前,必須使用API函數cyg_mbox_create創建一個信箱。每個信箱都有一個唯一的控制碼,由第一個參數帶回,使用其他信箱操作函數對信箱進行操作時,都將使用這個控制碼。信箱的產生需要核心為其提供一個記憶體區,第二個參數將帶回該記憶體區的指標。如果不再需要某個信箱,可以使用cyg_mbox_delete函數將其刪除,它只簡單的作廢沒有發送的消息。
用於等待信箱的函數是cyg_mbox_get。如果信箱內有一個懸掛的被cyg_mbox_put函數發出的消息,則cyg_mbox_get將立即返回信箱內沒有被取走的最早進入的消息指標,此處遵循FIFO原則;如果信箱內沒有懸掛消息,此線程將被阻塞直到有消息可用。cyg_thread_release函數可以打破線程的這種阻塞狀態,但此時cyg_mbox_get將返回空指標。信箱遵循先進先出的原則,不支援帶優先順序的消息。
cyg_mbox_get有兩個變體。它的一個變體是cyg_mbox_timed_get,該函數將等待直到有一個消息可用或者等待超時發生(等待消息成功返回消息指標,等待超時返回空指標NULL)。另一個變體是cyg_mbox_tryget,這是一個非阻塞函數,此函數不等待直接返回一個消息或者空指標。
如果要向信箱發送新的消息,可以調用cyg_mbox_put函數或者它的變體函數。該函數有兩個參數,一個是信箱的控制碼,另一個是要發送的消息的指標。如果信箱中有空的槽位元,則消息將被立即放置到該槽位上,如果此時有一個正在等待的線程,該線程將被喚醒以便能夠收到該消息。如果信箱滿,cyg_mbox_put函數將阻塞直到有可用的槽位。其變體函數cyg_mbox_timed_put具有超時等待功能,cyg_mbox_tryput是一個非阻塞函數,如果沒有空餘槽位其會立即返回false。
有四個API函數用於檢測信箱的當前狀態。在使用它們的時候,應該注意它們返回的結果可能不是信箱當前最新的狀態。因為在得到信箱狀態到返回之間,信箱有可能被其他線程修改過。cyg_mbox_peek函數返回信箱內當前的消息數,cyg_mbox_peek_item函數提取信箱內的第一個消息,但消息仍然保留在信箱內。cyg_mbox_waiting_to_get和cyg_mbox_waiting_to_put函數表明當前是否有線程被阻塞在對信箱的讀寫操作上。
每個信箱的槽位元數可以通過配置選項CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE進行控制,其預設值是10,並且所有信箱大小都是相同的。
程式 :
#include <cyg/hal/hal_arch.h>
#include <cyg/kernel/kapi.h>
#include <stdio.h>
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
cyg_uint8 Stack_MBoxGet[STACK_SIZE]; // 執行緒MBox_Get的堆疊
cyg_handle_t H_MBoxGet; // 執行緒MBox_Get的控制碼
cyg_thread Obj_MBoxGet; // 執行緒MBox_Get的信息結構體
cyg_uint8 Stack_MBoxPut[STACK_SIZE]; // 執行緒MBox_Put的堆疊
cyg_handle_t H_MBoxPut; // 執行緒MBox_Put的控制碼
cyg_thread Obj_MBoxPut; // 執行緒MBox_Put的信息結構體
cyg_handle_t H_MBox; // 消息郵箱的控制碼
cyg_mbox Obj_MBox; // 消息郵箱的數據對象
//====================================================
// 語法格式:void MBox_Get(cyg_addrword_t data)
// 功能描述: 主執行緒
//====================================================
void MBox_Get(cyg_addrword_t data)
{
void * Message = NULL;
while(1)
{
Message = cyg_mbox_get(H_MBox);
printf("\nMessage addr is:%u", (int)Message);
Message = NULL;
}
}
//====================================================
// 語法格式:void MBox_Put(cyg_addrword_t data)
// 功能描述: 主執行緒
//====================================================
void MBox_Put(cyg_addrword_t data)
{
unsigned int Msg[10] = {0,1,2,3,4,5,6,7,8,9};
while(1)
{
cyg_thread_delay(200);
cyg_mbox_put(H_MBox, (void *)Msg);
printf("\nMessage has been sent to MailBox,and the addr of msg is %u", (unsigned int)Msg);
}
}
//====================================================
// 語法格式:void cyg_user_start(void)
// 功能描述: 主函數
//====================================================
void cyg_user_start(void)
{
cyg_mbox_create(&H_MBox, &Obj_MBox); // 初始化消息郵箱
cyg_thread_create(10, // 執行緒優先級
MBox_Get, // 執行緒函數名
(cyg_addrword_t)0, // 執行緒參數
"MBox_Get", // 執行緒名稱
(void *)Stack_MBoxGet, // 執行緒堆疊
STACK_SIZE, // 執行緒堆疊大小
&H_MBoxGet, // 返回執行緒控制碼
&Obj_MBoxGet); // 執行緒信息結構體
cyg_thread_create(4, // 執行緒優先級
MBox_Put, // 執行緒函數名
(cyg_addrword_t)0, // 執行緒參數
"MBox_Put", // 執行緒名稱
(void *)Stack_MBoxPut, // 執行緒堆疊
STACK_SIZE, // 執行緒堆疊大小
&H_MBoxPut, // 返回執行緒控制碼
&Obj_MBoxPut); // 執行緒信息結構體
cyg_thread_resume(H_MBoxGet); // 啟動執行緒
cyg_thread_resume(H_MBoxPut); // 啟動執行緒
return;
}
執行結果 :