|
前不久有同事将μTenux的消息邮箱实验例程写完并且在博客中简要说明了μTenux邮箱的机制及涉及到的数据结构。我想对这部分有必要重点分析一下,因为大家用习惯了μC/OS-II,使用起来μTenux难免会产生些问题。
在新版的μC/OS-III已经删掉了邮箱机制,因为μC/OS的实现机制上看,它的邮箱和队列实际上是一样的,消息队列只是一个邮箱的链表罢了。所以μC/OS-III就将消息邮箱删除了。
首先,明确一下邮箱的定义。操作系统中的邮箱就是任务或者线程间通信的一种方式(因为邮箱用到的是地址指针,进程的地址是孤立的,所以进程间用邮箱肯定不行,庆幸的是RTOS一般不会涉及到进程,只会和任务或者线程打交道)。现实生活中,我们在自己家的墙上钉一个箱子,写上邮箱编号,这就是邮箱的创建。早上醒来看看邮箱有没有信件或者报纸,这就是收取邮箱消息(如果没有一直等,或者等一段时间就不等了,或者干脆不等了,这些都是你来决定的)。有信件要邮递,就将信件放到邮箱里,这就是发送邮箱消息(有没有人取走它,什么时候取走,这些都不是你关心的问题,这就是所谓的“异步”)。把邮箱拆了就叫删除邮箱。看看邮箱的编号,这叫做查询邮箱。
不同的操作系统会有不同的固定结构来存储数据,就比如说一个固定的盒子,μTenux的邮箱结构是一个铁盒子,而μC/OS-II是一个木头盒子,钉在墙上都可以放上标号,当做邮箱,这是区别一。
不同的操作系统中对邮箱做了不一样的解释,μC/OS-II认为邮箱只能容纳一则消息,消息没有取走,但是又有一条消息来,那原来的消息链就丢失了,想要存取多条消息?可以啊,你用消息队列呗!但是,μTenux不一样,它允许你存取多条消息,消息的长度是不受限制的。问题来了!用户说,你怎么知道我的消息有多大,你说内存允许就可以存取多条,我才不信呢!明明木头盒子和铁盒子一样嘛!大小没区别,凭啥你就实现了多条消息存取?莫非你的邮箱和μC/OS-II的队列一样?
NO!我可以明确的回答你。这是他们的区别二。我要重点分析一下μTenux的邮箱实现机制。
μTenux的队列和μC/OS-II的队列还是有区别的,这个是以后要论述的内容。μTenux的邮箱到底是怎样的呢?
首先,创建邮箱,这点基本上没啥区别。
1.μTenux的建立邮箱函数API:
ID mbxid = tk_cre_mbx (T_CMBX * pk_cmbx);
这个函数中ID是INT类型,新建的邮箱ID为1,依次累加,最大不会超过配置文件里的CFN_MAX_MBXID数量。pk_cmbx参数是用户要建立的邮箱需要的相关信息。T_CMBX的数据结构如下:
typedef struct t_cmbx {
VP exinf; /* Extended information */
ATR mbxatr; /* Mail box attribute */
UB dsname[8]; /* Object name */
} T_CMBX;
exinf是一个void*类型的参数,可以存储扩展信息,这个扩展信息用邮箱查询函数式可以查到的。应用exinf这个参数可以实现更加灵活的功能,比如需要一个更大的空间来指示用户信息,或在邮箱建立后某些信息可能需要更改,则可以为其分配一片独立的空间,将内存的数据包的地址放置到exinf中。用户尽可以展开自己的想象力和创造力!
mbxatr是邮箱的属性,这个参考用户内核手册吧,还有dsname,我比较懒,大家别怪偶~~~~~除非你比我更懒~~~~~~O(∩_∩)O哈哈~
2.μTenux的删除邮箱函数API:
ER 而成的= tk_del_mbx (ID mbxid);
这个真没什么可讲的。
3.μTenux的发送消息到邮箱的函数API:
ER ercd = tk_snd_mbx (ID mbxid, T_MSG *pk_msg);
!!!~~~~!!!!****** 重点在这了!!赶紧看过来!!!!!
μC/OS-II发送消息的时候直接给消息指针就OK了,但是μTenux不是。μTenux是带有消息头的。消息头可以是T_MSG类型,也可以是T_MSG_PRI类型,然后才是你传入的消息指针。T_MSG和T_MSG_PRI的定义如下:
typedef struct t_msg {
VP msgque[1]; /* Area for message queue */
} T_MSG;
typedef struct t_msg_pri {
T_MSG msgque; /* Area for message queue */
PRI msgpri; /* Message priority */
} T_MSG_PRI;
你可以用偷梁换柱的方法将pk_msg定义为:
typedef struct u_msg {
VP msgque[1]; /* Area for message queue,as same as T_MSG */
UB *usrmsg; /* Area for message pointer */
} U_MSG;
然后这样用:
U_MSG sndmsg;
……………………
sndmsg.usrmsg = "test*test*test*test*test....\n";
………………………………
ercd = tk_snd_mbx(MbxID_S,(T_MSG*)&sndmsg);
详细例子大家可以参考官方的release版本软件包。但是,这种使用方式大家必须知道,原因大家可以参考核心代码,我尽量简单扼要地、提纲挈领地、不遗余力地、干干脆脆地(O(∩_∩)O哈哈~,又犯病了~~~)给大家介绍其中的奥秘。邮箱结构里记录的永远是消息的地址,μTenux在记录的地址的同时在新进来的消息头上链入的下一个消息的地址,当然,如果这条消息没有优先级,它是排在队尾的,这个时候指针指向的就是它自己。所以,消息头是操作系统维护的,虽然消息头是用户给的空间,但是请不要更改,会爆炸的!!!!bomp!!!!
哦~~~~~~~~大家恍然大悟,原来如此是吧!!!!!!既不会让操作系统增加负担,又实现了邮箱的多存多取,只不过链表要用户来维护。这点在用户手册里写得不甚明了,害得我看源代码看了三天,惯性思维害死人啊!!!!!μTenux这点强于μC/OS,但是又让人感觉μTenux有点儿霸道。知道了μTenux的小秘密是不是觉得很爽(源代码开源的,我这可不算泄密啊O(∩_∩)O~),别人不会用,现在你会用了是不是觉得很cool?我就是喜欢这种cool的感觉,同时也喜欢μTenux的霸道!!就像昨天李娜赢了莎拉波娃那场球,活就要活出自己的样子,有时候就是要霸道一些才能堵住无聊人的嘴!!!!(才思泉涌啊~~~~~受不了了~~~~~~o(╯□╰)o)
源代码中会有些地方用了强制类型转换,反正消息头部一定是链表指针就对了,我不在这里分析了,毕竟大家会用就行了,感兴趣自己研究源代码去,T/Kernel的代码经过了30年,实现的部分很多灵巧的地方值得称赞。
4.μTenux的接收邮箱的消息函数API:
ER ercd = tk_rcv_mbx ( ID mbxid, T_MSG ** ppk_msg, TMO tmout );
这个函数大家看手册吧,(都下班了,我还在加班,原谅我的懒惰吧,我饿了~~~~),消息一出来,头部的链表为NULL,就是断链了,所以之前你如果发送消息的时候没有空出消息头,那么这次取出消息你就惨了,是个NULL!!O(∩_∩)O~
5.μTenux的查询邮箱状态函数API:
ER ercd = tk_ref_mbx ( ID mbxid, T_RMBX *pk_rmbx);
这个也看手册吧~~~~~~~
有很多人问,操作系统是啥?嵌入式操作系统那么多?你们做的这个有啥意义?……………………
我就不一一回答了,人都是被逼出来的。你去问问JJ.L,他为啥写μC/OS,就是因为当时他所用的操作系统不稳定,开发人员水平还有限,他干脆自己写一个算了,发展到现在20多年,结果现在美国航空航天、生命攸关的系统都用了μC/OS。我们的μTenux性能和μC/OS-II相当甚至优于μC/OS-II,而且最重要的是开源免费,国人不是不喜欢交钱的东西又想让自己拥有的东西很有价值嘛!所以,μTenux出现了。我们用的是经历了30年考验的T-Kernel内核,前身叫做ITRON,如果说μC/OS现在是v3.0,那么μTenux就是v6.0了,这么比较可能有些片面,但是,性能好坏只有用过的人才有发言权,不是吗?
希望自己的努力能够换来回报,我们的团队啥都好,就是给的实习工资太低了,抱怨一下,希望老板别看见,看见了也不说是小阿奔说的~~~~( ⊙ o ⊙ )啊!肚子好饿~~~~~好像说是要和μC/OS-II对比,没写多少μC/OS-II邮箱的实现机制,感觉应该不难理解μC/OS-II的源码吧,大家自己分析吧,我的眼睛真得开始出现圈圈了~~~~~~~
如果有误请及时告知偶~~~~~ |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|