一、前言
最近看了点事件驱动编程。了解到在时间驱动编程中,重要的是一个事件收集器、一个事件发送器和一个事件处理器。
这让我联想到VxWorks中的消息队列,控制发送的就是事件收集器,控制接收的就是事件发送器。
下面就一起来看看VxWorks消息队列相关的函数。
源码面前无细节,正好我有VxWorks5.5的源码,可以来看一下消息队列模块的实现。
想要下载VxWorks5.5的源码: VxWorks Net
二、VxWorks消息队列模块详解
VxWorks的消息队列模块包括源文件msgQLib.h和msgQLib.c。
为了控制文章篇幅和易于阅读,我将msgQLib.h的主要内容复制过来,了解一下消息队列模块的数据结构和函数方法。
msgQLib.h
typedef struct /* MSG_Q_INFO */
{
int numMsgs; /* OUT: number of messages queued */
int numTasks; /* OUT: number of tasks waiting on msg q */
int sendTimeouts; /* OUT: count of send timeouts */
int recvTimeouts; /* OUT: count of receive timeouts */
int options; /* OUT: options with which msg q was created */
int maxMsgs; /* OUT: max messages that can be queued */
int maxMsgLength; /* OUT: max byte length of each message */
int taskIdListMax; /* IN: max tasks to fill in taskIdList */
int * taskIdList; /* PTR: array of task ids waiting on msg q */
int msgListMax; /* IN: max msgs to fill in msg lists */
char ** msgPtrList; /* PTR: array of msg ptrs queued to msg q */
int * msgLenList; /* PTR: array of lengths of msgs */
} MSG_Q_INFO;
extern STATUS msgQLibInit (void);
extern MSG_Q_ID msgQCreate (int maxMsgs, int maxMsgLength, int options);
extern STATUS msgQDelete (MSG_Q_ID msgQId);
extern STATUS msgQSend (MSG_Q_ID msgQId, char *buffer, UINT nBytes,
int timeout, int priority);
extern int msgQReceive (MSG_Q_ID msgQId, char *buffer, UINT maxNBytes,
int timeout);
extern STATUS msgQInfoGet (MSG_Q_ID msgQId, MSG_Q_INFO *pInfo);
extern int msgQNumMsgs (MSG_Q_ID msgQId);
extern void msgQShowInit (void);
extern STATUS msgQShow (MSG_Q_ID msgQId, int level);
要使用VxWorks的消息队列,需要包含头文件
#include
下面对主要函数API的使用方法进行一下讲解。
msgQCreate 创建一个消息队列
MSG_Q_ID msgQCreate
(
int maxMsgs, /*队列中存储的最大消息数目*/
int maxMsgLength, /*每个消息的最大字节数*/
int options /*消息在消息队列中的排列方式*/
)
options一般有两个选项:
- MSG_Q_FIFO 表示消息以先进先出的方式在队列中
- MSG_Q_PRIORITY 表示消息以优先级的方式在队列中,高优先级的消息会直接送到队列顶端
- 返回一个MSG_Q_ID类型的队列ID。
msgQSend 向一消息队列发送消息包
STATUS msgQSend
(
MSG_Q_ID msgQId, /* 要发送信息的队列id*/
char * buffer, /* 要发送的信息 */
UINT nBytes, /* 要发送信息的长度(字节),即sizeof(buffer) */
int timeout, /* 消息进入队列的等待时间 */
int priority /* 该消息的优先级 */
)
timeout意思是:当消息队列已满时,等待消息队列有空间时所等待的时间。超过该时间还没空间可用的话,消息包被舍弃。它有两个特殊值:NO_WAIT(0)立即返回,不管消息包是否被发送;WAIT_FOREVER(-1)一直等待消息队列有空间可用。 priority表示:指明发送的消息的优先级,可能值有:MSG_PRI_NORMAL(0)正常优先级,将消息置于消息队列的尾部;MSG_PRI_URGENT(1)紧急消息,将消息置于消息队列的首部。 返回一个STATUS状态值
msgQReceive从队列接收消息
int msgQReceive
(
MSG_Q_ID msgQId, /* 接收消息的队列的ID */
char * buffer, /* 接收消息字节缓冲区 */
UINT maxNBytes, /* 接受字节的最大长度 */
int timeout /* 等待时间 */
)
该函数从消息队列msgQId接收消息,将其拷贝到最大长度为maxNBytes的缓冲区buffer。如果消息包长度超过maxNBytes,多余部分被舍弃。等待时间timeout有两个特殊值: NO_WAIT(0)立即返回,WAIT_FOREVER(-1)一直等待消息队列有消息可取。 返回接收到的buffer的字节大小或者ERROR
msgQDelete 删除一个消息队列
STATUS msgQDelete
(
MSG_Q_ID msgQId /*要删除的队列ID*/
)
三、代码实例
要实现跑VxWorks的代码,我们需要安装tornado集成开发环境,这个开发环境支持xp和win7 32位操作系统,考虑到我们现在的PC一般都是Windows10操作系统,因此我们可以考虑使用VMware来安装一个win7 32位。
安装教程我当时是参考的:
Tornado2.2安装教程注意代码中不要使用 // 注释,tornado2.2默认是不支持的。
#include "vxWorks.h"
#include "msgQLib.h"
#define MAX_MSGS (10)
#define MAX_MSG_LEN (100)
MSG_Q_ID myMsgQId;
task3(void)
{
if ((myMsgQId = msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY)) == NULL)
return (ERROR);
}
task2 (void)
{
char msgBuf[MAX_MSG_LEN];
if (msgQReceive(myMsgQId, msgBuf, MAX_MSG_LEN, WAIT_FOREVER) == ERROR)
return (ERROR);
logMsg ("Message from task 1:\n%s\n", msgBuf, 0,0,0,0,0);
}
#define MESSAGE "Greetings from Task 1"
task1 (void)
{
taskDelay (sysClkRateGet()*5);
if (msgQSend (myMsgQId, MESSAGE, MAX_MSG_LEN, WAIT_FOREVER,
MSG_PRI_NORMAL) == ERROR)
return (ERROR);
}
void TestMsgQ(void)
{
taskSpawn("t3",100,0,0x20000,(FUNCPTR)task3,0,0,0,0,0,0,0,0,0,0);
taskSpawn("t2",100,0,0x20000,(FUNCPTR)task2,0,0,0,0,0,0,0,0,0,0);
taskSpawn("t1",100,0,0x20000,(FUNCPTR)task1,0,0,0,0,0,0,0,0,0,0);
}
启动shell,输入
sp TestMsgQ
1
-> sp TestMsgQ
task spawned: id = 38092b0, name = s2u0
value = 58757808 = 0x38092b0
然后输入 i,查看此时操作系统有几个任务在运行。
-> i
NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY
tExcTask _excTask 3818dd8 0 PEND 408358 3818cd8 0 0
tLogTask _logTask 38132a8 0 PEND 408358 38131a8 0 0
tWdbTask _wdbTask 380e660 3 READY 408358 380e510 0 0
t2 _task2 37ddde0 100 PEND 408358 37ddc94 0 0
t1 _task1 37baa88 100 DELAY 408358 37ba9dc 0 195
value = 0 = 0x0
后面两个任务 t2,t1就是我们创建的任务。