一、消息队列控制块:在include/rtdef.h中

#ifdef RT_USING_MESSAGEQUEUE
/**
* message queue structure
*/
struct rt_messagequeue
{
struct rt_ipc_object parent; /**< inherit from ipc_object */ //继承自IPC对象 void *msg_pool; /**< start address of message queue *///消息队列首地址 rt_uint16_t msg_size; /**< message size of each message */ //每条消息的最大长度
rt_uint16_t max_msgs; /**< max number of messages */ //消息队列最大可容纳的消息条数 rt_uint16_t entry; /**< index of messages in the queue *///当前消息队列中存在的消息条数 void *msg_queue_head; /**< list head */ //队首
void *msg_queue_tail; /**< list tail */ //队尾
void *msg_queue_free; /**< pointer indicated the free node of queue *///指向空闲队列
};
typedef struct rt_messagequeue *rt_mq_t;
#endif

以上是消息队列控制块的定义,那么消息队列内部包含的每条消息元素又是如何定义的呢?在src/ipc.c中定义:

struct rt_mq_message
{
struct rt_mq_message *next;//指向下一条消息元素
};
可能大家会有个疑问,怎么消息元素没有消息的具体数据内容呢?
其实上面这个消息元素只能算作是消息头,就好比短信的标题一般,真正内部跟随在这个消息头后面,一直到下一个消息头之前的所有内存中的数据就是消息的真正内容。rt-thread采用静态队列的方式来实现消息队列的IPC功能的。消息头只是用来做索引功能,通过它可以索引到下一个消息头的位置。如果大家还是有些不明白,那么可以先看看消息队列是如何初始化的,就会明白为什么会有这么一个消息头了。

二、消息队列相关接口:在src/ipc.c中:

创建消息队列:
rt_mq_t rt_mq_create(const char *name, //消息队列的名称
rt_size_t msg_size, //消息队列中每条消息的最大长度
rt_size_t max_msgs, //消息队列的最大容量
rt_uint8_t flag); //消息队列采用的等待方式(FIFO/PRIO)
创建消息队列时先创建一个消息队列对象控制块,然后给消息队列分配一块内存空间,组织成空闲消息链表,这块内存的大小等于[消息大小+消息头(用于链表连接)]与消息队列容量的乘积,接着再初始化消息队列,此时消息队列为空。 删除消息队列:
rt_err_t rt_mq_delete(rt_mq_t mq);
删除消息队列时,如果有线程被挂起在该消息队列等待队列上,则内核先唤醒挂起在该消息等待队列上的所有线程(返回值是 -RT_ERROR),然后再释放消息队列使用的内存,最后删除消息队列对象。
初始化消息队列:
rt_err_t rt_mq_init(rt_mq_t mq, //指向静态消息队列对象的句柄
const char *name, //消息队列的名称
void *msgpool, //用于存放消息的缓冲区首地址
rt_size_t msg_size, //消息队列中每条消息的最大长度
rt_size_t pool_size, //存放消息的缓冲区大小
rt_uint8_t flag); //消息队列采用的等待方式(FIFO/PRIO)
初始化消息队列时,该接口需要获得消息队列对象的句柄(即指向消息队列对象控制块的指针)、消息队列名、消息缓冲区指针、消息大小以及消息队列容量。消息队列初始化后所有消息都挂在空闲消息列表上,消息队列为空。 脱离消息队列:
rt_err_t rt_mq_detach(rt_mq_t mq);
使用该函数接口后,内核先唤醒所有挂在该消息等待队列对象上的线程(返回值是-RT_ERROR ),然后将该消息队列对象从内核对象管理器中删除。
发送消息:
rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size);
线程或者中断服务程序都可以给消息队列发送消息。当发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部。当且仅当空闲消息链表上有可用的空闲消息块时,发送者才能成功发送消息;当空闲消息链表上无可用消息块,说明消息队列已满,此时,发送消息的的线程或者中断程序会收到一个错误码(-RT_EFULL)。
发送消息时,发送者需指定发送到的消息队列的对象句柄(即指向消息队列控制块的指针),并且指定发送的消息内容以及消息大小。在发送一个普通消息之后,从空闲消息链表上取下的队首消息块被转移到了消息队列队尾。 发送紧急消息:
rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size);
发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时,从空闲消息链表上取下来的队首消息块不是挂到消息队列的队尾,而是挂到消息队列的队首,这样接收者就能够优先接收到紧急消息,从而及时进行消息处理。 接收消息:
rt_err_t rt_mq_recv(rt_mq_t mq, //消息队列对象的句柄
void *buffer, //用于接收消息的数据块
rt_size_t size, //消息大小
rt_int32_t timeout); //指定的超时时间
当消息队列中有消息时,接收者才能接收消息,否则接收者会根据超时时间设置或挂起在消息队列的等待线程队列上,或直接返回。
接收消息时,接收者需指定存储消息的消息队列对象句柄,并且指定一个内存缓冲区,接收到的消息内容将被复制到该缓冲区里。此外,还需指定未能及时取到消息时的超时时间。
接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。
控制消息队列:
rt_err_t rt_mq_control(rt_mq_t mq, rt_uint8_t cmd, void *arg);
只支持RT_IPC_CMD_RESET这一条命令,表示复位消息队列。

RT-thread内核之消息队列的更多相关文章

  1. Linux内核情景分析之消息队列

    早期的Unix通信只有管道与信号,管道的缺点: 所载送的信息是无格式的字节流,不知道分界线在哪,也没通信规范,另外缺乏控制手段,比如保温优先级,管道机制的大小只有1页,管道很容易写满而读取没有及时,发 ...

  2. System V 消息队列

    3.1 概述 消息队列结构: struct msqid_ds { struct ipc_perm msg_perm; //权限结构 struct msg *msg_first; //队列中第一个消息 ...

  3. Linux环境进程间通信(三):消息队列

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  4. 四十九、进程间通信——System V IPC 之消息队列

    49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...

  5. IPC 进程间通信方式——消息队列

    消息队列 消息队列是内核中的一个链表 用户进程将数据传输到内核后,内核重新添加一些如用户ID.组ID.读写进程的ID和优先级等相关信息后并打包成一个数据包称为消息 允许一个或多个进程往消息队列中读写消 ...

  6. (转)Linux环境进程间通信----系统 V 消息队列列

    转:http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通 ...

  7. 消息队列内核结构和msgget、msgctl 函数

    一.消息队列 1.消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 2.每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 3.消息队列与管道不同的是,消息队列是基于 ...

  8. μC/OS-III---I笔记9---任务等待多个内核对象和任务内建信号量与消息队列

    在一个任务等待多个内核对象在之前,信号量和消息队列的发布过程中都有等待多个内核对象判断的函数,所谓任务等待多个内核对象顾名思义就是一任务同时等待多个内核对象而被挂起,在USOC-III中一个任务等待多 ...

  9. 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 百篇博客分析OpenHarmony源码 | v33.02

    百篇博客系列篇.本篇为: v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁 ...

随机推荐

  1. 在CentOS7中搭建Zookeeper集群

    前几天装了CentOS7.并安装了一些基本的工具,现在我手上有三台机器:分别是master,slave1,slave2. 今天我将搭建zookeeper,使用的版本是zookeeper-3.4.11. ...

  2. 如何配置 SpaceVim

    本文将系统地介绍如何配置 SpaceVim,配置 SpaceVim 主要包括以下几个内容: 设置 SpaceVim 选项 启动/禁用模块 添加自定义插件 添加自定义按键映射以及插件配置 设置Space ...

  3. GoF设计模式

    GOF23种设计模式简介 GoF(“四人帮”,指Gamma, Helm, Johnson & Vlissides, Addison-Wesley四人)提出的23种设计模式可谓经典,由于其定义比 ...

  4. 使用Unity创建依赖注入

        这篇文章翻译自<Dependency Injection With Unity>第三章.文中提到的类似"前几节"的内容您不必在意,相信您可以看懂的. P.S:如 ...

  5. PLSQL集合类型

    PLSQL集合类型   --联合数组(索引表) /* 用于存储某个数据类型的数据集合类型 .通过索引获得联合数组中得值 如下例子: */ DECLARE CURSOR cur_chars IS SEL ...

  6. 浅析JVM内存区域及垃圾回收

    一.JVM简介 JVM,全称Java Virtual Machine,即Java虚拟机.以Java作为编程语言所编写的应用程序都是运行在JVM上的.JVM是一种用于计算设备的规范,它是一个虚构出来的计 ...

  7. Jenkis 无法下载插件问题解决

    在新机器上安装jenkins后,安装插件报如下错误 sun.security.provider.certpath.SunCertPathBuilderException: unable to find ...

  8. centos 6.5 启动时卡在进度条位置无法进入系统解决办法。

    今天公司服务器因突然断电导致phddns 花生壳 启动失败,一直卡在启动进度条页面. 解决办法 1.按F5查看卡在什么位置, 2.查看解决方法:程序卡住的情况下,直接备份资料后,卸载程序重启就可以了. ...

  9. Linux内核设计笔记12——内存管理

    内存管理学习笔记 页 页是内核管理内存的基本单位,内存管理单元(MMU,管理内存并把虚拟地址转化为物理地址的硬件)通常以页为单位进行处理,从虚拟内存的角度看,页就是最小单位. struct page{ ...

  10. HADOOP docker(六):hive简易使用指南

    前言1.hive简介1.1 hive组件与相应功能:1.2 hive的表类型1.3 分区表1.3 分隔符1.4 hive的数据存储2.数据类型2.1 基本数据类型2.1 复杂数据类型2.3 NULL3 ...