vxworks中任務間的通信支持信號量、消息隊列、管道、信號、事件

vxworks中任務間的通信支持信號量、消息隊列、管道、信號、事件
2011-07-01 19:50

vxworks中任務間的通信支持信號量、消息隊列、管道、信號、事件、共享內存等。
一:信號量
信號量分二進制信號量、互斥信號量、計數信號量。
1:二進制信號量
(1)semBCreate():創建二進制信號量
SEM_ID semBCreate(int options,SEM_B_STATE initialState)
options 可以爲基於優先級的隊列EM_Q_PRIORITY(0x1)或者是基於先進先出的隊列SEM_Q_FIFO(0X0).
initialState 可以是信號量初始化爲滿SEM_FULL(1)或者爲空SEM_EMPTY(0)。
(2)semTake(): 獲取信號量
STATUS semTake(SEM_ID semID,int timeout)
semID爲信號量ID。
timeout 表示任務一直等待信號量,直到可用WAIT_FOREVER(-1)或者不等待,直接下步操作NO_WAIT(0)。
(3)semGive():釋放信號量
STATUS semGive(SEM_ID semID)
(4)semFlush():喚醒信號量
STATUS semFlush(SEM_ID semID)
通過此函數可以將所有阻塞在信號量(WAIT_FOREVER)上的任務釋放。
(5)semDelete():刪除信號量
STATUS semDelete(SEM_ID semID)
(6)semInfo():得到阻塞在信號量上的所有任務ID列表
int semInfo(SEM_ID semID,int idList[],int maxTasks)
idList[]爲要顯示任務ID的數組。
maxTasks爲要顯示的任務最大數。
(7)semShow():顯示信號量的相關信息
STATUS semShow(SEM_ID semID,int level)
level分概括(0),詳細(1)。

2:互斥信號量
互斥信號量相比二進制信號量增加了防止優先級倒置、遞歸訪問等功能。
(1)semMCreate():創建互斥信號量
SEM_ID semMCreate(int options)
options 的選項有:
- SEM_Q_PRIORITY(0x1):需要獲取信號量的任務基於優先級原則排列。
- SEM_Q_FIFO(0x0):需要獲取信號量的任務基於先進先出原則排列。
- SEM_DELETE_SAFE(0x4):保護任務防止意外刪除,當執行獲取信號量(semtake)時操作時會默認執行任務保護

(taskSafe)操作,當執行釋放信號量(semGive)操作時會默認執行取消任務保護(taskUnsafe)操作。
- SEM_INVERSION_SAFE(0x8):保護系統,防止系統出現優先級倒置現象。
- SEM_EVENTSEND_ERR_NOTIFY(0X10):任務發送事件失敗時,會發送錯誤號。
(2)semMGiveForce():強制釋放互斥信號量
STATUS semMGiveForce(SEM_ID semId)

3:計數信號量
計數信號量主要用於蒐集某些信號量。
SEM_ID semCCreate(int options,int initialCount)
options爲信號量屬性或類型
initialCount 初始化計數
/************************************************************************
示例代碼:以二進制信號量爲例
STATUS task1(void); //聲明兩個任務
STATUS task2(void);
int taskId1,taskId2; //全局變量任務ID
SEM_ID semTest1,semTest2; //信號量
int initTask()   //任務初始化
{
taskId1=taskSpawn("task1",120,0,10240,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0); //創建任務1
taskId2=taskSpawn("task2",120,0,10240,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0); //創建任務2
semTest1=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); //創建信號量1
semTest2=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); //創建信號量2
if(semTest1==NULL)   //如果創建信號量失敗,則返回錯誤,成功着返回OK
{
   return ERROR;
}
return OK;
}

STATUS task1(void) //任務1主體函數
{
while(1)
{
semGive(semTset1);             //任務1釋放信號量1
printf("任務1釋放了信號量!\n");
semTake(semTest2,WAIT_FOREVER);//任務1得到信號量2,在任務2沒有釋放信號量2前,任務1在此等待
printf("任務1得到了信號量!\n");
}
}

STATUS task1(void)//任務2主體函數
{
while(1)
{
semTake(semTest1,WAIT_FOREVER);//任務2得到信號量1,在任務1沒有釋放信號量1前,任務2在此等待
printf("任務2得到了信號量!\n");
semGive(semTset2);             //任務2釋放信號量2
printf("任務2釋放了信號量!\n");
}
}
********************************************************************************/

二:消息隊列
Vxworks系統中提供了兩種消息隊列庫:msgQLib和mqPxLib。
msgQLib提供了標準的vxworks消息隊列,而msPxLib提供了POSIX消息隊列。
(1)msgQCreate():創建或者初始化消息隊列
MSG_Q_ID msgQCreate(int maxMsgs,int maxMsgLength,int options)
maxMsgs 爲最大消息數
maxMsgLength 消息的最大字節數
options 信息的屬性
其中options可以爲
-MSG_Q_FIFO(0x00):任務以FIFO原則排隊。
-MSG_Q_PRIORITY(0X01):任務以基於優先級的原則排隊。
-MSG_Q_EVENTSEND_ERR_NOTIFY(0X02):消息隊列向他的註冊任務發送事件失敗時,將返回一個ERROR的值,並且正確地設置errno。成功創建消息隊列後會返回消息隊列ID。
(2)msgQDelete():刪除消息隊列
STATUS msgQDelete(MSG_Q_ID msgQId) //要刪除的消息隊列
(3)msgQSend():發送消息隊列
STATUS msgQSend(MSG_Q_ID msgQId, //要發送的消息隊列
                char* buffer,    //要發送的消息指針
                UINT nBytes,     //消息長度
                int timeout,     //等待的tick數 當爲NO_WAIT(0)時,表示消息沒有發送出去也立刻返回,當爲WAIT_FOREVER(-1)時,則一直等待發送,知道消息發生發送出                                   去
                int priority     //普通(MSG_PRI_NORMAL(0))還是緊急模式(MSG_Q_PRI_URGENT(1))
               )
(4)msgQReceive():從消息隊列中收取消息
int msgQReceive(MSG_Q_ID msgQId, //接收的消息隊列ID
                char* buffer,     //接收消息的BUFFER指針,如果消息超過了BUFFER的最大字節數,則超出的部分將被丟棄。
                UINT maxNBytes,   //BUFFER的最大字節數
                int timeout       //等待的tick數,當爲NO_WAIT(0)時,表示消息沒有發送出去也立刻返回,當爲WAIT_FOREVER(-1)時,則一直等待發送,知道消息發生發送                                      出去
               )
(5)msgQNumMSgs():得到排隊到消息隊列中的消息數
int msgQNumMsgs(int MSG_Q_ID msgQId) //消息隊列的ID
該函數返回排隊到消息隊列中的消息數。
/**********************************************************************************
示例代碼:
STATUS task1(void); //聲明兩個任務
STATUS task2(void);

int taskId1,taskId2; //全局變量任務ID
MSG_Q_ID msgQId1; //消息隊列ID
char buffer[50]; //接收消息的buffer

int initTask()   //任務初始化
{
taskId1=taskSpawn("task1",120,0,10240,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0); //創建任務1
taskId2=taskSpawn("task2",120,0,10240,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0); //創建任務2
msgQId=msgQCreate(20,50,MSG_Q_PRIORITY); //創建消息隊列
if(msgQId==NULL)   //如果創建信號量失敗,則返回錯誤,成功着返回OK
{
   return ERROR;
}
return OK;
}

STATUS task1(void) //任務1主體函數
{
while(1)
{
if(msgQSend(msgQId1,MSG,sizeof(MSG),WAIT_FOREVER,MSG_PRI_NORMAL)==ERROR)//向消息隊列發送消息MSG
{
    return ERROR;
}
taskDelay(10);
}
}

STATUS task1(void)//任務2主體函數
{
while(1)
{
if(msgQReceive(msgQId1,buffer,50,WAIT_FOREVER)==ERROR)//從消息隊列接收消息
{
    return ERROR;
}
printf("消息是%s\n",buffer);//將消息的內容顯示出來
}
}
*********************************************************************************/

三:管道
管道是一種虛擬的I/O設備,所以對管道可以通過標準的I/O口函數進行操作。
(1)pipeDevCreate():創建管道
STATUS pipeDevCreate(char* name,int nMessages,int nBytes)
name 爲管道名
nMessages 爲管道中的最大數目
nBytes 爲每個消息的字節數
(2)pipeDevDelete():刪除管道
STATUS pipeDevDelete(char* name,BOOL force)
force 爲是否要強制刪除
(3)pipeDrv():初始化管道
STATUS pipeDrv(void)
/*********************************************************************************
示例代碼:管道
#define MSG "hello"

STATUS task1(void); //聲明兩個任務
STATUS task2(void);

int taskId1,taskId2; //全局變量任務ID
int pipeId;
int temp;
char buffer[50];

int initTask()   //任務初始化
{
taskId1=taskSpawn("task1",120,0,10240,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0); //創建任務1
taskId2=taskSpawn("task2",120,0,10240,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0); //創建任務2
temp=pipeDevCreate("/pipe/pipeTest",50,50); //創建管道
if(temp==ERROR)
{
return ERROR;
}
pipeId=open("/pipe/pipeTest",O_RDWR,0); //打開管道
if(pipeId==ERROR)
{
return ERROR;
}
return OK;
}

STATUS task1(void) //任務1主體函數
{
while(1)
{
if(write(pipeId,MSG,sizeof(MSG))==ERROR)//向管道寫信息
{
    return ERROR;
}
taskDelay(10);
}
}

STATUS task2(void)//任務2主體函數
{
while(1)
{
if(read(pipeId,buffer,50)//向管道里讀信息
{
    return ERROR;
}
printf("消息是%s\n",buffer);//將消息的內容顯示出來
}
}
*************************************************************************/

四:信號
信號是由事件引發的軟中斷,中斷並非由外界硬件產生,而是由內部程序自己產生。需要特別注意的是,信號的處理程序並非在中斷上下文中進行處理,而是在接受任務本身的上下文中進行處理。
(1)signal():將信號與特定的處理程序綁定
void (*signal(int signo,void(*pHandler)()))
signo 爲信號ID,
*pHandler () 爲信號處理程序
(2)kill():向指定的任務發送信號
int kill(int tid,int signo)
tid 爲任務ID
signo 爲要發送的信號
/**************************************************************************************
示例代碼:信號
#define MSG "hello"

STATUS task1(void); //聲明兩個任務
STATUS task2(void);

int taskId1,taskId2; //全局變量任務ID
int signalTest=5;

int initTask()   //任務初始化
{
taskId1=taskSpawn("task1",120,0,10240,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0); //創建任務1
taskId2=taskSpawn("task2",120,0,10240,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0); //創建任務2
return 0;
}

STATUS task1(void) //任務1主體函數
{
signal(signalTest,sigISR); //將信號與信號處理程序綁定
while(1)
{

}
}

void sigISR(int sig)//任務2主體函數
{

if(sig==signalTest)
{
   logMsg("信號數是%d\n",sig,0,0,0,0,0); //輸出信息
}
return;

}

STATUS task2(void) //任務1主體函數
{
while(1)
{
kill(taskId1,signalTest);//發送信號給任務1
taskDelay(10);
}
}
******************************************************************************************/

五:事件
事件用於任務之間或者任務與ISR,或者任務與系統之間。任務最多可以註冊24個事件,每個任務的TCB中有專門的事件寄存器,但此寄存器不可直接訪問,有事件發生變化的時候會改變相應的寄存器值。
(1)eventReceive():接收事件
STATUS eventReceive(UINT32 events,UINT8 options,int timeout,UINT32* pEventsReceived)
events 爲等待的事件號
timeout 爲等待的事件
pEventsReceived 爲反映接收到的事件變量
其中options可選項爲:
-EVENTS_WAIT_ANY(0X1):等待任何一個事件發生了就就緒
-EVENTS_WAIT_ALL(0X0):等待所有事件發生了再就緒
-EVENTS_RETURN_ALL(0X2):返回所有等待的和不等待的事件
-EVENTS_FETCH(0X80):pEventsReceived變量設置已經接收到的事件相應位,並且立刻返回。
(2)evenSend():發送事件
STATUS eventSend(int taskId,UINT32 events)
taskId 爲要發送的任務
events 爲要發送的事件
(3)evenClear():清除當前任務的所有事件
(4)semGive():將事件拷貝到在該信號量註冊的事件寄存器
(5)msgQSend():將事件拷貝到在該隊列註冊的事件寄存器
/**********************************************************************************************
示例代碼:事件

STATUS task1(void); //聲明兩個任務
STATUS task2(void);

int taskId1,taskId2; //全局變量任務ID
SEM_ID semId1; //促使事件發生的資源

int initTask()   //任務初始化
{
taskId1=taskSpawn("task1",120,0,10240,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0); //創建任務1
taskId2=taskSpawn("task2",110,0,10240,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0); //創建任務2
semId1=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY); //創建二進制信號量
if(semId1==NULL)
{
return ERROR;
}
return OK;
}

STATUS task1(void) //任務1主體函數
{
UINT32 tmp_receive;
semEvStart(semId1,VXEV01,EVENTS_OPTIIONS_NONE);//任務1在資源:二進制信號量semId1上註冊,如果資源發生變化,則任務會收到相應的事件
while(1)
{
eventReceive(VXEV01,WAIT_ANY,WAIT_FOREVER,&tmp_receive);//等待事件發生
if((tmp_receive&VXEV01)!=0)
{
    printf("收到事件!\n");
}
}
}

STATUS task2(void)//任務2主體函數使信號量的可用狀態發生變化,促使事件發生
{
while(1)
{
semGive(semId1);
semTake(semId1,NO_WAIT);
taskDelay(10);
}
}
 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章