对列(queue)是任务间通信的一种简单实现方式,可以用来在任务间传递下数据,或者在中断与任务之间。新数据会被发送至队列尾部,在大多数情况下,队列是线程安全的先进先出(FIFO)缓冲器。当然,数据同样可以被发送至队列首部。

下面的动图演示了任务A将数据发送至队列尾部,任务B将数据取出,完成任务间数据交换:

queue

用户模型:最大限度的简化、最高限度的灵活性

灵活性与简单性通常是两种互斥的属性,但是在freeRTOS中,这被优雅的融合在一起了。任务在发送数据到队列中的时候,实际上是发送的是原数据的一份拷贝,对于多字节的数据同样可以将数据指针的拷贝发送至队列,这样设计的优点是显而易见的:

  • 这意味这不需要额外申请空间给需要传递的数据,使用队列自身的空间即可。节省了申请空间、复制传递数据的空间开销。同时,因为数据拷贝,对于发送数据的任务来说,这个数据是复用的,即不需要管其他任务是否接收到这个数据,发送任务即可以对原数据进行改写等其他处理。另外,正因为如此,发送任务不需要等待其他任务响应是否接收到数据,发送与接收是独立的,是任务的各自行为,这降低了队列之间数据传递的复杂性。

  • 数据拷贝的方式的另外一种情况是通过传递数据引用(或指针),在原数据比较大的情况下,无法逐字节去将数据拷贝到队列中,此时传递数据的指针是更加合理的处理方式,不过这时候需要考虑,原任务改变数据,接收任务接收到数据也会随之改变。实际上,freeRTOS+UDP传递网络数据帧的就是通过这种方式进行的。

  • 由内核负责队列存储区的内存分配和管理,降低了用户的使用难度。

  • 某个队列可以用来传递多个地方的多种消息类型。比如定义一个结构体,结构体中的成员A负责定义消息类型,成员B负责保存数据或者指针。这样就完成了多种消息类型的传递。

  • 队列的这种实现方式同样适用于使用内存保护的环境中,任务在受保护的内存单元中传递数据时,RTOS调用队列的发送函数将提升处理器的权限,队列的存储区域只能由freeRTOS的内核访问。

  • 在中断中使用的API函数是与任务中使用的API不同的,这意味着,每次API调用不需要在每次调用的时候去检查调用上下文。同时,这也意味着,与其他RTOS相比,用户在实现中断服务的时候需要考虑的更少。

  • API简单

队列阻塞

队列的API在使用时可以定义一个阻塞时间。空队列的读、满队列的写都会导致任务被挂起,除非空队列有了数据或者满队列有了可用空间,否则直到阻塞时间结束,任务将一只处在阻塞状态下。

如果一个队列中,有多个任务因为这个队列而阻塞,那么当队列有效的时候,拥有最高优先即的任务将退出阻塞态。

你可以在”队列管理”一节中获得更多信息,也可以通过freeRTOS提供的相关例程熟悉队列的用法,这部分内容在FreeRTOS/Demo/Common/Minimal路径下。

需要提醒的是,中断中所有队列的操作都需要使用后缀为FromISR的API。