1、队列简介
概念:
队列是任务到任务、任务到中断、中断到任务数据交流的一种机制,说白了,队列就是用来传递消息的。
---------------------------------------------------------------------------------------------------------------------------------
类似全局变量的作用,但又和全局变量有所不同。
全局变量的弊端:数据无保护,导致数据不安全,当多个任务同时对该变量操作时,数据易受损。
当有一个任务写队列或者读队列的时候,会组织其他任务对队列进行操作,就会避免全局变量的弊端。
---------------------------------------------------------------------------------------------------------------------------------
队列项目和队列长度:
在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做队列项目,队列能够存储队列项目的最大数量称为队列长度。
队列的特点:
1、数据入队出队方式:队列通常采用“先进先出”(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS中也可以配置为”后进先出“LIFO方式。
2、数据传递方式:FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递,FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递。
3、多任务访问:队列不属于某个任务,任何任务和中断都可以向队列发送/读取消息。
4、出队、入队阻塞:当任务向队列发送消息时,可以指定一个阻塞时间,假设此时当队列已满无法入队:
①若阻塞时间设置为0 :直接返回不会等待;
②若阻塞时间设置为0-port_MAX_DELAY:等待设定的阻塞时间,若在该时间内还无法入队,超时后直接返回不再等待;
③若阻塞时间设为port_MAX_DELAY:死等,一直等到可以入队为止。出队阻塞与入队阻塞类似。
那返回是什么意思?应该不是简单的不再传递数据,肯定会有相应的错误处理。
注意,当多个任务写入消息给一个”满队列“时,这些任务都会进入阻塞状态,也就是说有多个任务在等待同一个队列的空间。当队列中有空间时,优先级最高的任务会进入就绪态,如果大家优先级都相同,那么等待时间最久的任务会进入就绪态。
队列的基本操作过程:
2、队列结构体
队列分为两部分,一部分为队列结构体,另一部分为存储区域。
后边两个队列锁,听课说是当上锁的时候,可以正常读写队列,然是不能操作等待发送列表和等待接收列表,咱也不知道用处是啥,慢慢学,后边见分晓。
后边介绍那个联合体。
最后,上一张队列图。
3、队列相关API函数
我们使用队列的一般流程是:创建队列,然后写队列,最后读队列嘛。
创建队列相关API函数:
动态方式创建队列
xQueueCreate()
它其实是一个宏定义,穿了个马甲,下边看看穿上马甲的全貌吧。
#define xQueueCreate ( uxQueueLength, uxItemSize )
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE ))
第一个参数uxQueueLength是队列的长度,第二个参数uxItemSize是队列项目的大小,第三个参数queueQUEUE_TYPE_BASE是创建的类型是啥,先看看都有啥类型。
有这些,由此我们便可以想到,队列集、互斥信号量等等其实都是由这个函数干的,只不过后边它穿上了不同的马甲。
再来说下返回值吧,当返回值是NULL的时候,表示队列创建失败,当返回值是其他值的时候,代表队列的句柄,表示队列创建成功,句柄还是比较重要的,操作队列需要用到。
由于经常使用的是动态方式创建队列,所以课程里边只介绍了动态方式,等后边我搜搜资料,我再把静态方式加进来。
写队列相关API函数:
写队列主要分为两种吧,一个是在任务中写队列,一个是在中断中写队列。其实又可以分为另外三种,往队列首部写、尾部写和覆写。分类方式不同。
看看穿上马甲的全貌
写入位置相关的宏定义
形参和返回值说明
读队列相关API函数
这个信息读取缓冲区,就是接收消息的一个变量的地址,注意它这是一个指针常量。