【FreeRTOS】第七课(1):任务间通信(使用队列)
目录
一、通信方法概述
1.使用全局变量
2.使用环形缓冲区
3.使用队列(重点介绍)
二、环形缓冲区的简单介绍
三、使用队列进行通信
1.以流水线举例
1)分析作为接收方B的执行流程
一、通信方法概述
多任务间的通信可以使用全局变量、环形缓冲区、队列
无互斥措施有可能会导致多个任务同时使用一个功能函数
无阻塞-唤醒措施会让一些暂时没有发挥作用的任务占用CPU资源
1.使用全局变量
可以简单地使用一个int类型的变量作为标志位来传递信息,也可以使用结构体来传递信息
可传输数据个数:一个变量只能传递一个数据
互斥措施:无
阻塞-唤醒:无
2.使用环形缓冲区
可传输数据个数:多个
互斥措施:无
阻塞-唤醒:无
3.使用队列(重点介绍)
可传输数据个数:多个
互斥措施:有
阻塞-唤醒:有
二、环形缓冲区的简单介绍
环形缓冲区可以看做一个首尾相连的数组
对环形缓冲区的读写如下
//初始时 w 和 r 都在数组第一个元素位置
//环形缓冲区空:r == w
//环形缓冲区满:w走到数组最后一个元素位置,再++就要返回第一个元素的位置//判断环形缓冲区未满不能依靠 w == r,因为此时也有可能是 w 写完一轮回到起点了
//可以借助一个新的变量 next_w = w + 1 来标识 w 是否已经写满数组了int w = 0;
int r = 0;
int next_w = w + 1;
int buf[8] = { 0 };//当环形缓冲区未满时可以往里面写数据
if ( next_w != r )
{buf[w] = val;w++;//当 next_w == 8 时说明 w 已经写满数组了,写到数组最后一个元素的位置了if ( next_w == 8 ){next_w = 0;}
}//当环形缓冲区内有数据时可以读数据
if ( r != w )
{val = buf[r];r++;//当读溢出时回到数组第一个元素位置if ( r == 8 ){r = 0;}
}
三、使用队列进行通信
队列读写的本质就是使用加了互斥和阻塞-唤醒措施的环形缓冲区
FreeRTOS中的任务队列由两个链表组成,一个链表是等待发送链表,一个链表是等待接收链表
使用三个变量:写位置、读位置、计数值
每写一个数据,计数值就+1
每读一个数据,计数值就-1
不读写数据,只修改计数值,此时计数值就是信号量
保证计数值为1,此时计数值就是互斥量
1.以流水线举例
把A任务(也可以是中断程序)看做A工人,B任务看做B工人,两者进行数据交换的场所(队列)就是流水线
A工人需要借助流水线把产品交给B工人
流水线不是时时刻刻都有空位的,在流水线上没有空位的时候A工人可以休息一会
流水线不是时时刻刻都有产品的,在流水线上没有产品的时候B工人可以休息一会
发送方:需要面对流水线满的情况
每隔一段时间依靠闹钟唤醒自己去检查流水线上是否有空的位置放产品
当B工人把流水线上的一个产品处理掉时,即使闹钟没响,B工人也会主动叫醒A工人
接收方:需要面对流水线空的情况
每隔一段时间依靠闹钟唤醒自己去检查流水线上是否有产品
当A工人把产品放到流水线上时,即使闹钟没响,A工人也会主动叫醒B工人
1)分析作为接收方B的执行流程
创建后被放入就绪链表中得到运行
需要等待A任务发来“产品”,此时B任务会从就绪链表同时转放在阻塞链表和队列的等待接收链表中
如果A任务发来了“产品”,它就会把B任务唤醒,将B任务从阻塞链表和队列的等待接收链表中重新放入就绪链表中运行
如果A任务没有发来产品,但是闹钟时间到了,B任务也会被从阻塞链表和队列的等待接收链表中重新放入就绪链表中运行,同时给出返回值表示是因为长时间没有“产品”依靠闹钟唤醒的