RT-thread内核之消息队列
一、消息队列控制块:在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内核之消息队列的更多相关文章
- Linux内核情景分析之消息队列
早期的Unix通信只有管道与信号,管道的缺点: 所载送的信息是无格式的字节流,不知道分界线在哪,也没通信规范,另外缺乏控制手段,比如保温优先级,管道机制的大小只有1页,管道很容易写满而读取没有及时,发 ...
- System V 消息队列
3.1 概述 消息队列结构: struct msqid_ds { struct ipc_perm msg_perm; //权限结构 struct msg *msg_first; //队列中第一个消息 ...
- Linux环境进程间通信(三):消息队列
linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...
- 四十九、进程间通信——System V IPC 之消息队列
49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...
- IPC 进程间通信方式——消息队列
消息队列 消息队列是内核中的一个链表 用户进程将数据传输到内核后,内核重新添加一些如用户ID.组ID.读写进程的ID和优先级等相关信息后并打包成一个数据包称为消息 允许一个或多个进程往消息队列中读写消 ...
- (转)Linux环境进程间通信----系统 V 消息队列列
转:http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通 ...
- 消息队列内核结构和msgget、msgctl 函数
一.消息队列 1.消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 2.每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 3.消息队列与管道不同的是,消息队列是基于 ...
- μC/OS-III---I笔记9---任务等待多个内核对象和任务内建信号量与消息队列
在一个任务等待多个内核对象在之前,信号量和消息队列的发布过程中都有等待多个内核对象判断的函数,所谓任务等待多个内核对象顾名思义就是一任务同时等待多个内核对象而被挂起,在USOC-III中一个任务等待多 ...
- 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 百篇博客分析OpenHarmony源码 | v33.02
百篇博客系列篇.本篇为: v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁 ...
随机推荐
- 在vue项目中添加eslint规则
自己配置脚手架时候如何安装eslint语法规则, 第一步安装 官方推荐的安装包如下 eslint eslint-config-standard eslint-plugin-standard eslin ...
- Tomcat7 调优及 JVM 参数优化
Tomcat 的缺省配置是不能稳定长期运行的,也就是不适合生产环境,它会死机,让你不断重新启动,甚至在午夜时分唤醒你.对于操作系统优化来说,是尽可能的增大可使用的内存容量.提高CPU 的频率,保证 ...
- Java设计模式(4)——创建型模式之单例模式(Singleton)
一.概述 弥补一下之前没有给设计模式下的定义,先介绍一下设计模式(引用自百度百科): 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计 ...
- 20145209 2016-2017-2 《Java程序设计》第9周学习总结
20145209 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 JDBC简介 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找 JDBC ...
- 20145234黄斐《Java程序设计》第三周学习总结
教材学习内容总结 类与对象 定义:对象,与过程相对. Java中变量有2种类型,一个是基本类型,另一个则是类类型.基本类型在之前学过,本次学习类类型.使用Java撰写程序几乎都是在使用对象,要产生对象 ...
- python的bif介绍
Python是面向对象的解释性程序设计语言,Python的语法简洁,特点是用空白符作为语句缩进. BIF(bulit in function)内置函数,就是Python自身提供的函数功能,编程者直接使 ...
- Hive窗口函数之LAG、LEAD、FIRST_VALUE、LAST_VALUE的用法
一.创建表: create table windows_ss ( polno string, eff_date string, userno string ) ROW FORMAT DELIMITED ...
- Python-内置函数3
'''1.lambda 声明一个匿名函数,并且自动给你返回值2.map()3.float()4.globals()5.locals()6.input()7.print()8.int()9.int()1 ...
- YUM本地源制作与yum网络版仓库
1.修改本机上的YUM源配置文件,将源指向自己 cd /etc/yum.repos.d/ 备份原有的YUM源的配置文件 rename .repo .repo.bak * rename CentOS-M ...
- Qt-QML-Repeater-导航条
上篇文章中,我写了一个自己的Button,也就是美化了一下QML自带的Button 就是上面的这个,剩下的就是放三张图片在上面就可以了,当然了,这个Button在后期,还是会加入更让多的美化,比如,可 ...