消息队列

  • 传输的数据不定长
  • 支持先进先出FIFO,同时支持后进先出LIFO
  • 均支持超时机制。
  • 每个消息队列都与消息空间在同一段连续的内存空间中
  • 消息队列的大小是消息队列控制块大小+(单个消息空间大小 * 消息队列长度)
  • 任务或者中断服务程序都可以给消息队列发送消息
  • 超时发送,超时发送失败返回 errQUEUE_FULL
  • 发送紧急消息,就是放在队列头部
  • 支持 消息读超时

同步互斥的方法对比

包含头文件

#include <queue.h>
  • 消息队列运作模型

    读消息的3中情况
  1. 有就取出,没有 扭头就走
  2. 没有等一会儿
  3. 死等消息
    发送消息
    队列满了就等会儿,超时了就返回errQUEUE_FULL

消息队列的内存结构

数据结构

typedef struct QueueDefinition
{int8_t *pcHead;                    /*< 指向队列消息存储区起始位置,即第一个消息空间 */int8_t *pcTail;                  /* 指向队列消息存储区结束位置地址 */int8_t *pcWriteTo;             /*< 指向队列消息存储区下一个可用消息空间. */union                          /* 是一对互斥变量*/. */{int8_t *pcReadFrom;            /*< Points to the last place that a queued item was read from when the structure is used as a queue. */UBaseType_t uxRecursiveCallCount;/*当结构体用于互斥量时,uxRecursiveCallCount 用于计数 */} u;List_t xTasksWaitingToSend;      /*< 发送消息阻塞列表 */List_t xTasksWaitingToReceive;    /*< 个获取消息阻塞列表 */volatile UBaseType_t uxMessagesWaiting;/*< 当前消息队列的消息个数 */UBaseType_t uxLength;            /*< 队列的长度 */UBaseType_t uxItemSize;          /*< 示单个消息的大小*/volatile int8_t cRxLock;       /*< 队列上锁后,储存从队列收到的列表项数目,也就是出队的数量 如果队列没有上锁,设置为 queueUNLOCKED*/volatile int8_t cTxLock;       /*< 队列上锁后,储存发送到队列的列表项数目,也就是入队的数量 如果队列没有上锁,设置为 queueUNLOCKED*/#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */#endif#if ( configUSE_QUEUE_SETS == 1 )struct QueueDefinition *pxQueueSetContainer;#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif} xQUEUE;

消息队列函数

1. 创建消息队列

//宏定义
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,// 队列能够存储的最大消息单元数目,能够存储的消息个数UBaseType_t uxItemSize );//队列中消息单元的大小,以字节为单位
返回NULL,创建失败,成功返回队列句柄
枚举值 说明
queueQUEUE_TYPE_BASE 表示队列
queueQUEUE_TYPE_SET 表示队列集合 。
queueQUEUE_TYPE_MUTEX 表示互斥量。
queueQUEUE_TYPE_COUNTING_SEMAPHORE 表示计数信号量。
queueQUEUE_TYPE_BINARY_SEMAPHORE 表示二进制信号量。
queueQUEUE_TYPE_RECURSIVE_MUTEX 表示递归互斥量。

2. 消息队列删除函数

 void vQueueDelete( QueueHandle_t xQueue )

1. 发送消息函数

  1. 向队列尾部发送一个队列消息
  2. 消息以拷贝的形式入队,而不是以引用的形式
  3. 该xQueueCreate函数绝对不能在中断服务程序里面被调用,
  4. 中断中使用有中断保护功能的 xQueueSendFromISR()来代替

1.1 发送消息到–尾部

//
#define       xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )BaseType_t xQueueSend(QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait);//返回:
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
xTicksToWait 队列满时,等待队列空闲的最大超时时间,超时时间的单位为系统节拍周期,portMAX_DELAY 一直等指导成功
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

1.2 发送消息到–头部


//
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )BaseType_t xQueueSendToFront( QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait );
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
xTicksToWait 队列满时,等待队列空闲的最大超时时间,超时时间的单位为系统节拍周期,portMAX_DELAY 一直等指导成功
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

1.3 通用版本

其他的非中断发送都是使用他的宏定义实现

BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) }
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
xTicksToWait 队列满时,等待队列空闲的最大超时时间,超时时间的单位为系统节拍周期,portMAX_DELAY 一直等指导成功
xCopyPosition queueSEND_TO_BACK:发送到队尾;queueSEND_TO_FRONT:发送到队头;queueOVERWRITE:以覆盖的方式发送
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

2. 中断保护版本的消息发送–中断版本

只能用于中断中执行,是不带阻塞机制的

2.1 发送消息到队列头

//
#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
pxHigherPriorityTaskWoken 如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,将*pxHigherPriorityTaskWoken设置成 pdTRUE,然后在中断退出前需要进行一次上下文切换, 去 执 行 被 唤醒 的 优 先 级 更高 的 任 务 。从FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken 作为一个可选参数,可以设置为 NULL。
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

2.2 发送消息到队列尾–中断版本


#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
pxHigherPriorityTaskWoken 如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,将*pxHigherPriorityTaskWoken设置成 pdTRUE,然后在中断退出前需要进行一次上下文切换, 去 执 行 被 唤醒 的 优 先 级 更高 的 任 务 。从FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken 作为一个可选参数,可以设置为 NULL。
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

2.3 中断发送的通用版本–中断版本

 BaseType_t xQueueGenericSendFromISR(QueueHandle_t       xQueue,const    void    *pvItemToQueue,BaseType_t   *pxHigherPriorityTaskWoken,BaseType_t   xCopyPosition//{ queueSEND_TO_BACK:发送到队尾;queueSEND_TO_FRONT:发送到队头;queueOVERWRITE:以覆盖的方式发送 });
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向要发送到队列尾部的队列消息
pxHigherPriorityTaskWoken 如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,将*pxHigherPriorityTaskWoken设置成 pdTRUE,然后在中断退出前需要进行一次上下文切换, 去 执 行 被 唤醒 的 优 先 级 更高 的 任 务 。从FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken 作为一个可选参数,可以设置为 NULL。
xCopyPosition queueSEND_TO_BACK:发送到队尾;queueSEND_TO_FRONT:发送到队头;queueOVERWRITE:以覆盖的方式发送
返回值 发送消息成功返回 pdTRUE,否则返回 errQUEUE_FULL表示队列已满。

3. 消息读取函数-普通版本

这两个函数不能用于中断,是带有阻塞机制的

移除已经获取的消息

#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )

获取消息但是不移除消息

#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )

通用版本的实现

 BaseType_t xQueueGenericReceive(QueueHandle_t   xQueue,void *pvBuffer,TickType_t    xTicksToWait,BaseType_t xJustPeek,);
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向接收到要保存的数据。
xTicksToWait 队列空时,阻塞超时的最大时间。如果该参数设置为 0,函数立刻返回。超时时间的单位为系统节拍周期,常量 portTICK_PERIOD_MS 用于辅助计算真实的时间,单位为 ms。如果 INCLUDE_vTaskSuspend 设置成 1,并且指定延时为 portMAX_DELAY 将导致任务无限阻塞(没有超时)。
xJustPeek 是否移除 pdFALSE 移除; pdTRUE 不移除
返回值 队列项接收成功返回 pdTRUE,否则返回 pdFALSE。

4. 消息读取函数-中断版本

4.1移除已经获取的消息

//移除已经获取的消息
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, //队列句柄。void * const pvBuffer, //指针,指向接收到要保存的数据。BaseType_t * const pxHigherPriorityTaskWoken )//
//返回值 队列项接收成功返回 pdTRUE,否则返回 pdFALSE。
参数 说明
xQueue 队列句柄
pvItemToQueue 指针,指向接收到要保存的数据。
pxHigherPriorityTaskWoken 任务在往队列投递信息时,如果队列满,则任务将阻塞在该队列上。如果 xQueueReceiveFromISR()到账了一个任 务 解 锁 了 则将 *pxHigherPriorityTaskWoken 设 置为pdTRUE , 否 则 *pxHigherPriorityTaskWoken 的 值将不变。从 FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken作为一个可选参数,可以设置为 NULL。
返回值 队列项接收成功返回 pdTRUE,否则返回 pdFALSE。

4.2不会把消息从该队列中移除

BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, //队列句柄void * const pvBuffer )//指针,指向接收到要保存的数据。

消息队列使用注意事项

  1. 使用 xQueueSend()、xQueueSendFromISR()、xQueueReceive()等这些函数之前应先创建需消息队列,并根据队列句柄进行操作。
  2. 队列读取采用的是先进先出(FIFO)模式,会先读取先存储在队列中的数据。当然也 FreeRTOS 也支持后进先出(LIFO)模式,那读取的时候就会读取到后进队列的数据。
  3. 在获取队列中的消息时候,我们必须要定义一个存储读取数据的地方,并且该数据区域大小不小于消息大小,否则,很可能引发地址非法的错误。
  4. 无论是发送或者是接收消息都是以拷贝的方式进行,如果消息过于庞大,可以将消息的地址作为消息进行发送、接收

消息队列的内部机制

队列的 作用

  1. 解决互斥问题,
  2. 解决cpu空转的问题

队列的核心:关中断解决互斥问题,链表实现任务的休眠和唤醒,数组实现数据的保存

typedef struct QueueDefinition /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{int8_t * pcHead;           /*< 保存数据空间的指针*/int8_t * pcWriteTo;        /*< Points to the free next place in the storage area. */union{QueuePointers_t xQueue;     /*< 消息队列的队列头*/SemaphoreData_t xSemaphore; /*<用于信号量的信号量头 */} u;List_t xTasksWaitingToSend;             /*是一个发送消息阻塞列表, 用于保存阻塞在此队列的任务, 任务按照优先级进行排序, 由于队列已满,想要发送消息的任务无法发送消息 */List_t xTasksWaitingToReceive;          /*是一个获取消息阻塞列表, 用于保存阻塞在此队列的任务, 任务按照优先级进行排序, 由于队列是空的,想要获取消息的任务无法获取到消息。*/volatile UBaseType_t uxMessagesWaiting; /*< 当前队列中保存的数据元素的个数 */UBaseType_t uxLength;                   /*队列的长度*/UBaseType_t uxItemSize;                 /*< 单个消息的大小 *//*这两个成员变量为 queueUNLOCKED 时,表示队列未上锁;当这两个成员变量为queueLOCKED_UNMODIFIED 时,表示队列上锁*/volatile int8_t cRxLock;                /*队列上锁后, 储存从队列收到的列表项数目, 也就是出队的数量,
如果队列没有上锁,设置为 queueUNLOCKED*/volatile int8_t cTxLock;                /*队列上锁后, 储存从队列收到的列表项数目, 也就是出队的数量,
如果队列没有上锁,设置为 queueUNLOCKED */#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */#endif#if ( configUSE_QUEUE_SETS == 1 )struct QueueDefinition * pxQueueSetContainer;#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif
} xQUEUE;

消息队列的初始化

  1. 分配内存,内存包括消息的队列头的空间和保存消息的空间,消息的空间 = 消息的个数 * 单个消息的大小
  2. 初始化QueueDefinition 成员

发送消息函数

接收数据函数

4.FreeRTOS学习笔记-消息队列相关推荐

  1. Linux学习笔记-消息队列的接收

    目录 接收消息 举个例子 接收消息 #include <sys/msg.h> ssize_t msgrcv(int msgqid, void *ptr, size_t nbytes, lo ...

  2. Linux学习笔记-消息队列的打开、创建、控制

    目录 打开或创建消息队列 消息队列的控制 发送消息 举个栗子 打开或创建消息队列 #include <sys/msg.h> int msgget(key_t key, int flag); ...

  3. Linux学习笔记-消息队列概念

    目录 System V IPC概念 System V IPC对象的访问 举几个例子 IPC对象的权限和所有者结构体 消息队列 消息队列属性 System V IPC概念 Unix系统存在信号.管道和命 ...

  4. 【ESP32+freeRTOS学习笔记-开篇前言】

    目录 前言的前言 RTOS的选择 开发与实践环境 参考资料 笔记的形式 专题文章的链接(持续更新中......) 前言的前言 单片机的开发,也有两年多了,之前一直是做一些简单应用,因此以裸机开发的方式 ...

  5. freeRtos学习笔记 (8) 任务通知

    freeRtos学习笔记 freeRtos任务通知 任务通知的优缺点 freeRtos任务控制块中包含两个32位的变量,用于任务通知,在一些情况下,任务通知可以替代信号量和事件组,并且比信号量和事件组 ...

  6. freeRtos学习笔记 (7)信号量

    freeRtos学习笔记 freeRtos信号量 信号量种类 信号量分为四种:二值信号量,互斥信号量,计数信号量和递归互斥信号量,其中计数信号量用于管理系统多个共享资源,用计数值表示可用资源数目;二值 ...

  7. freeRtos学习笔记 (6)软件定时器

    freeRtos学习笔记 freeRtos软件定时器 软件定时器需要注意事项 软件定时器的精度基于时钟节拍,例如系统时钟节拍为10ms, 软件定时器定时时间必须是10ms的整数倍,因此软件定时器一般用 ...

  8. freeRtos学习笔记 (5)事件组

    freeRtos学习笔记 freeRtos事件组 为什么要用事件组? 多任务环境下, 任务.中断之间往往需要同步操作,一个事件发生会告知等待中的任 务,即形成一个任务与任务.中断与任务间的同步.事件可 ...

  9. FreeRTOS学习笔记

    FreeRTOS学习笔记 (这是我自己学习FreeRTOS整理的笔记,仅供参考) 第一部分:实现FreeRTOS内核 变量名: 定义变量时往往会把变量的类型当作前缀加在变量上 变量类型 前缀 char ...

最新文章

  1. 竞赛报名 | AI时代数据库交互怎么玩?首届中文NL2SQL挑战赛开战
  2. linux elf 文件加密
  3. centos下添加的端口不能访问(防火墙关闭)
  4. Python文件操作学习总结
  5. SVN中update to revision与revert to revision的区别
  6. Leetcode 101.对称二叉树 (每日一题 20210709)
  7. 1.15 Java访问控制修饰符(public、 private、protected 和 friendly)
  8. scrapy爬虫代理——利用crawlera神器,无需再寻找代理IP
  9. C语言:L1-037 A除以B (10分)(解题报告)
  10. Qt学习笔记-使用QStyleFactory::create()变换风格
  11. Redis如何实现刷抖音不重复-布隆过滤器(Bloom Filter)
  12. 安装mysql的一些小问题
  13. 测试用例入门(二) - 使用等价类划分法编写测试用例
  14. 关键系统进程 C:\Windows\system32\lsass.exe 失败,状态代码是 255。现在必须重新启动计算机。
  15. html如何添加字体
  16. 谈论bringup我们到底在谈论什么?
  17. 即时通讯-Netty篇
  18. 第一个RDD,几个数据探查命令
  19. java 获取当前是周几_java 获取今天(某一天)是星期几/周几
  20. 移动端h5 实现多个音频播放

热门文章

  1. mysql mvcc实例讲解_轻松理解MYSQL MVCC 实现机制
  2. nsdictionary获取值_获得nsdictionary值
  3. 无法解析 uafxcw.lib_吉利DMS系统一周热点问题解析
  4. SpringCloud Consul 服务注册与发现
  5. php去掉关联数组,大家都应该掌握的PHP关联数组使用技巧
  6. 解决maven项目jdbc报错:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
  7. pytorch Embedding模块,自动为文本加载预训练的embedding
  8. Linux当前终端走代理ip
  9. windows守护进程_在Linux的Windows子系统上(WSL)使用Docker(Ubuntu)
  10. ambari mysql 密码_Ambari 切换 mysql 数据库