现在的位置: 首页 > 综合 > 正文

vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件

2013年07月04日 ⁄ 综合 ⁄ 共 8147字 ⁄ 字号 评论关闭
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);
}
}
 

抱歉!评论已关闭.