浅析 FreeRTOS 的队列传输数据原理及方式

发布时间:2026/6/27 2:33:19
浅析 FreeRTOS 的队列传输数据原理及方式 底层实现队列传输数据的底层实现是通过memcpy函数实现的内存拷贝。队列创建函数动态QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize )其中uxQueueLength是这个队列最大能容纳的元素数量uxItemSize是每个元素的大小。队列发送数据函数尾插xQueueSend(QueueHandle_t xQueue,const void *const pvItemToQueue, TickType_t xTicksToWait )其中xQueue是所使用的队列的句柄pvItemToQueue是所要传输的数据的起始地址xTicksToWait则是允许阻塞的最长时间。xQueueSend的底层实现便是从pvItemToQueue所指向的地址开始使用memcpy函数拷贝uxItemSize长度字节的内存到xQueue的队列环形缓冲区的pcWriteTo所指向的内存实现数据的拷贝。了解了上述内容再来看接下来的三种数据拷贝方式。三种拷贝三种拷贝方式分别是深拷贝、浅拷贝、零拷贝。由其名称也能看出三种拷贝真正所拷贝的数据的大小越来越小直到零拷贝完全未对任何数据进行拷贝。传值Queue by Value可近似理解为深拷贝深拷贝即将所有要拷贝的数据原原本本的拷贝到目标内存中。这种拷贝方式最耗费内存和时间但是对要拷贝的变量的存储方式没什么要求也就是可以对局部变量进行拷贝。在使用队列发送数据时如果使用的的队列句柄所指向的队列在创建时的uxItemSize是sizeof(data_t)也就是数据块本身的大小那此时所使用的方式就是深拷贝。传引用Queue by Reference可近似理解为浅拷贝浅拷贝即只将要拷贝的数据的地址拷贝到目标内存只拷贝一个指针变量的大小。这种拷贝方式耗费时间近乎于 0 。但是由于数据接收方想要访问这块数据前提是传来的指针最终指向的数据必须能在原函数结束之后继续存在也就是不能存储于函数的栈帧内不能是局部变量。这就要求这个指针要指向通过动态分配的内存或者是一个全局变量。在使用队列发送数据时如果使用的的队列句柄所指向的队列在创建时的uxItemSize是sizeof(void *)也就是指针的大小并且传入的pvItemToQueue是指向数据的指针的地址那此时所使用的方式就是浅拷贝。基于共享内存的零拷贝Zero Copy零拷贝顾名思义就是不对任何内存进行拷贝。零拷贝是利用共享内存进行实现的所以此时数据的发送、接收方实际上需要的仅是共享内存写入 / 读取完毕的通知。这种拷贝方式完全不耗费任何拷贝时间只需要考虑到通知对方的时间。由于完全不需要拷贝这种方式其实可以脱离队列进行实现需要的只是一块共享内存以及消息通知机制。这个消息通知机制可以是二进制信号量、互斥量、事件组、任务通知效率最高等等。