设为首页 加入收藏

TOP

uC/OSIII的消息队列处理机制(二)
2015-11-21 02:13:24 来源: 作者: 【 】 浏览:56
Tags:uC/OSIII 消息 队列 处理 机制
S_MSG_SIZE MsgSize; /* 消息真身的长度 */
CPU_TS MsgTS; /* 时间截 */
};
确切地说,OS_MSG真的只是消息的结构,它是消息的载体,不是真身。仔细观察OS_MSG成员,就能发现它里面这个“void *MsgPtr和MsgSize” 这两个才是消息真身,它通常是指向一个全局变量的数组或者其他什么变量,消息正是通过这个指针来进行传递的。如果说OS_MSG是一封书信,那void *MsgPtr和MsgSize才是信的内容,这个内容只是“说”了一些坐标点,而坐标所指向的变量本身才是真正要传递的“小秘密”,可能是某处宝藏吧,也说不定。
至此消息存储的数据结构也看完了,大概流程如下:
OS_Q->OS_MSG_Q ->OS_MSG -> void *MsgPtr和MsgSize->宝藏
结合之前那条任务挂起表的主线,就形成了以下这条主线:
宝藏<-OS_Q<->任务TCB (注意TCB也反向指着OS_Q)

以上数据结构要牢记。接下来,才可以打开消息队列传递的大门。
对消息队列的基本操作是void OSQPost(OS_Q *p_q...)和void *OSQPend (OS_Q *p_q...)
注意OSQPend 函数为了节省一个传入参数,使用函数返回值作为获得的消息指针。
先看一下OSQPost函数,它的作用是完成“宝藏<-OS_Q”的环节,把消息挂接到对应的消息队列OS_Q上,函数的基本内容如下:
void OSQPost (OS_Q *p_q, /*要post到的消息队列*/
void *p_void, /*指向要传递的消息数据的指针*/
OS_MSG_SIZE msg_size, /*消息数据的长度,与指针配合使用*/
OS_OPT opt, /*选项:用于控制传递到队列头或尾;
是否推送给全部等待的TCB;
是否进行调度*/
OS_ERR *p_err) /*错误指针*/
{
CPU_TS ts;
...(大段的参数检查代码,此处略。)
ts = OS_TS_GET(); /* Get timestamp */
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u /*如果使用中断中延迟推送方案,调用 OS_IntQPost函数进行post*/
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /*这里判断是否在中断中,延迟推送方案是为中断量身定制的,用于防止关中断时间太长,在其他地方不需要使用*/
OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_Q, /* Post to ISR queue */
(void *)p_q,
(void *)p_void,
(OS_MSG_SIZE)msg_size,
(OS_FLAGS )0,
(OS_OPT )opt,
(CPU_TS )ts,
(OS_ERR *)p_err);
return;
}
#endif
/*如果没在中断中,或者没有定义延迟中断推送,就直接调用OS_QPost函数进行推送*/
OS_QPost(p_q,
p_void,
msg_size,
opt,
ts,
p_err);
}
延迟推送中,OS_IntQPost()函数的接收者是中断延迟处理任务OS_IntQTask(),(这两个函数都定义在ucosiii\source的os_int.c文件中)该任务处理中再调用OS_QPost()函数,结果就是OS_QPost()调用点由中断中转移到中断处理任务中,节省了关中断时间。延迟推送和中断机制不是这里讨论的重点,所以直接进入OS_QPost()函数:
void OS_QPost (OS_Q *p_q,
void *p_void,
OS_MSG_SIZE msg_size,
OS_OPT opt,
CPU_TS ts,
OS_ERR *p_err) /*入口参数与OS_QPost一样*/
{
OS_OBJ_QTY cnt;
OS_OPT post_type;
OS_PEND_LIST *p_pend_list;
OS_PEND_DATA *p_pend_data;
OS_PEND_DATA *p_pend_data_next;
OS_TCB *p_tcb;
CPU_SR_ALLOC();
OS_CRITICAL_ENTER();
p_pend_list = &p_q->PendList; /*这里是找出该队列下的OS_PEND_LIST列表*/
if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) {
/* 如果列表里显示等待的任务TCB数目为0,也就是没有任务pend该队列,就没必要查
找相关的任务进行推送,直接把消息保存下来就好了*/
部分代码略。
/*那么就调用OS_MsgQPut,将消息存储到队列中的消息链表中*/
OS_MsgQPut(&p_q->MsgQ,
p_void,
msg_size,
post_type,
ts,
p_err);
OS_CRITICAL_EXIT();
return;
}
/* 如果列表里显示等待的任务TCB数目不为0,也就是有任务正在pend该队列,就必须把消息推送给它,就会执行以下代码*/
cnt = 要推送的数量;代码略;
p_pend_data = p_pend_list->HeadPtr; /*从p_pend_list里找出p_pend_data链表*/
while (cnt > 0u) {
p_tcb = p_pend_data->TCBPtr; /*从p_pend_data里找出等待的任务TCB*/
p_pend_data_next = p_pend_data->NextPtr;
OS_Post((OS_PEND_OBJ *)((void *)p_q), /*推送到等待的任务TCB*/
p_tcb,
p_void,
msg_size,
ts);
p_pend_data = p_pend_data_next;
cnt--; /*按要推送的数量cnt循环,直到退出*/
}
OS_CRITICAL_EXIT_NO_SCHED();
if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
OSSched(); /* 进行任务调度 */
}
*p_err = OS_ERR_NONE;
}
可见,OS_QPost 函数中又包含了两层调用:如果没有任务等待该消息队列,就调用OS_MsgQPut函数;如果有任务在等待,就调用OS_Post把消息推送给正在等待的任务。
简单介绍下这两个函数,它们是最后一级了,内容基本都是查找排序算法,没有太多的架构知识可讲了:
OS_MsgQPut函数(定义在ucosiii\source的OS_msg.c中)负责从OS_MSG_POOL中取出一个空闲的OS_MSG,将消息写入到它内部,然后将该OS_MSG挂到对应的消息队列下面。
OS_Post函数(定义在ucosiii\source的OS_core.c中)是直接向任务推送消息的函数,它先判断任务是单队列QPend还是MultiPend:
如果是单队列QPend,就把消息内容指针直接写到TCB里面MsgPtr和MsgSize中:
p_tcb->MsgPtr = p_void; /* Deposit message in OS_TCB of task waiting */
p_tcb->MsgSize = msg_size;
注意这两个成员变量,是定义在任务TCB结构体中的两个成员,是伴随TCB一生的,可以随时取用。
如果是MultiPend,则调用OS_Post1函数,把消息内容指针写到OS_PEND_DATA中专供MultiPend使用的几个字段中,这个在前面介绍OS

首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇POJ 1265 多边形格点数Pick公式 下一篇2013级C++第4周(春)项目――再和..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: