全部博文(83)
分类:
2009-11-01 22:00:28
为什么要用:
任务间的通信可以通过全局变量或者信号量来完成。全局变量虽然可以承载通信的内容,但是接收方无法意识到信息的到达,除非发送方向接收方发送一个信号量,或者接收方不断该全局变量;信号量可以立即使接收方知道某个事件的发生,但无法传递具体内容。用信号量进行通信就像我们只拨通别人的手机而不与之通话;用消息队列或者邮箱进行通信则可达到既 拨通别人的手机又与之通话的效果。换句话说,消息队列和邮箱可以及时传送事件的内容。
邮箱通信的机理:
发送方通过内核服务把一封邮件投递到邮箱,内核完成投递任务后通知等待列表中的接收方收取邮件。在整个投递过程中,内核充当了邮递员的角色。这里的“邮件”通常是一个指针,接收方可以通过该指针获取邮件内容。
邮箱的基本操作:
内核通常提供如下的邮箱服务:初始化邮箱的内容。邮箱最初可以包含或者不包含邮件。把邮件发送到邮箱(post)。如果邮箱已满,则返回错误信息(OS_MBOX_FULL)。以“挂起”方式接收邮件(pend)。如果邮箱为空,则把取信者挂起;若超过一定时间邮箱仍为空,则返回超时信息。
以“非挂起”方式接收邮件(accept)。如果邮箱为空,则返回一个空指针。
当希望一次性向某个任务发送多则消息时,邮箱就有点见肘了。因为一个邮箱只能装一封信。把多上邮箱集中到一起管理和使用就变成了消息队列,所以消息队列的操作和邮箱很相似。可以简单地认为,消息队列是邮箱数组。
如果发送者是一对一的方式发送邮件,则等待列表中的优先级最高的任务将获取邮件;如果是以广播的方式发送邮件,则等待该邮件的所有任务将获得此邮件。
/********************************************************************
* 文 件 名:main.c
* 功 能:利用消息队列和邮箱,实现任务间的通讯。
* 说 明:观察信息窗口中由jtag_uart输出的信息。
********************************************************************/
#include
#include
#include "includes.h" /* MicroC/OS-II总头文件 */
#include "alt_ucosii_simple_error_check.h" /* 错误处理软件模块 */
#define WAIT_FOREVER 0 /* 超时常数,0表示永远等待 */
#define TASK_STACKSIZE 2048 /* 定义任务栈大小 */
/* 定义各任务任务栈 */
OS_STK initialize_task_stk[TASK_STACKSIZE];
OS_STK msg_sender_stk[TASK_STACKSIZE];
OS_STK msg_receiver1_stk[TASK_STACKSIZE];
OS_STK msg_receiver2_stk[TASK_STACKSIZE];
OS_STK mail_send1_stk[TASK_STACKSIZE];
OS_STK mail_send2_stk[TASK_STACKSIZE];
OS_STK mail_send3_stk[TASK_STACKSIZE];
OS_STK print_task_stk[TASK_STACKSIZE];
/* 分配各任务优先级 */
#define INITIALIZE_TASK_PRIORITY 6
#define PRINT_TASK_PRIORITY 7
#define MSG_SENDER_PRIORITY 8
#define MSG_RECEIVER1_PRIORITY 9
#define MSG_RECEIVER2_PRIORITY 10
#define MAIL_SEND1_PRIORITY 11
#define MAIL_SEND2_PRIORITY 12
#define MAIL_SEND3_PRIORITY 13
/* 定义消息队列 */
#define MSG_QUEUE_SIZE 30 /* 消息队列大小 */
OS_EVENT *msgqueue; /* 消息队列事件指针 */
void *msgqueueTbl[MSG_QUEUE_SIZE]; /* 队列缓冲区 */
/* 定义三个邮箱 */
OS_EVENT *mailbox1;
OS_EVENT *mailbox2;
OS_EVENT *mailbox3;
/* 定义任务状态记录 */
INT32U number_of_messages_sent = 0; /* 发出消息的数量 */
INT32U number_of_messages_received_task1 = 0; /* 接收任务1收到消息的数量 */
INT32U number_of_messages_received_task2 = 0; /* 接收任务2收到消息的数量 */
/* 局部函数声明 */
int initOSDataStructs(void); /* 初始化消息队列和邮箱的数据结构 */
int initCreateTasks(void); /* 初始化任务 */
/* 每5秒打印一次使用消息队列的进行通讯的任务状态信息. */
void PrintTask(void* pdata)
{
while (1)
{
OSTimeDlyHMSM(0, 0, 5, 0);
printf("************************************************************\n");
printf("The number of messages sent by the MsgSender: %lu\n",
number_of_messages_sent);
printf("\n");
printf("The number of messages received by the MsgReceiver1: %lu\n",
number_of_messages_received_task1);
printf("\n");
printf("The number of messages received by the MsgReceiver2: %lu\n",
number_of_messages_received_task2);
printf("************************************************************\n");
printf("\n");
}
}
/* 消息发送任务: 将消息通过消息队列广播给所有等待消息的任务,当队列满时,延时1s */
void MsgSender(void* pdata)
{
INT8U return_code = OS_NO_ERR; /* 系统调用的返回状态 */
INT32U msg = 0; /* 欲发出的消息 */
OS_Q_DATA queue_data; /* 用于保存从消息队列的事件控制块中获取的数据信息 */
while (1)
{
return_code = OSQQuery(msgqueue, &queue_data); /* 查询本消息队列的信息 */
alt_ucosii_check_return_code(return_code); /* 检查系统调用的返回状态 */
if(queue_data.OSNMsgs < MSG_QUEUE_SIZE) /* 查询消息队列是否已满 */
{ /* 消息队列未满,将消息(msg)通过消息队列(msgqueue)广播给所有等待消息的任务*/
return_code = OSQPostOpt(msgqueue, (void *)&msg, OS_POST_OPT_BROADCAST);
alt_ucosii_check_return_code(return_code); /* 检查系统调用的返回状态 */
msg++; /* 产生新消息 */
number_of_messages_sent++; /* 记录发出消息的条数 */
}
else
{ /* 消息队列已满,延时1s */
OSTimeDlyHMSM(0, 0, 1, 0);
}
}
}
/* 消息接收任务1: 每300ms接收一次消息队列的消息*/
void MsgReceiver1(void* pdata)
{
INT8U return_code = OS_NO_ERR; /* 系统调用的返回状态 */
INT32U *msg; /* 存储接收到的消息 */
while (1)
{ /* 到msgqueue接收消息,如果消息队列为空,则一直等待 */
msg = (INT32U *)OSQPend(msgqueue, WAIT_FOREVER, &return_code);
alt_ucosii_check_return_code(return_code);
number_of_messages_received_task1++; /* 接到消息,计数器加1 */
OSTimeDlyHMSM(0, 0, 0, 300); /* 延时300ms */
}
}
/* 消息接收任务1: 每1s接收一次消息队列的消息*/
void MsgReceiver2(void* pdata)
{
INT8U return_code = OS_NO_ERR; /* 系统调用的返回状态 */
INT32U *msg; /* 存储接收到的消息 */
while (1)
{ /* 到msgqueue接收消息,如果消息队列为空,则一直等待 */
msg = (INT32U *)OSQPend(msgqueue, WAIT_FOREVER, &return_code);
alt_ucosii_check_return_code(return_code);
number_of_messages_received_task2++; /* 接到消息,计数器加1 */
OSTimeDlyHMSM(0, 0, 1, 0); /* 延时1s */
}
}
/* 邮件发送任务1: 从mailbox1中收取信息,把信息加1后发到mailbox2*/
void MailSend1(void* pdata)
{
INT8U return_code = OS_NO_ERR; /* 系统调用的返回状态 */
INT32U *mbox1_contents; /* 指向邮件内容的指针 */
while (1)
{ /* 从mailbox1接收邮件,如果邮箱为空,则一直等待 */
mbox1_contents = (INT32U *)OSMboxPend(mailbox1, WAIT_FOREVER, &return_code);
alt_ucosii_check_return_code(return_code);
/* 输出邮件内容,并把内容加1 */
printf("Task1 received the message: %lu in mailbox 1\n",
(*mbox1_contents)++);
printf("Task1 incremented the message and placed it into mailbox 2\n");
printf("\n");
return_code = OSMboxPost(mailbox2,
(void *)mbox1_contents); /* 把邮件发送到mailbox2 */
alt_ucosii_check_return_code(return_code);
}
}
/* 邮件发送任务2: 从mailbox2中收取信息,把信息加1后发到mailbox3*/
void MailSend2(void* pdata)
{
INT8U return_code = OS_NO_ERR; /* 系统调用的返回状态 */
INT32U *mbox2_contents; /* 指向邮件内容的指针 */
while(1)
{ /* 从mailbox1接收邮件,如果邮箱为空,则一直等待 */
mbox2_contents = (INT32U *)OSMboxPend(mailbox2, WAIT_FOREVER, &return_code);
alt_ucosii_check_return_code(return_code);
/* 输出邮件内容,并把内容加1 */
printf("Task2 received the message: %lu in mailbox 2\n", (*mbox2_contents)++);
printf("Task2 incremented the message and placed it into mailbox 3\n");
printf("\n");
/* 把邮件发送到mailbox3 */
return_code = OSMboxPost(mailbox3,(void *)mbox2_contents);
alt_ucosii_check_return_code(return_code);
}
}
/* 邮件发送任务3: 从mailbox3中收取信息,把信息加1后发到mailbox1*/
void MailSend3(void* pdata)
{
INT8U return_code = OS_NO_ERR;
INT32U *mbox3_contents;
while (1)
{
mbox3_contents = (INT32U *)OSMboxPend(mailbox3, WAIT_FOREVER, &return_code);
alt_ucosii_check_return_code(return_code);
printf("Task3 received the message: %lu in mailbox 3\n", (*mbox3_contents)++);
printf("Task3 incremented the message and placed it into mailbox 1\n");
printf("\n");
usleep(3000000); /* 延时3000000us */
/* 把邮件发送到mailbox1 */
return_code = OSMboxPost(mailbox1,(void *)mbox3_contents);
alt_ucosii_check_return_code(return_code);
}
}
/* 初始化各子任务 */
void initialize_task(void* pdata)
{
INT8U return_code = OS_NO_ERR;
INT32U mbox1_contents = 0;
/* 初始化消息队列和邮箱的数据结构 */
initOSDataStructs();
/* 创建个子任务 */
initCreateTasks();
/* 向mailbox1发送一封邮件*/
return_code = OSMboxPost(mailbox1, (void *)&mbox1_contents);
alt_ucosii_check_return_code(return_code);
return_code = OSTaskDel(OS_PRIO_SELF);
alt_ucosii_check_return_code(return_code);
while (1);
}
int main (int argc, char* argv[], char* envp[])
{
INT8U return_code = OS_NO_ERR;
/* 创建父任务 */
return_code = OSTaskCreateExt(initialize_task,
NULL,
&initialize_task_stk[TASK_STACKSIZE],
INITIALIZE_TASK_PRIORITY,
INITIALIZE_TASK_PRIORITY,
initialize_task_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
OSStart(); /* 启动OS */
return 0;
}
/* This function simply creates the three Mailboxes */
int initOSDataStructs(void)
{ /* 初始化邮箱的数据结构 */
mailbox1 = OSMboxCreate((void *)NULL);
mailbox2 = OSMboxCreate((void *)NULL);
mailbox3 = OSMboxCreate((void *)NULL);
/* 初始化消息队列的数据结构 */
msgqueue = OSQCreate(&msgqueueTbl[0], MSG_QUEUE_SIZE);
return 0;
}
int initCreateTasks(void)
{
INT8U return_code = OS_NO_ERR;
/* 创建打印任务 */
return_code = OSTaskCreateExt(PrintTask,
NULL,
&print_task_stk[TASK_STACKSIZE],
PRINT_TASK_PRIORITY,
PRINT_TASK_PRIORITY,
print_task_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MsgSender任务 */
return_code = OSTaskCreateExt(MsgSender,
NULL,
&msg_sender_stk[TASK_STACKSIZE],
MSG_SENDER_PRIORITY,
MSG_SENDER_PRIORITY,
msg_sender_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MsgReceiver1任务 */
return_code = OSTaskCreateExt(MsgReceiver1,
NULL,
&msg_receiver1_stk[TASK_STACKSIZE],
MSG_RECEIVER1_PRIORITY,
MSG_RECEIVER1_PRIORITY,
msg_receiver1_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MsgReceiver2任务 */
return_code = OSTaskCreateExt(MsgReceiver2,
NULL,
&msg_receiver2_stk[TASK_STACKSIZE],
MSG_RECEIVER2_PRIORITY,
MSG_RECEIVER2_PRIORITY,
msg_receiver2_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MailSend1任务 */
return_code = OSTaskCreateExt(MailSend1,
NULL,
&mail_send1_stk[TASK_STACKSIZE],
MAIL_SEND1_PRIORITY,
MAIL_SEND1_PRIORITY,
mail_send1_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MailSend2任务 */
return_code = OSTaskCreateExt(MailSend2,
NULL,
&mail_send2_stk[TASK_STACKSIZE],
MAIL_SEND2_PRIORITY,
MAIL_SEND2_PRIORITY,
mail_send2_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
/* 创建MailSend3任务 */
return_code = OSTaskCreateExt(MailSend3,
NULL,
&mail_send3_stk[TASK_STACKSIZE],
MAIL_SEND3_PRIORITY,
MAIL_SEND3_PRIORITY,
mail_send3_stk,
TASK_STACKSIZE,
NULL,
0);
alt_ucosii_check_return_code(return_code);
return 0;
}
/* This is the end of this file */