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. 并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  2. C++ 中 ZeroMemory、memset 危险需慎用

    使用C/C++编程时,常使用ZeroMemory.memset或 “={0}”来对结构体对象进行初始化或清零.然而这三种方式都有各自的特点,使用时需谨慎,否则容易出现严重错误,本人今日解决一个导致宕机 ...

  3. [转]不正当使用HashMap导致cpu 100%的问题追究

    以前项目中遇到类似业务,但使用的是CurrentHashMap,看到这篇文章,转载记录,警示自己. 以下内容转自: 转载自并发编程网 – ifeve.com(http://ifeve.com/hash ...

  4. APIO2015 酱油记

    Day 0 昨天CTSC才比完,当然是要浪啦! 于是浪了一天...午饭都没吃... 晚饭...貌似也没吃... 晚上的时候觉得这样子浪不太好,还是要认真一下,打开bzoj,弃疗了...还是浪吧... ...

  5. js浏览器检测

    1.判断浏览器类型 if navigator.userAgent.indexOf(”MSIE”)>0) {} //判断是否IE浏览器 if(isFirefox=navigator.userAge ...

  6. 通过ksoap2-android来调用Web Service操作的实例

    import java.io.IOException; import org.ksoap2.SoapEnvelope;import org.ksoap2.serialization.SoapObjec ...

  7. DeepLearning之路(一)逻辑回归

    逻辑回归 1.  总述 逻辑回归来源于回归分析,用来解决分类问题,即预测值变为较少数量的离散值. 2.  基本概念 回归分析(Regression Analysis):存在一堆观测资料,希望获得数据内 ...

  8. const 放在函数后

    const 放在函数后表示这个函数是常成员函数, 常成员函数是不能改变成员变量值的函数.const 限定符,它把一个对象转换成一个常量.举例:为了使成员函数的意义更加清楚,我们可在不改变对象的成员函数 ...

  9. Ubuntu下Speedtest的安装

    要安装Speedtest,需要先安装apache,参见<Ubuntu下Apache的安装>一文:*(再安装LAMP server,参见<Ubuntu下快速安装LAMP server& ...

  10. xml+js+html的二级联动

    首先需要准备的文档是: cities.xml //主要是标注中国各省及其各省下的各个城市 内容如下: <?xml version="1.0" encoding="U ...