RTX线程通信之——消息队列

Posted Albert Nie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RTX线程通信之——消息队列相关的知识,希望对你有一定的参考价值。

Message Queue

我们知道,Thread and Event FlagsSemaphore,Mutex等通常用于触发线程的执行,并没有涉及到如何在两个线程之间交换数据。RTX提供了两种机制用于线程之间的数据传输。一个是消息队列(也称为管道),一个是邮箱队列(也称为内存池)。它们之间的区别在于消息队列一次传输一个整型或指针变量,而邮箱队列一次‘’传输‘’一个数据块

当然,本文的主人公是: 消息队列

消息队列

Message passing is another basic communication model between threads. In the message passing model, one thread sends data explicitly, while another thread receives it. The operation is more like some kind of I/O rather than a direct access to information to be shared. In CMSIS-RTOS, this mechanism is called message queue. The data is passed from one thread to another in a FIFO-like operation. Using message queue functions, you can control, send, receive, or wait for messages. The data to be passed can be of integer or pointer type:

在这里插入图片描述

抓重点,消息队列具有以下特点:

  • 类似FIFO的管道。一端负责数据传入,另一端负责数据读出,先进先出。
  • 数据类型只能是整型指针类型数据。

暂且了解这么多~

RTX 消息队列 API

类型

  • osMessageQueueAttr_t : 消息队列属性结构体
  • osMessageQueueId_t : 消息队列句柄

函数

在这里插入图片描述

osMessageQueueNew

osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t* attr)
// 输入
* msg_count : 消息队列中最大的消息数量
* msg_size : 消息的最大字节数
* attr : 消息队列属性,默认为NULL
// 输出
* 消息队列ID or NULL

osMessageQueueGetName

const char* osMessageQueueGetName(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
* 消息队列名字

osMessageQueuePut

osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id,const void* msg_ptr,uint8_t msg_prio,uint32_t timeout)
// 输入
* mq_id : 消息队列ID
* msg_ptr: 指向待放入消息的指针
* msg_prio: 消息优先级
* timeout : 超时设定
// 输出
* 函数执行状态码: osOK、osErrorTimeout、osErrorResource、osErrorParameter

osMessageQueueGet

osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id,void* msg_ptr,uint8_t* msg_prio,uint32_t timeout)
// 输入
* mq_id : 消息队列ID
* msg_ptr: 待放入对象的地址
* msg_prio : 消息优先级
* timeout: 超时设定
// 输出
* 函数执行状态码: osOK、osErrorTimeout、osErrorResource、osErrorParameter

osMessageQueueGetCapacity

uint32_t osMessageQueueGetCapacity(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
*  消息队列所能容纳的最大消息个数

osMessageQueueGetMsgSize

uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
* 消息的最大字节数

osMessageGetCount

uint32_t osMessageQueueGetCount(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
* 压入消息队列的个数

osMessageQueueGetSpace

uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
* 消息队列剩余可压入消息个数

osMessageQueueReset

osStatus_t osMessageQueueReset(osMessageQueueId_t mq_id)
// 输入
* mq_id : 消息队列ID
// 输出
* 函数执行状态: osOK、osErrorTimeout、osErrorResource、osErrorParameter

osMessageQueueDelete

osStatus_t osMessageQueueDelete(osMessageQueueId_t mq_id)
// 输入
* mq_id :消息队列c
// 输出
* 函数执行状态: osOK、osErrorTimeout、osErrorResource、osErrorParameter

使用案例

下面简单介绍使用消息队列的一些基本步骤~

1.首先,需要分配内存资源,建立消息队列属性结构体。

消息队列的属性结构体原型为:

static const osMessageQueueAttr_t  {
     const char *name;   ///< name of the message queue
     uint32_t attr_bits; ///< attribute bits
     void *cb_mem;       ///< memory for control block
     uint32_t cb_size;   ///< size of provided memory for control block
     void *mq_mem;       ///< memory for data storage
     uint32_t mq_size;   ///< size of provided memory for data storage
};

2.创建消息队列

创建消息队列

osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t* attr)

3.放入数据

将数据放入消息队列

osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id,const void* msg_ptr,uint8_t msg_prio,uint32_t timeout)

4.读出数据

将数据从消息队列读出

osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id,void* msg_ptr,uint8_t* msg_prio,uint32_t timeout)

官方案例

#define MSGQUEUE_OBJECTS 16                     // number of Message Queue Objects
typedef struct {                                // object data type
  uint8_t Buf[32];
  uint8_t Idx;
} MSGQUEUE_OBJ_t;
 
osMessageQueueId_t mid_MsgQueue;                // message queue id

mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), NULL);

void Thread_MsgQueue1 (void *argument) {
  MSGQUEUE_OBJ_t msg;
  while (1) {
    ; // Insert thread code here...
    msg.Buf[0] = 0x55U;                                         // do some work...
    msg.Idx    = 0U;
    osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
    osThreadYield();                                            // suspend thread
  }
}
 
void Thread_MsgQueue2 (void *argument) {
  MSGQUEUE_OBJ_t msg;
  osStatus_t status;
  while (1) {
    ; // Insert thread code here...
    status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U);   // wait for message
    if (status == osOK) {
      ; // process data
    }
  }
}

小结

本文主要简要介绍了RTX的消息队列,重点内容如下:

  • 消息队列的概念
  • 消息队列的函数接口
  • 消息队列的使用步骤

本文只是对消息队列的一个粗浅介绍,具体运用到项目中,还是多参考官方资料,好啦,就这么多~

【推荐阅读:☞RTX线程通信之——内存池

参考资料

☞官方入口

以上是关于RTX线程通信之——消息队列的主要内容,如果未能解决你的问题,请参考以下文章

RTX 线程通信之——内存池

RTX 线程通信之——内存池

RTX线程通信之——线程标志

RTX线程通信之——线程标志

RTX线程通信之——线程标志

RTX线程通信之——线程标志