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实验】消息缓冲区的更多相关文章
-
【uTenux实验】邮箱
邮箱是一个通过在系统(共享)内存空间传递消息来实现同步和通信的对象.uTenux中每个邮箱都包含一个用来发送消息的消息队列和一个用于等待接收消息的任务队列,其使用邮箱功能的消息内容放置在发送方和接收方 ...
-
【uTenux实验】集合点端口
这个是头一次接触的概念.比较不好理解.内核规范中的说明就要20页! 看了王总写的uTenux内核规范之后,有那么一点明白了但理解不深. 集合点端口就像每次工作前的收集情况会.首长下达收集情况指令,各个 ...
-
【uTenux实验】中断处理
中断处理是一个比较有意思的东西.uTenux的中断处理包括了处理外部中断.CPU异常等.他是OS中任务无关部分.因此,当中断到来的时候OS会停止任务调度,不会发生任务切换.直到程序从中断中返回. uT ...
-
【uTenux实验】写在开始实验之前
1.使用的uTenux内核代码:http://www.uloong.cc/cn/download/uTenux_V1.6.00r180.zip 2.uTenux的特性: 1.微内核 2.开放源码.完 ...
-
【uTenux实验】任务管理
任务就是一个无限循环.uTenux提供的任务管理功能是很强大的,包括建立和删除一个任务,启动或退出任务,取消一个任务的启动请求,改变任务的优先级和査询任务状态,使任务进人睡眠状态和唤醒状态,取消唤醒请 ...
-
【uTenux实验】信号量
信号量(semaphore)是一个用来指示可用的资源并将可用资源的数量以数值的形式表示出来的对象.当使用一组资源时,信号量用来实现互斥控制和同步.uTenux提供了信号量出来的API,可以很方便地使用 ...
-
【uTenux实验】事件标志
事件标志是一个用来实现同步的对象,由多个位组成,用作指示对应事件存在的标志.事件标志由用来指示对应事件存在的位模式(bitpattern)和一个等待事件标志的任务队列组成. uTenux提供了一组AP ...
-
【uTenux实验】互斥体
互斥体,*中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...
-
【uTenux实验】内存池管理(固定内存池和可变内存池)
1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...
随机推荐
-
AssetBundle系列——游戏资源打包(一)
将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内容资源assetbundle(2)资源维护列表,包含每个资源的名字(完整路径名)和对应的版本号[资源名 ...
-
瀑布流布局--原生JavaScript
HTML(注意包裹关系,方便js调用) <body> <div id="main"> <div class="box"> & ...
-
Android AndroidManifest学习笔记
<application>标签 : android:allowBackup="true" 数据可以备份 <activity>标签:configChanges ...
-
commons.net.telnet使用示例
import org.apache.commons.net.telnet.TelnetClient; import java.io.IOException; public class TelnetDe ...
-
Office Add-in 设计规范与最佳实践
作者:陈希章 发表于 2017年8月6日 引子 离上一篇Office Add-in的文章已经过去了一段时间,期间有去年Office 365 Asia Devday & Hackathon的二等 ...
-
Spring 对事务管理的支持
1.Spring对事务管理的支持 Spring为事务管理提供了一致的编程模板,在高层次建立了统一的事务抽象.也就是说,不管选择Spring JDBC.Hibernate .JPA 还是iBatis,S ...
-
stark组件开发之列表页面自定义函数扩展
对于展示页面, 可能需要显示一些. 数据库中,没有的字段. 比如, 删除按钮, 编辑按钮. 这个数据库,是没有的. 所以,可能就需要, 添加一个这个东西. 比如我在渲染的时候, 给他添加两个函数进 ...
-
zifutongji
第三次作业要求我们自己写程序,我算我们班写的比较晚的了,我听他们写的都是在文件中写一段代码,然后读出来.我们班大部分都是,所以,我就想可不可以跟他们不一样呢,写一个属于自己的思路. 所以我想到了数组. ...
-
Kubernetes部署SpringCloud(二) 部署ZUUL与服务 非host, 伸缩与负载均衡
因为服务需要可缩容,所以不能使用host部署. 涉及两个应用,zuul,basic-info-api 验证,在k8s任意一个node 从zuul 访问 basic-info-api 创建一个Sprin ...
-
成都达内推荐PHP书籍【update 2017.1.10】
[初阶](基础知识及入门) 01. <PHP与MySQL程序设计(第4版)> 02. <深入浅出MySQL 数据库开发 优化与管理维护 第2版> 03. <实战Nginx ...