uTenux的消息缓冲区是一个通过传递大小可变的消息来实现同步和通信的对象。

消息缓冲区由三部分组成:1、待发消息队列  2、等接收消息的任务队列  3、用来保存缓冲消息的空间。

和信号相比,消息队列能够传递更多的信息。与管道相比,消息队列提供了有格式的数据,这可以减少开发人员的工作量。但消息队列仍然有大小限制。

在uTenux中当缓冲区空时,接收消息的任务进入等待状态。当缓冲区满时,发送消息的任务进入等待状态。

每个消息只能接收一次,消息被接收接收后消息从消息缓冲区中删除。

使用tk_snd_mbf发送消息到消息缓冲区时,由于发送的消息字提供了VP型的消息头指针和消息长度。接收数据时,只有OS知道数据的长度。至于数据内部结构谁都不知道,因此必须消息的收发双方必须事先约定好消息类型,接收方根据消息数据的类型准备接收到消息的存放空间。关于VP指针(void*)前文已详诉,这里就不唠叨了。关于VP类型,只需要记住一点即可:

Void类型的指针是无类型的指针,可以指向任何结构。因为它就是一个指针!

在引用这个指针时候,需要预先知道这个指针指向地址的结构。不然编译器无法知道所指数据的类型而报错

与邮箱不同,消息缓冲传递的不是地址而是实实在在的将消息复制到缓冲区

基于这个特性,我觉得消息缓冲区更适合处理大量数据的传输。比如usart接收数据的处理。Usart每次接收到数据,直接丢到缓冲去即可。uasrt后来接收到的数据不会覆盖上次的数据,OS只管根据自己的需要处理下缓冲去消息即可。

比如对于STM32F4,USART的数据寄存器地址是(0x40001004),如果是按照邮箱的方式来处理数据。只需要将这个地址0x40001004传递给邮箱,接收消息的任务结束时候,只需要从这个地址取出来数据即可。至于中间这个数据是否发生了变化,接收端不知道。

而使用消息队列的时候却是首先将地址0x40001004中的数据,复制到消息队列中。任务从消息队列中取消息的时候,也不会关心原数据的地址。(感觉我这样分析像数据队列了)

消息缓冲区的SVC

tk_cre_mbf  (mbf = message buffer)创建消息缓冲区 。

消息队列的各种属性在设置时设置。其中mbfatr消息缓冲区的属性的设置如下;

TA_TFIFO          等待发送的任务按FIFO的数序排队

„     TA_TPRI            等待发送的任务按优先级顺序排队

„     TA_USERBUF    表示任务使用用户指定的区域作为缓冲区

„     TA_DSNAME       设定DS对象名

一个悲剧的小插曲:

按照习惯性的写法,在接收消息的时候我这样写的:

if(E_OK == tk_rcv_mbf(MbfID_1,(VP)msgrcv,-1))
{
tm_putstring((UB*)"Task A receive a message.the message is:\n");
tm_putstring((UB*)msgrcv);
}
else
{
tm_putstring((UB*)"Task A Failed receive the message\n");
PutErcd(ercd);
}

然后发现TaskA死活收不到消息,这就怪了。一直检查发送部分,没出错。最后看手册才注意到:返回值是接收的消息大小(字节数)或错误编码。这样写即使受到消息了也不会正常显示。。。

不仔细看手册函数说明害死人啊!

【实验描述】

首先创建两个任务TaskA和TaskB,优先级分别为18和20.然后创建两个消息队列。

启动任务TaskA,在TaskA中启动TaskB。

TaskA向MbfID_1发送消息,然后去等待MbfID_2中的消息。此时MbfID_1中没消息,TaskA进入休眠状态。任务TaskB开始执行。

TaskB首先接收MbfID_1中的消息,通过串口显示出来后再向MbfID_2中发送消息。发送完成后,TaskA释放等待条件满足,立即抢断TaskB。开始执行剩下的代码和循环。

如果没有上面的小插曲,这个实验是相当低简单。可惜疏忽了一下,费了一晚上时间才搞定。

【实验代码及输出】

#include "MessbufSample.h"

#define  MBF1SIZE      200
#define MBF2SIZE 200
#define MBF1MAXMSIZE 80
#define MBF2MAXMSIZE 80 void MbfSampleTaskA(W stacd,VP exinf);
void MbfSampleTaskB(W stacd,VP exinf); static ID TaskID_A;
static ID TaskID_B;
static ID MbfID_1;
static ID MbfID_2; ER MbfSample( void)
{
T_CTSK ctsk;
T_CMBF cmbf; //创建任务TaskA
ctsk.bufptr = NULL;
ctsk.exinf = (VP)NULL;
ctsk.itskpri = 18;
ctsk.stksz = 512;
ctsk.task = MbfSampleTaskA;
ctsk.tskatr = TA_HLNG | TA_RNG0;
TaskID_A = tk_cre_tsk(&ctsk); //创建任务TaskB
ctsk.itskpri = 20;
ctsk.task = MbfSampleTaskB;
TaskID_B = tk_cre_tsk(&ctsk); //创建消息缓冲区MbfID_1
cmbf.bufptr = (VP)NULL; //不使用用户缓冲区
cmbf.bufsz = MBF1SIZE; //消息缓冲区200字节
cmbf.exinf = (VP)NULL;
cmbf.maxmsz = MBF1MAXMSIZE; //最大消息大小
cmbf.mbfatr = TA_TFIFO;
MbfID_1 = tk_cre_mbf(&cmbf); //创建消息缓冲区MbfID_2
cmbf.bufsz = MBF2SIZE;
cmbf.maxmsz = MBF2MAXMSIZE;
MbfID_2 = tk_cre_mbf(&cmbf); tk_sta_tsk(TaskID_A,5);
return TRUE;
} void MbfSampleTaskA(W stacd,VP exinf)
{
UW len;
B c;
T_RMBF rmbf;
W msgsz; B msgsend1[] = "Do you think hanshuyujifen is very good?\n";
B msgsend2[] = "Do you think hanshuyujifen work hard?\n";
B msgrcv[100] = "\0"; tk_sta_tsk(TaskID_B,0);
while(1)
{
tm_putstring((UB*)"I am in task a\n");
tm_putstring((UB*)"Task A send a message:\n");
tm_putstring((UB*)msgsend1);
if(E_OK == tk_snd_mbf(MbfID_1,(VP)msgsend1,strlen(msgsend1),-1))
{
tm_putstring((UB*)"Task A send message sucessfully\n");
}
else
{
tm_putstring((UB*)"Task A Failed send a message:\n");
return;
}
if(E_OK == tk_snd_mbf(MbfID_1,(VP)msgsend2,strlen(msgsend2),-1))
{
tm_putstring((UB*)"Task A send message sucessfully\n");
}
else
{
tm_putstring((UB*)"Task A Failed send a message:\n");
return;
} if(E_OK < tk_rcv_mbf(MbfID_2,(VP)msgrcv,-1))
{
tm_putstring((UB*)"Task A receive a message.the message is:\n");
tm_putstring((UB*)msgrcv);
}
else
{
tm_putstring((UB*)"Task A Failed receive the message\n");
}
}
} void MbfSampleTaskB(W stacd,VP exinf)
{
UW len;
B msgsend[] = "Yes,i think so.\n";
B msgrcv[100] = "\0";
B msgrcv2[100] = "\0";
while(1)
{
tk_rcv_mbf(MbfID_1,(VP)msgrcv,-1);
tm_putstring((UB*)"Task B receive a message.\nThe Message is:\n");
tm_putstring((UB*)msgrcv);
if(E_OK == tk_rcv_mbf(MbfID_1,(VP)msgrcv,-1));
tm_putstring((UB*)"Task B receive a message.\nThe Message is:\n");
tm_putstring((UB*)msgrcv2);
Delay(0x1000000);
tm_putstring((UB*)"Task B will send a message,the message is:\n");
tm_putstring((UB*)msgsend);
if(E_OK == tk_snd_mbf(MbfID_2,(VP)msgsend,strlen(msgsend),-1))
{
tm_putstring((UB*)"TaskB send a message sucessfully\n");
}
else
{
tm_putstring((UB*)"Task B Failed receive the message\n");
}
}
}

输出如下:

----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

I am in task a
Task A send a message:
Do you think hanshuyujifen is very good?
Task A send message sucessfully
Task B receive a message.
The Message is:
Do you think hanshuyujifen is very good?
Task B will send a message,the message is:
Yes,i think so.
Task A receive a message.the message is:
Yes,i think so.
。。。。。。

【附加实验】

在上述消息队列中,一次放置多个消息。

如果消息缓冲空间足够,发送多个消息跟发送一个消息,对发送发来说没什么区别。当消息缓冲快满的时候,容纳不下新消息,发送任务就会进入等待状态。直到缓冲区有足够空间。

但是接收第二条消息时候一定要记得把用于存放消息的内存块先清空了。否则的话,会将上一条信息没有被覆盖掉的东西输出来。

【uTenux实验】消息缓冲区的更多相关文章

  1. 【uTenux实验】邮箱

    邮箱是一个通过在系统(共享)内存空间传递消息来实现同步和通信的对象.uTenux中每个邮箱都包含一个用来发送消息的消息队列和一个用于等待接收消息的任务队列,其使用邮箱功能的消息内容放置在发送方和接收方 ...

  2. 【uTenux实验】集合点端口

    这个是头一次接触的概念.比较不好理解.内核规范中的说明就要20页! 看了王总写的uTenux内核规范之后,有那么一点明白了但理解不深. 集合点端口就像每次工作前的收集情况会.首长下达收集情况指令,各个 ...

  3. 【uTenux实验】中断处理

    中断处理是一个比较有意思的东西.uTenux的中断处理包括了处理外部中断.CPU异常等.他是OS中任务无关部分.因此,当中断到来的时候OS会停止任务调度,不会发生任务切换.直到程序从中断中返回. uT ...

  4. 【uTenux实验】写在开始实验之前

    1.使用的uTenux内核代码:http://www.uloong.cc/cn/download/uTenux_V1.6.00r180.zip 2.uTenux的特性: 1.微内核  2.开放源码.完 ...

  5. 【uTenux实验】任务管理

    任务就是一个无限循环.uTenux提供的任务管理功能是很强大的,包括建立和删除一个任务,启动或退出任务,取消一个任务的启动请求,改变任务的优先级和査询任务状态,使任务进人睡眠状态和唤醒状态,取消唤醒请 ...

  6. 【uTenux实验】信号量

    信号量(semaphore)是一个用来指示可用的资源并将可用资源的数量以数值的形式表示出来的对象.当使用一组资源时,信号量用来实现互斥控制和同步.uTenux提供了信号量出来的API,可以很方便地使用 ...

  7. 【uTenux实验】事件标志

    事件标志是一个用来实现同步的对象,由多个位组成,用作指示对应事件存在的标志.事件标志由用来指示对应事件存在的位模式(bitpattern)和一个等待事件标志的任务队列组成. uTenux提供了一组AP ...

  8. 【uTenux实验】互斥体

    互斥体,维基百科中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...

  9. 【uTenux实验】内存池管理(固定内存池和可变内存池)

    1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...

随机推荐

  1. oracle procedure

    http://www.cnblogs.com/wuhenke/archive/2010/03/20/1690535.html

  2. Octopus系列之价格计算公式

    百分比:在原价的基础上优惠5%,相当于95%折销售实际价格:最后实际销售的价格[基准价格:如果有特价就基于特价,没有特价基于原价]优惠金额:减少的金额 批量优惠 百分比: 原价*(1-5%)的算法实际 ...

  3. JavaWeb chapter 4 Servlet处理HTTP请求

    1.  GET/POST提交方法: 用户在网页上点击一个超链接:(get) 用户提交在网页上提交表单:(post或者get) 用户在浏览器地址栏输入URL地址并回车(get) 2.  默认情况下都是使 ...

  4. debug实战:COM组件GetToSTA导致高内存+GC被阻塞

    最近花了好几周解决一个WPF高内存的问题,问题的表象是内存不断增加.未被回收,根源是GC的FinalizeThread被阻塞,导致整个GC挂掉.从以下几步来分析这个问题: 1.用ANTS Memory ...

  5. Servlet路径跳转1---使用相对路径和绝对路径,在页面上调用servlet的路径写法(超链接的方式和表单的方式)

    课程1-13   http://www.imooc.com/video/5554 Servlet路径跳转: 绝对路径:放在任何地方都对的路径 相对路径:相对于当前资源的路径 index文件 加上/,表 ...

  6. jQuery.extend源码深层分析

    在网站的开发中,经常会自己写一些jQuery插件来方便使用,其中自然少不了一个关键的方法->jQuery.extend(),使用这个方法来扩展jQuery对象. 那么今天就来讲讲这个函数的实现原 ...

  7. oracle 拼接一张表所有字段

    declare t_name varchar2(100) := upper('dba_tab_columns'); cursor c_col is select column_name from db ...

  8. hdu 2084

    ps:这道题...是DP题..所以我去看了百度一些东西,才知道了什么是状态方程,状态转移方程.. 做的第一个DP题,然后TLE一次.贴上TLE的代码: #include "stdio.h&q ...

  9. 三部曲一(数据结构)-1022-Gold Balanced Lineup

    Gold Balanced Lineup Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Othe ...

  10. HDU 4822----其实不会这个题

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4822 并不会做这个题,题解说是LCA(最近公共祖先),并不懂,说一下我自己的思路吧,虽然没能实现出来. 题 ...