queue-management
2025-09-07 19:41:08

进程间通信方式

两种方式

  • a图采用进程间共享内存,共用和交互数据更快
  • b图采用消息队列,更通用更稳定
    全局变量不太线程安全
    example
    TaskA和B之间通过队列交互数据,A写B读。

队列的实现方式

  • 复制队列(Queue by copy):写入队列的数据每个字节都被完整复制到队列中。
  • 引用队列(Queue by reference):写入队列的是数据的引用或指针。

FreeRTOS采用复制队列。优势如下:

  • 有些储存在栈上的变量在函数运行结束后是将会被销毁的,如果采用引用队列的话引用会失效
  • 发送数据的任务可以重复使用变量,采用引用队列的话每发送一个数据需要一个新的变量
  • 发送队列数据的任务和接受队列数据的任务之间是没有耦合的,两者互相不影响
  • 复制队列可以通过储存指向数据块的指针实现引用队列的功能

一个队列可以有对个写入数据的任务和多个读取数据的任务。
阻塞时间(block time):当队列数据为空时,任务处于阻塞状态的时间。
当任务尝试读取队列数据时,可以设置一个阻塞时间(xQueueReceive())。 当有数据在队列或到达阻塞时间时,任务进入就绪状态。如果有多个任务同时在阻塞状态等待队列数据,优先级高的任务会在数据到达时进入就绪状态;在优先级相同的时候,等待时间长的任务会进入就绪状态。
同理可得多个任务写入队列的情景。
同时,FreeRTOS 允许任务使用队列集同时等待多个队列,当队列集中的任何一个队列收到数据时,任务可以被唤醒。

常见API

FreeRTOS API

  1. 创建队列
1
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize )
  • 返回值是QueueHandle_t具柄类型,表示的是对所创建队列的一个引用句柄。FreeRTOS从FreeRTOS的堆中指定一些内存空间给队列使用。如果堆中没有足够空间给队列使用的话函数的返回值会是NULL
  • uxQueueLength:队列包含数据的最大长度
  • uxItemSize:每个数据占用的字节大小
  1. 发送数据
1
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue,TickType_t xTicksToWait )

xQueueSend()函数用于将数据发送到队列(具体一点就是队列的尾部)。如果要在中断程序调用的话需要使用xQueueSendFromISR()函数(只能在中断函数中使用)。

  • xQueue 队列的具柄,来自于xQueueCreate()的返回值
  • pvItemToQueue 所发送数据的引用,然后这些数据会被复制到队列中
  • xTicksToWait 队列如果满时发送任务的阻塞时间(block time),上文已经介绍过,可以通过pdMS_TO_TICKS()把时间转换成节拍数。如果设置为portMAX_DELAY的话任务将永远等待下去(需要FreeRTOSConfig.h头文件中INCLUDE_vTaskSuspend参数设置为1)
    返回值 发送数据成功时返回pdPASS,失败时返回errQUEUE_FULL
1
2
BaseType_t xQueueSendToFront( QueueHandle_t xQueue, const void * pvItemToQueue,TickType_t xTicksToWait )
BaseType_t xQueueSendToBack( QueueHandle_t xQueue, const void * pvItemToQueue,TickType_t xTicksToWait )

可选择发送到队列开头还是结尾,xQueueSendToBack本质和xQueueSend是一样的。

  1. 接收数据
1
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer,TickType_t xTicksToWait )

xQueueReceive用于从队列里读取数据,同时读取到的数据会被从队列中移除。

  • xQueue 队列的具柄,来自于xQueueCreate()的返回值
  • pvBuffer 指向内存空间的一个引用,读取的数据会被复制到这片内存
  • xTicksToWait 队列如果空时接送任务的阻塞时间(block time),如果设置为portMAX_DELAY的话任务将永远等待下去(需要FreeRTOSConfig.h头文件中INCLUDE_vTaskSuspend参数设置为1)

返回值 接收数据成功时返回pdPASS,失败时返回errQUEUE_EMPTY

  1. 查询队列数据数量
1
UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue )
  1. 查看数据
1
2
    BaseType_t xQueuePeek(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait
);

查看队列前面的数据项,但不会将其移除。中断中使用xQueuePeekFromISR

  • xQueue:要读取的队列句柄。
  • pvBuffer:指向用于存储队列项的缓冲区的指针。
  • xTicksToWait:如果队列为空,任务等待的最大时间(tick 数);如果为 0,则立即返回。
    返回值 成功读取pdTRUE,没读到返回pdFALSE。

CMSIS RTOS API

CMSIS API

图形化配置

cubemx
Item Size可以换成用户自定义的结构体类型。

CMSIS中邮件队列

引用队列的实现,叫做邮件队列(mail queue),传递的是储存数据块的地址指针。
mail-queue