Linux-IPC-消息队列

Linux IPC 之 消息队列(Message Queue)

在 Linux 中,消息队列(Message Queue) 是一种进程间通信(IPC)机制,允许进程通过一个消息队列在内核空间中交换数据。消息队列是基于 队列 数据结构实现的,具有先进先出(FIFO)特性,即最先发送的消息最先被接收。它提供了一种更加灵活的方式,比管道更适合于处理不同类型和不同大小的消息。

  • 其他IPC机制之内存共享见文章Linux IPC 内存共享

消息队列的特点

  1. 先进先出(FIFO):消息队列是按消息到达的顺序进行处理的,保证了顺序性。
  2. 异步通信:进程可以在不阻塞的情况下发送或接收消息。发送消息的进程不会因为目标进程没有及时接收消息而被阻塞(除非队列已满)。接收消息的进程会阻塞,直到队列中有消息可读(也可以通过设置非阻塞模式,避免阻塞行为)。
  3. 可存储多个消息:一个消息队列中可以存储多个消息,进程可以分批读取消息队列中的消息。
  4. 支持消息优先级:消息队列支持消息优先级,允许根据消息的优先级来决定消息的处理顺序。
  5. 可读可写:并不是只能一端读一端写,不过一般设置一端读一端写(看业务需求)。

POSIX 消息队列

POSIX 消息队列的特性

  1. 基于文件系统:POSIX 消息队列通过文件系统接口进行操作。消息队列有一个 名称,类似文件路径,进程通过文件名访问消息队列。这种设计使得 POSIX 消息队列在进程间通信中更加灵活,支持不同进程间通过路径来通信。
  2. 异步操作:POSIX 消息队列是异步的,允许进程以非阻塞模式发送和接收消息。
  3. 优先级:POSIX 消息队列支持设置消息的优先级,允许进程根据优先级来控制消息的处理顺序。
  4. 文件描述符接口:POSIX 消息队列通过文件描述符进行管理,与常规文件操作(如 open()、read()、write())相似

POSIX 消息队列的 API

POSIX 消息队列的 API 主要通过以下几个函数实现:

  1. mq_open():创建或打开消息队列。
  2. mq_send():发送消息到消息队列。
  3. mq_receive():从消息队列接收消息。
  4. mq_close():关闭消息队列。
  5. mq_unlink():删除消息队列。

POSIX 消息队列的操作流程

1. mq_open()

用于创建或打开一个消息队列。它返回一个消息队列的文件描述符,进程通过该文件描述符进行其他操作。

函数原型

mqd_t mq_open(const char *name, int oflag, ...);
  • ...: 可选参数,只有在某些特定的标志(例如 O_CREAT)时才需要。
  • 通常,读取消息的进程会使用 O_RDONLYO_RDONLY | O_NONBLOCK 来打开消息队列,表示它只需要从队列中读取消息。因此,这种进程的 mq_open() 只需要传递 两个参数:
#include <mqueue.h>mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
  • namemq_open 使用的共享内存名称,应当是以 / 开头的 POSIX 名称,会在/dev/mqueue/下创建name不要/的设备文件。
  • oflag:打开标志,如 O_CREAT(创建)、O_RDONLY(只读)、O_WRONLY(只写)、 O_NONBLOCK(非阻塞读)(默认为阻塞)等。
  • mode:消息队列的权限,通常设置为 0666。
  • attr:一个结构体,指定消息队列的属性,如最大消息大小、队列的最大消息数等。
    • 如果不指定mq_attr的话,内核将会使用默认值,特别是mq_msgsize会有默认值(一般是8192),所以接收方一定要设置大于等于这个大小的缓存区去接收信号队列的数据。
    • mq_maxmsg的值设置必须大于0,否则会报错(显然最多为0是无意义的)。
struct mq_attr {long mq_flags;       // 标志,通常为 0long mq_maxmsg;      // 队列中最多消息数long mq_msgsize;     // 每个消息的最大字节数long mq_curmsgs;     // 当前队列中的消息数
};
2. mq_receive()

从消息队列接收消息。

#include <mqueue.h>ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
  • mqdes:消息队列的文件描述符。
  • msg_ptr:接收消息内容的缓冲区。
  • msg_len:缓冲区的大小。
  • msg_prio:接收的消息优先级。
3. mq_send()

向消息队列发送消息。

#include <mqueue.h>int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
  • mqdes:消息队列的文件描述符。
  • msg_ptr:指向要发送的消息内容的指针。
  • msg_len:消息的长度。
  • msg_prio:消息的优先级,值越大优先级越高,排在消息队列最前
4. mq_close()

关闭消息队列的文件描述符,类似于关闭文件。

#include <mqueue.h>int mq_close(mqd_t mqdes);
  • mqdes:消息队列的文件描述符。
  • 打开引用计数++
5. mq_unlink()

删除消息队列。这通常是在消息队列不再使用时调用,用于清理资源。

#include <mqueue.h>int mq_unlink(const char *name);
  • name:要删除的消息队列的名称。

  • mq_unlink 是用于删除 POSIX 消息队列对象的系统调用。它的作用是 从系统中删除消息队列存对象的名称,使得它在 mq_open 中不可见(在/dev/mqueue/目录下将不会有对应的消息队列文件),但不会立即销毁消息队列,直到所有进程关闭该消息队列对象后,系统才会回收它

  • 不会立即删除消息队列的实际数据,如果有进程仍然持有文件描述符或映射该消息队列,则消息队列仍然存在,直到所有引用(文件描述符)都被mq_unlinkmq_close() 释放。

  • namemq_open 使用的共享内存名称,应当是以 / 开头的 POSIX 名称,会在/dev/mqueue/下创建name不要/的设备文件。

  • 可以查看消息队列的信息

    • ls -l /dev/mqueue/<name>
    • stat /dev/mqueue/<name>
  • 强制删除 POSIX 消息队列

    • rm /dev/mqueue/<name>

接口详细说明

oflag
标志描述
O_RDONLY只读打开消息队列对象,如果消息队列对象不存在报错
O_WRONLY只读模式打开消息队列对象,如果消息队列对象不存在报错
O_CREAT如果消息队列对象不存在,则创建,若对象已存在,仍会成功返回文件描述符
O_EXCLO_CREAT 一起使用,若对象已存在,则返回错误
O_NONBLOCK打开消息队列时,设置为非阻塞模式。如果消息队列为空,mq_receive()mq_send() 会立即返回,而不会阻塞。
O_RDWR打开消息队列进行读写操作。,如果消息队列对象不存在报错
mode

mq_open 中的 mode 参数

  • mq_openmode 参数用于指定消息队列对象的访问权限,其语义与 open 系统调用的 mode 参数相同。它仅在 O_CREAT 标志被使用时才生效,否则会被忽略。
  1. mode常见权限
模式(宏)数值(八进制描述
S_IRUSR0400用户可读
S_IWUSR0200用户可写
S_IRGRP0040组可读
S_IWGRP0020组可写
S_IROTH0004其他用户可读
S_IWOTH0002其他用户可写
  1. mode 组合方式

可以通过 按位或 (|) 运算符 组合多个权限。例如:

  • 0666(所有用户可读写):
mq_open("/my_queue", O_CREAT | O_RDWR, 0666, NULL);

等价于:

mq_open("/my_queue", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, NULL);

POSIX 消息队列代码示例

进程 A(写入消息队列)
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>#define QUEUE_NAME "/my_queue"int main() {mqd_t mq;struct mq_attr attr;char *msg = "Hello 1 from Process A by message queue !";char *msg2 = "Hello 2 from Process A by message queue !";unsigned int prio = 1;attr.mq_flags = 0;attr.mq_maxmsg = 10;attr.mq_curmsgs = 0;attr.mq_msgsize = strlen(msg) > strlen(msg2) ? strlen(msg) + 1 : strlen(msg2) + 1;// 打开或创建消息队列// 如果在attr参数填NULL,则系统会给默认值mq = mq_open(QUEUE_NAME, O_WRONLY | O_CREAT, 0666, &attr);if (mq == (mqd_t) -1) {perror("mq_open");exit(1);}// 发送消息,优先级为2if (mq_send(mq, msg, strlen(msg) + 1, 2) == -1) {perror("mq_send");exit(1);}printf("Message sent: %s\n", msg);// 发送消息,优先级为7,优先级越大越高,排在消息队列最前if (mq_send(mq, msg, strlen(msg2) + 1, 7) == -1) {perror("mq_send");exit(1);}printf("Message sent: %s\n", msg2);// 关闭消息队列mq_close(mq);// mq_unlink(QUEUE_NAME);return 0;
}
进程 2(读取消息队列)
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>#define QUEUE_NAME "/my_queue"int main() {mqd_t mq;char buffer[1024];unsigned int prio;// 打开消息队列mq = mq_open(QUEUE_NAME, O_RDONLY, 0666, NULL);if (mq == (mqd_t) -1) {perror("mq_open");exit(1);}// 接收消息,并获取消息优先级(数字越大优先级越高)if (mq_receive(mq, buffer, sizeof(buffer), &prio) == -1) {perror("mq_receive");exit(1);}printf("Message received: %s\n", buffer);printf("Message priority: %u\n", prio);// 关闭消息队列mq_close(mq);// mq_unlink(QUEUE_NAME);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/24883.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI开放Deep Research权限,AI智能体大战升级,DeepSeek与Claude迎来新对决

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

个人电脑小参数GPT预训练、SFT、RLHF、蒸馏、CoT、Lora过程实践——MiniMind图文版教程

最近看到Github上开源了一个小模型的repo&#xff0c;是真正拉低LLM的学习门槛&#xff0c;让每个人都能从理解每一行代码&#xff0c; 从零开始亲手训练一个极小的语言模型。开源地址&#xff1a; GitHub - jingyaogong/minimind: &#x1f680;&#x1f680; 「大模型」2小时…

【数据结构】顺序表和链表

线性表 线性表 (linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串 ….. 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时…

一文讲解Redis的内存淘汰和过期策略

Redis 报内存不足怎么处理&#xff1f; Redis 内存不足有这么几种处理方式&#xff1a; 修改配置文件 redis.conf 的 maxmemory 参数&#xff0c;增加 Redis 可用内存 也可以通过命令 set maxmemory 动态设置内存上限 修改内存淘汰策略&#xff0c;及时释放内存空间 使用 R…

游戏引擎学习第125天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾并为今天的内容做准备。 昨天&#xff0c;当我们离开时&#xff0c;工作队列已经完成了基本的功能。这个队列虽然简单&#xff0c;但它能够执行任务&#xff0c;并且我们已经为各种操作编写了测试。字符串也能够正常推送到队…

【UCB CS 61B SP24】Lecture 16 - Data Structures 2: ADTs, BSTs学习笔记

本文首先介绍了抽象数据类型与树的概念&#xff0c;接着重点讲解二叉搜索树的定义与操作方式&#xff0c;并用 Java 实现一个标准的二叉搜索树结构。 1. 抽象数据类型 首先引入一个概念叫做抽象数据类型&#xff08;Abstract Data Type&#xff0c;ADT&#xff09;&#xff0…

包子凑数——蓝桥杯真题Python

包子凑数 输入输出样例 示例 1 输入 2 4 5输出 6样例说明 凑不出的数目包括&#xff1a;1, 2, 3, 6, 7, 11。 示例 2 输入 2 4 6输出 INF样例说明 所有奇数都凑不出来&#xff0c;所以有无限多个 运行限制 最大运行时间&#xff1a;1s最大运行内存: 256M 最大公约数 最大公…

一周学会Flask3 Python Web开发-Jinja2模版中加载静态文件

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 一个Web项目不仅需要HTML模板&#xff0c;还需要许多静态文件&#xff0c;比如 CSS、JavaScript文件、图片以及音频等。在Fla…

Python的那些事第三十二篇:用于创建静态、动画和交互式可视化的绘图库Matplotlib

Matplotlib:用于创建静态、动画和交互式可视化的绘图库 摘要 Matplotlib 是一个广泛使用的 Python 绘图库,能够创建静态、动画和交互式可视化图表。本文首先介绍了 Matplotlib 的基本功能和架构,然后通过具体的示例代码展示了如何使用 Matplotlib 创建不同类型的图表。接着…

tableau之雷达图和凹凸图

一、雷达图 概念 雷达图&#xff08;Radar Chart&#xff09;&#xff0c;也称为蜘蛛网图&#xff08;Spider Chart&#xff09;或星状图&#xff08;Star Chart&#xff09;&#xff0c;是一种用于多变量数据可视化的图表。它以中心点向外辐射的轴线表示不同的变量&#xff…

Redis-列表结构实操

列表实操 前言简单练习基本的LPUSH和RPUSH操作列表元素的访问与修改列表元素的插入和删除列表阻塞操作 困难练习分页列表游标机制业务上考虑直接访问任意页如何高效分页局限性小结 实现限时排行版轮换消息队列可靠性实现分布式锁实现 总结 前言 之前总结过-列表的数据结构,但是…

SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)

目录 一、环境准备 二、新建项目 三、整合依赖 1、MyBatis Plus 数据库操作 2、Hutool 工具库 3、Knife4j 接口文档 4、其他依赖 四、通用基础代码 1、自定义异常 2、响应包装类 3、全局异常处理器 4、请求包装类 5、全局跨域配置 补充&#xff1a;设置新建类/接…

实现Python+Django+Transformers库中的BertTokenizer和BertModel来进行BERT预训练,并将其应用于商品推荐功能

一、环境安装准备 #git拉取 bert-base-chinese 文件#创建 虚拟运行环境python -m venv myicrplatenv#刷新source myicrplatenv/bin/activate#python Django 集成nacospip install nacos-sdk-python#安装 Djangopip3 install Django5.1#安装 pymysql settings.py 里面需要 # 强制…

Rk3568驱动开发_点亮led灯代码完善(手动挡)_6

1.实现思路&#xff1a; 应用层打开设备后通过write函数向内核中写值&#xff0c;1代表要打开灯&#xff0c;0代表要关闭灯 Linux配置gpio和控制gpio多了一个虚拟内存映射操作 2.注意事项&#xff1a; 配置和读写操作的时候要谨慎&#xff0c;比如先关掉gpio再注销掉虚拟内存…

线性回归(一)基于Scikit-Learn的简单线性回归

主要参考学习资料&#xff1a; 《机器学习算法的数学解析与Python实现》莫凡 著 前置知识&#xff1a;线性代数-Python 目录 问题背景数学模型假设函数损失函数优化方法训练步骤 代码实现特点 问题背景 回归问题是一类预测连续值的问题&#xff0c;满足这样要求的数学模型称作…

P10108 [GESP202312 六级] 闯关游戏

题目大意 如题 分析 设最佳通关方案为 { s 1 , s 2 , . . . , s k } \{s_1,s_2,...,s_k\} {s1​,s2​,...,sk​}&#xff0c;其中 s i s_i si​ 代表第 i i i 次到达的关卡&#xff08; ≥ N \ge N ≥N 的不算&#xff09;。 当 a k N − 1 a_kN-1 ak​N−1 时&#…

vllm的使用方式,入门教程

vLLM是一个由伯克利大学LMSYS组织开源的大语言模型推理框架&#xff0c;旨在提升实时场景下的大语言模型服务的吞吐与内存使用效率。以下是详细的vLLM使用方式和入门教程&#xff1a; 1. 前期准备 在开始使用vLLM之前&#xff0c;建议先掌握一些基础知识&#xff0c;包括操作…

web的分离不分离:前后端分离与不分离全面分析

让我们一起走向未来 &#x1f393;作者简介&#xff1a;全栈领域优质创作者 &#x1f310;个人主页&#xff1a;百锦再新空间代码工作室 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[1504566…

HDFS扩缩容及数据迁移

1.黑白名单机制 在HDFS中可以通过黑名单、白名单机制进行节点管理&#xff0c;决定数据可以复制/不可以复制到哪些节点。 黑名单通常是指在HDFS中被标记为不可用或不可访问的节点列表&#xff0c;这些节点可能由于硬件故障、网络问题或其他原因而暂时或永久性地无法使用。当一…

数据如何安全“过桥”?分类分级与风险评估,守护数据流通安全

信息化高速发展&#xff0c;数据已成为企业的核心资产&#xff0c;驱动着业务决策、创新与市场竞争力。随着数据开发利用不断深入&#xff0c;常态化的数据流通不仅促进了信息的快速传递与共享&#xff0c;还能帮助企业快速响应市场变化&#xff0c;把握商业机遇&#xff0c;实…