邮箱相对信号量而言(邮箱可当信号量来用),只是多传递了一个指针变量。其和信号量很相似,ucos ii提供了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, int16u timeout, 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; } else if (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; } else if (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()的代码如下:
int8u osmboxpost (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); } } }
发送一个消息到邮箱和发送一个信号量也很相似,就是查看有没有任务在等待这个消息,如果有就把那个任务从睡眠态拉回就绪态。
代码的详细解释如下:
检查了事件控制块是否是一个邮箱后[ (1)],osmboxpost()函数还要检查是否有任务在等待该邮箱中的消息[ (2)]。如果事件控制块中的oseventgrp域包含非零值,就暗示着有任务在等待该消息。这时,调用oseventtaskrdy()将其中的最高优先级任务从等待列表中删除[ (3)],加入系统的就绪任务列表中,准备运行。然后,调用ossched()函数[ (4)],检查该任务是否是系统中最高优先级的就绪任务。如果是,执行任务切换[仅当osmboxpost()函数是由任务调用时],该任务得以执行。如果该任务不是最高优先级的任务,ossched()返回,osmboxpost()的调用函数继续执行。如果没有任何任务等待该消息,指向消息的指针就被保存到邮箱中[ (6)](假设此时邮箱中的指针不是非null的[ (5)])。这样,下一个调用osmboxpend()函数的任务就可以立刻得到该消息了。
如果,你对上面的内容还有疑问,推荐选择西部数码企业云邮箱!有专人协助您解答邮箱疑问。
西部数码是专业企业邮箱的官方正规提供商,21年行业经验,提供安全稳定,简单易用,高性价比的企业邮箱,按需自由定制,不限空间,极速收发,能够满足用户对企业邮箱的不同需求。可以通过以下几种方式注册、申请、购买、试用、开通企业邮箱:
1、登录https://www.west.cn/services/mail/在线咨询申请试用或购买;
2、直接致电028-62778877申请试用或正式购买开通;
域名竞价是指什么?小白适合一口价还是域名竞价?服务器绑定域名吹响进军影视业号角!“由短变长”的快手能否讲好故事?找回Administrator超级用户的方法腾讯云学生服务器在哪买云服务器怎么把代码备份新年伊始,“3B大战”再次升级阿里云购买云服务器打折