queue-management
2025-09-07 19:41:08
进程间通信方式

- a图采用进程间共享内存,共用和交互数据更快
- b图采用消息队列,更通用更稳定
全局变量不太线程安全

TaskA和B之间通过队列交互数据,A写B读。
队列的实现方式
- 复制队列(Queue by copy):写入队列的数据每个字节都被完整复制到队列中。
- 引用队列(Queue by reference):写入队列的是数据的引用或指针。
FreeRTOS采用复制队列。优势如下:
- 有些储存在栈上的变量在函数运行结束后是将会被销毁的,如果采用引用队列的话引用会失效
- 发送数据的任务可以重复使用变量,采用引用队列的话每发送一个数据需要一个新的变量
- 发送队列数据的任务和接受队列数据的任务之间是没有耦合的,两者互相不影响
- 复制队列可以通过储存指向数据块的指针实现引用队列的功能
一个队列可以有对个写入数据的任务和多个读取数据的任务。
阻塞时间(block time):当队列数据为空时,任务处于阻塞状态的时间。
当任务尝试读取队列数据时,可以设置一个阻塞时间(xQueueReceive())。 当有数据在队列或到达阻塞时间时,任务进入就绪状态。如果有多个任务同时在阻塞状态等待队列数据,优先级高的任务会在数据到达时进入就绪状态;在优先级相同的时候,等待时间长的任务会进入就绪状态。
同理可得多个任务写入队列的情景。
同时,FreeRTOS 允许任务使用队列集同时等待多个队列,当队列集中的任何一个队列收到数据时,任务可以被唤醒。
常见API
FreeRTOS API
- 创建队列
1 | QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize ) |
- 返回值是QueueHandle_t具柄类型,表示的是对所创建队列的一个引用句柄。FreeRTOS从FreeRTOS的堆中指定一些内存空间给队列使用。如果堆中没有足够空间给队列使用的话函数的返回值会是NULL
- uxQueueLength:队列包含数据的最大长度
- uxItemSize:每个数据占用的字节大小
- 发送数据
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 | BaseType_t xQueueSendToFront( QueueHandle_t xQueue, const void * pvItemToQueue,TickType_t xTicksToWait ) |
可选择发送到队列开头还是结尾,xQueueSendToBack本质和xQueueSend是一样的。
- 接收数据
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 | UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ) |
- 查看数据
1 | BaseType_t xQueuePeek(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait |
查看队列前面的数据项,但不会将其移除。中断中使用xQueuePeekFromISR
- xQueue:要读取的队列句柄。
- pvBuffer:指向用于存储队列项的缓冲区的指针。
- xTicksToWait:如果队列为空,任务等待的最大时间(tick 数);如果为 0,则立即返回。
返回值 成功读取pdTRUE,没读到返回pdFALSE。
CMSIS RTOS API

图形化配置

Item Size可以换成用户自定义的结构体类型。
CMSIS中邮件队列
引用队列的实现,叫做邮件队列(mail queue),传递的是储存数据块的地址指针。
