{{ v.name }}
{{ v.cls }}类
{{ v.price }} ¥{{ v.price }}
邮箱相对信号量而言(邮箱可当信号量来用),只是多传递了一个指针变量。其和信号量很相似,ucosii提供了5个对邮箱进行操作的函数。它们是:
1.建立一个邮箱,osmboxcreate();2.等待一个邮箱中的消息,osmboxpend();3.发送一个消息到邮箱中,osmboxpost();4.无等待地从邮箱中得到一个消息,osmboxaccept();5.查询一个邮箱的状态,osmboxquery();使用邮箱之前,必须先建立该邮箱。该操作可以通过调用osmboxcreate()函数来完成,并且要指定指针的初始值。一般情况下,这个初始值是null,但也可以初始化一个邮箱,使其在最开始就包含一条消息。如果使用邮箱的目的是用来通知任务某一个事件已经发生(发送一条消息),那么就要初始化该邮箱为null。如果用户用邮箱来共享某些资源,那么就要初始化该邮箱为一个非null的指针。在这种情况下,邮箱被当成一个二值信号量使用。下面来看看创建一个邮箱函数的实现代码:
os_event*osmboxcreate(void*msg){os_event*pevent;os_enter_critical();pevent=oseventfreelist;if(oseventfreelist!=(os_event*)0){oseventfreelist=(os_event*)oseventfreelist->oseventptr;}os_exit_critical();if(pevent!=(os_event*)0){pevent->oseventtype=os_event_type_mbox;(1)pevent->oseventptr=msg;(2)oseventwaitlistinit(pevent);}return(pevent);(3)}
仔细看看,其实和创建一个信号量的过程几乎是一样的,先申请一个空事件控制块,接着初始化这个事件控制块。最后返回一个指向这个事件控制块的指针。不同之处在于事件控制块的类型被设置成os_event_type_mbox[(1)],以及使用.oseventptr域来容纳消息指针。接着来看看等待邮箱函数实现代码:
void*osmboxpend(os_event*pevent,int16utimeout,int8u*err){void*msg;os_enter_critical();if(pevent->oseventtype!=os_event_type_mbox){(1)os_exit_critical();*err=os_err_event_type;return((void*)0);}msg=pevent->oseventptr;if(msg!=(void*)0){(2)pevent->oseventptr=(void*)0;(3)os_exit_critical();*err=os_no_err;}elseif(osintnesting>0){(4)os_exit_critical();*err=os_err_pend_isr;}else{ostcbcur->ostcbstat|=os_stat_mbox;(5)ostcbcur->ostcbdly=timeout;oseventtaskwait(pevent);os_exit_critical();ossched();os_enter_critical();if((msg=ostcbcur->ostcbmsg)!=(void*)0){(6)ostcbcur->ostcbmsg=(void*)0;ostcbcur->ostcbstat=os_stat_rdy;ostcbcur->ostcbeventptr=(os_event*)0;os_exit_critical();*err=os_no_err;}elseif(ostcbcur->ostcbstat&os_stat_mbox){(7)oseventto(pevent);(8)os_exit_critical();msg=(void*)0;(9)*err=os_timeout;}else{msg=pevent->oseventptr;(10)pevent->oseventptr=(void*)0;(11)ostcbcur->ostcbeventptr=(os_event*)0;(12)os_exit_critical();*err=os_no_err;}}return(msg);}
同样,它和ossempend()也很相似,说白了就是先看有没有有用的消息,要是没有,就把该任务挂起来。osmboxpend()首先检查该事件控制块是由osmboxcreate()函数建立的[(1)]。当.oseventptr域是一个非null的指针时,说明该邮箱中有可用的消息[(2)]。这种情况下,osmboxpend()函数将该域的值复制到局部变量msg中,然后将.oseventptr置为null[(3)]。这正是我们所期望的,也是执行osmboxpend()函数最快的路径。如果此时邮箱中没有消息是可用的(oseventptr域是null指针),osmboxpend()函数检查它的调用者是否是中断服务子程序[(4)]。象ossempend()函数一样,不能在中断服务子程序中调用osmboxpend(),因为中断服务子程序是不能等待的。这里的代码同样是为了以防万一。但是,如果邮箱中有可用的消息,即使从中断服务子程序中调用osmboxpend()函数,也一样是成功的。如果邮箱中没有可用的消息,osmboxpend()的调用任务就被挂起,直到邮箱中有了消息或者等待超时[(5)]。当有其它的任务向该邮箱发送了消息后(或者等待时间超时),这时,该任务再一次成为最高优先级任务,ossched()返回。这时,osmboxpend()函数要检查是否有消息被放到该任务的任务控制块中[(6)]。如果有,那么该次函数调用成功,对应的消息被返回到调用函数。发送一个消息到邮箱中osmboxpost()的代码如下:
int8uosmboxpost(os_event*pevent,void*msg){os_enter_critical();if(pevent->oseventtype!=os_event_type_mbox){(1)os_exit_critical();return(os_err_event_type);}if(pevent->oseventgrp){(2)oseventtaskrdy(pevent,msg,os_stat_mbox);(3)os_exit_critical();ossched();(4)return(os_no_err);}else{if(pevent->oseventptr!=(void*)0){(5)os_exit_critical();return(os_mbox_full);}else{pevent->oseventptr=msg;(6)os_exit_critical();return(os_no_err);}}}