1、队列(Queue)概述
队列可以用于"任务到任务"、"任务到中断"、"中断到任务"直接传输信息。队列涉及内容如下:
- 怎么创建、清楚、删除队列
- 队列中消息如何保存
- 怎么向队列发送数据、怎么从队列读取数据、怎么覆盖队列的数据
- 在队列上阻塞式什么意思
- 怎么在多个队列上阻塞
- 读写队列时如何影响任务的优先级
2、队列的特性
2.1、常规操作
(1)队列的简化操如入下图所示,从此图可知:
- 队列可以包含若干个数据:队列中有若干项,这被称为“长度”(length)
- 每个数据大小固定
- 创建队列时就要指定长度、数据大小
- 数据的操作采用先进先出的方式(FIFO,First In First Out):写数据时放到尾部,读数据时从头部读
- 把数据写到队列头部,不会覆盖原来的数据。(队列中的数据使用环形缓冲区管理数据,把数据放到头部时,会先移动头部位置,并不会覆盖原来的数据)
(2)更详细的操作如下图所示:
2.2、传输数据的两种方式
(1)使用队列传输数据时有两种方法:
- 拷贝:把数据、把变量的值复制进队列里
- 引用:把数据、把变量的地址复制进队列里
(2)FreeRTOS使用拷贝值的方法特点:
- 局部变量的值可以发送到队列中,后续即使函数退出、局部变量被回收,也不会影响队列中的数据
- 无需分配buffer来保存数据,队列中有buffer
- 变量可以马上再次使用(赋予其他值,引用则不行)
- 发送任务、接收任务解耦:接收任务不需要知道这数据是谁的、也不需要发送任务来解释数据
- 队列的空间有FreeRTOS内核分配,无需任务操心
- 对于有内存保护功能的系统,如果队列使用引用方法,也就是使用地址,必须确保双方任务对这个地址都有访问权限。使用拷贝方法时,则无此限制:内核有足够的权限,把数据复制进队列、再把数据复制出队列。
(3)引用的特点:
- 如果数据实在太大,可以使用队列传输它的地址
2.3、队列的阻塞访问
(1)只要知道队列的句柄,谁都可以读、写队列。任务、ISR都可以读、写队列。可以多个任务读写队列。
(2)任务读写队列时,简单地说:如果读写不成功,则阻塞;可以指定超时时间。口语化地说,就是可以定个闹钟:如果能读写了就马上进入就绪态,否则就阻塞直到超时。
(3)某个任务读队列时,如果队列没有数据,则该任务可以进入阻塞状态:还可以指定阻塞的时间。如果队列有数据了,则该阻塞的任务会变为就绪态。如果一直都没有数据,则时间到之后它也会进入就绪态。
(4)既然读取队列的任务个数没有限制,那么当多个任务读取空队列时,这些任务都会进入阻塞状态:有多个任务在等待同一个队列的数据。当队列中有数据时,哪个任务会进入就绪态?
- 优先级最高的任务。
- 如果大家的优先级相同,那等待时间最久的任务会进入就绪态。
(5)跟读队列类似,一个任务要写队列时,如果队列满了,该任务也可以进入阻塞状态:还可以指定阻塞的时间。如果队列有空间了,则该阻塞的任务会变为就绪态。如果一直都没有空间,则时间到之后它也会进入就绪态。
(6)既然写队列的任务个数没有限制,那么当多个任务写"满队列"时,这些任务都会进入阻塞状态:有多个任务在等待同一个队列的空间。当队列中有空间时,哪个任务会进入就绪态?
- 优先级最高的任务。
- 如果大家的优先级相同,那等待时间最久的任务会进入就绪态。