技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
这里任务间通信可以有两种方式,全局变量是一种,比如A,B,任务,占用资源C
那么,这里可以使用,关闭中断,信号量,互斥信号量,上锁的方式来保证资源的独占.
还可以使用消息队列
这里数据的指针,就是比如把数据放到一个数组里,那么这里传的就是这个数组的指针.
然后这个可见性
这个可见性指的是,比如这里的,
在A,B之间传递消息C,那么C这个数据,在,A,B传递过程中要保证C这个数据,一直都是有效的.
这里,我们消息队列,传递数据,用的是指针,要注意并不是copy数据,因为copy数据,还需要占用内存.
这里传递一个指针,不会占用内存.节省了内存.
然后这里采用动态内存分配的技术,给消息分配内存块用malooc,使用完内存再释放
然后要注意传递的消息,可以是全局变量,全局数据结构,全局数组,函数指针
一定不要是局部的,因为局部的,脱离了函数,就无效了,那么
很可能导致传递过去的数据就无效了.
所以这里消息数据的定义,一定要使用全局的,或者使用static,来定义一下这个变量.
消息队列就是个结构体.
去看看代码
消息队列的函数,是这个文件os_q.c
去看看这个OS_Q这个消息队列结构
可以看到这个os_q的消息队列结构
然后看看这个结构体中的OS_MSG_Q这个值.
可以看到这里
InPtr 这个是就是 in进入
OutPtr 这个就是 out出,都是个指针
这里就是消息队列的进和出
因为有个队列那么把数据插入到消息队列的什么位置,用这个in来设置,
然后读取的时候,这个消息数据就要OUT
然后NbrEntriesSize,这个是消息队列中,能插入的消息最大数
然后NbrEntries是,当前消息队列用了允许的最大数的多少.
然后NbrEntriesMax这个是,从开始到现在,历史上用到过的,消息队列最大值是多少.
举个例子,这里一个消息队列,有4个盒子,也就是说,
这个消息队列最大可以放四个数据块NbrEntriesSize
然后如果来了第5个数据块,那么就不能放了,就要等第一个数据块
获取了数据以后,才能用.
然后,咱们说还有一个时间戳,去看看
可以看到跟上面说的一样,这个消息,第一个NextPtr这个是指向下一个消息的指针
然后MsgPtr这个是指向当前消息数据的指针
然后MsgSize这个是,消息的大小
然后MsgTs是时间错可以看到就是这三个都有了.
可以看到这个图就比较清楚了.
标红的是重点的三个
去代码看看这三个函数
OSQCreate()这个是创建消息队列
p_q是消息队列
然后p_name是消息名称
然后max_qty是 消息队列最大容纳多少个消息
p_err 是错误码
这里,是请求消息队列
OSQPend()
p_q是要请求哪个消息队列
timeout是超时 ,0就是一直等待消息队列
opt是选项,去看看选项.
这个
OS_OPT_PEND_BLOCKING 是阻塞等待和
OS_OPT_PEND_NON_BLOCKING是不阻塞等待.
这个是接收到的消息的大小是多少
p_ts是时间错
p_err是错误码
这个是消息发送,第一个p_q是
要向哪个消息队列发送消息
p_void是真正的消息,这里是指针,就是要发送什么样的消息.
这个是msg_size这个是要发送的消息的大小,这里要注意,这里是字节.
这里
选项的话
OS_OPT_POST_ALL这个,是向所有等待这个消息的任务发送消息
然后
OS_OPT_POST_FIFO 是,消息的进出方式,FIFO,先进先出
OS_OPT_POST_LIFO 是,消息的进出方式,LIFO,后进先出
OS_OPT_POST_NO_SCHED这个是 不做任务切换.
选项还可以做一些组合使用,具体的组合方法已经列出来了.
去看看案例去:
这里,开始任务start_task然后
main任务
然后按键处理任务
消息显示任务
然后后面代码:
可以看到,这里
KEYMSG_Q_NUM 1这个是定义了,消息队列的数量,按键消息队列的数量,这里按键消息队列只能存储一个消息
然后
DATAMSG_Q_NUM 4这个是 发送数据的消息队列的数量,可以发送4个消息
然后这里定义了
OS_Q KEY_msg 按键消息的消息队列,用来模拟消息邮箱,咱们知道
再UCOII中是由消息邮箱概念的,在UCOSIII中没有消息邮箱概念了
消息邮箱和普通的消息队列的区别就是,消息邮箱,只能存放一条消息数据.
OS_Q DATA_Msg 定义一个数据消息队列用来发送消息的
后面声明了一个定时器.,可以看到定时器的回调函数
然后main函数中,创建消息队列
然后去创建定时器1
然后再去创建三个任务
然后去看看,定时器1的,回调函数做了啥.
可以看到,首先去申请一段内存,然后
然后这里,往申请的内存中去放一个字符串,pbuf中放入字符,然后
执行的次数msg_num++,也就是发送消息的次数,也放到申请的内存pbuf中去.
然后再去发送消息,就把这个pbuf发送出去,可以看到
定了10个消息长度,然后
选项,先进先出
然后再判断发送消息成功,发生错误的时候,就释放内存,停止定时器,
然后定时器的运行状态更新为停止运行
然后屏幕打出,定时器停止的字样.
这里为什么要,出现错误的时候要,停止定时器呢?
因为咱们知道,这个定时器,一直执行,所以会一直申请内存,那么
也没释放内存,所以这里一直申请内存就会
导致内存溢出,溢出以后,再发送消息除了错误,这里就要关闭定时器,不让他再去申请内存了.
malloc这个文件,定义了这个函数
再看看main函数
这里,当按下key0的时候
去发送消息然后,检测一下消息队列的容量是多少.
可以看到这里的key就是个值
那么可以看到,这里就是把key的值取出来,放到消息里面,发送出去了
然后再去看看
这个按键消息处理任务
可以看到,这个按键消息处理任务重针对,不同的按键做了不同的操作.
然后消息显示任务
可以看到,消息显示任务,这里
msgdis_task就是,先去请求消息
然后,然后把请求到的消息,显示出来,
然后再释放消息内存,这个
释放消息内存,就对应
前面,定时器的回调函数中消息申请内存
然后下载到开发版上看一下
启动可以看到这类定时器1,首先是停止的,
然后,再去看看,检查消息队列大小
这里可以看到,这里用消息队列的大小,减去当前使用了的,消息的大小,
从而,获取到,消息队列剩余的大小
msgq_remain_size
可以看到,数据消息发送队列,是4,剩余也是4.
然后按下不同按键就有对应的反应.
可以看到,按键以后,就可以看到,DATA_MSG去显示消息,同时剩余的DATA_Msg_rema
就增加了
任务内建消息,用于,多个任务等待统一消息队列.
看看代码如何使用:
有三个任务,start开始任务,main任务,然后
消息任务
然后,声明,任务内建消息长度
定时器1.
main函数中,可以看到,这里并没有创建消息队列,只是创建了定时器1.
而且又去创建了各个任务
msgdis_TaskTcb这个是消息显示任务
这个是定时器的回调函数,可以看到这里
OSTaskQPost
这个是发送消息的话,就是给哪个任务去发送消息OS_TCB
然后这里按键
按键没有做消息发送,仅仅做了按键扫描然后,开启,和停止定时器就可以了.
这显示的话,就是请求的时候,没有,请求哪个消息队列,默认就是请求自己任务的消息队列.
去下载到开发版看看效果