Posix消息队列使用总结

news2024/7/6 20:37:57

Posix在线文档:

The Single UNIX Specification, Version 2 (opengroup.org)

Linux系统中提供了两种不同接口的消息队列:

  1. POSIX消息队列。POSIX为可移植的操作系统接口。
  2. System V消息队列。System V 是 AT&T 的第一个商业UNIX版本(UNIX System III)的加强。

其中,POSIX消息队列可移植性较强,使用较广。

Linux系统中提供的消息队列一般应用于进行间通信,但也可以用于线程间通信。

本文介绍POSIX消息队列应用于线程间通信。

相关API

Linux内核提供了一系列函数来使用消息队列:

/**
 * @brief 创建消息队列实例
 *
 * Detailed function description
 *
 * @param[in] name: 消息队列名称
 * @param[in] oflag:根据传入标识来创建或者打开一个已创建的消息队列
                    - O_CREAT: 创建一个消息队列
                    - O_EXCL: 检查消息队列是否存在,一般与O_CREAT一起使用
                    - O_CREAT|O_EXCL: 消息队列不存在则创建,已存在返回NULL
                    - O_NONBLOCK: 非阻塞模式打开,消息队列不存在返回NULL
                    - O_RDONLY: 只读模式打开
                    - O_WRONLY: 只写模式打开
                    - O_RDWR: 读写模式打开
 * @param[in] mode:访问权限
 * @param[in] attr:消息队列属性地址
 *
 * @return 成功返回消息队列描述符,失败返回-1,错误码存于error中
 */
mqd_t mq_open(const char *name, int oflag,  mode_t mode, struct mq_attr *attr);

/**
 * @brief 无限阻塞方式接收消息
 *
 * Detailed function description
 *
 * @param[in] mqdes: 消息队列描述符
 * @param[in] msg_ptr:消息体缓冲区地址
 * @param[in] msg_len:消息体长度,长度必须大于等于消息属性设定的最大值
 * @param[in] msg_prio:消息优先级
 *
 * @return 成功返回消息长度,失败返回-1,错误码存于error中
 */
mqd_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);

/**
 * @brief 指定超时时间阻塞方式接收消息
 *
 * Detailed function description
 *
 * @param[in] mqdes: 消息队列描述符
 * @param[in] msg_ptr:消息体缓冲区地址
 * @param[in] msg_len:消息体长度,长度必须大于等于消息属性设定的最大值
 * @param[in] msg_prio:消息优先级
 * @param[in] abs_timeout:超时时间
 *
 * @return 成功返回消息长度,失败返回-1,错误码存于error中
 */
mqd_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout);

/**
 * @brief 无限阻塞方式发送消息
 *
 * Detailed function description
 *
 * @param[in] mqdes: 消息队列描述符
 * @param[in] msg_ptr:待发送消息体缓冲区地址
 * @param[in] msg_len:消息体长度
 * @param[in] msg_prio:消息优先级
 *
 * @return 成功返回0,失败返回-1
 */
mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);

/**
 * @brief 指定超时时间阻塞方式发送消息
 *
 * Detailed function description
 *
 * @param[in] mqdes: 消息队列描述符
 * @param[in] msg_ptr:待发送消息体缓冲区地址
 * @param[in] msg_len:消息体长度
 * @param[in] msg_prio:消息优先级
 * @param[in] abs_timeout:超时时间
 *
 * @return 成功返回0,失败返回-1
 */
mqd_t mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout);

/**
 * @brief 关闭消息队列
 *
 * Detailed function description
 *
 * @param[in] mqdes: 消息队列描述符
 *
 * @return 成功返回0,失败返回-1
 */
mqd_t mq_close(mqd_t mqdes);

/**
 * @brief 分离消息队列
 *
 * Detailed function description
 *
 * @param[in] name: 消息队列名称
 *
 * @return 成功返回0,失败返回-1
 */
mqd_t mq_unlink(const char *name);

消息队列的名称类似于设备文件,mq_open通过名称打开对应的消息队列,然后返回一个消息队列描述符,之后的操作都是引用返回的描述符,类似于打开文件时返回的文件描述符。

其实和文件的打开、读写、关闭都非常类似。

​POSIX消息队列允许进程以消息的形式交换数据。 消息队列是使用mq_open创建和打开的;此函数返回消息队列描述符(mqd_t),该描述符用于在以后的调用中引用打开的消息队列。每个消息队列由/somename形式的名称标识,该名称由一个初始斜杠组成,后跟一个或多个字符(都不是斜杠)。通过将相同的名称传递给mq_open,两个进程可以在同一队列上进行操作。 使用mq_send和mq_receive在队列之间来回传送消息。当进程使用完队列后,可以使用mq_close关闭该队列,而当不再需要该队列时,可以使用mq_unlink将其删除。可以使用mq_getattr和mq_setattr检索和修改队列属性(在某些情况下)。进程可以使用mq_notify请求异步通知消息到达先前为空的队列。 ​

消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。

几个主要函数可进一步参考:

mq_open

MQ_OPEN - Linux手册页-之路教程 (onitroad.com)

mq_send

MQ_SEND - Linux手册页-之路教程 (onitroad.com)

mq_receive

MQ_RECEIVE - Linux手册页-之路教程 (onitroad.com)

mq_close

MQ_CLOSE - Linux手册页-之路教程 (onitroad.com)

相关头文件如下:

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

注意事项

参考:

POSIX 消息队列函数(mq_open、mq_getattr、mq_send、mq_receive)示例_mqreceivetest-CSDN博客

关于消息队列mq_open的属性参数

指向attr的struct mq_attr字段指定队列允许的最大消息数和最大消息大小。此结构定义如下:

struct mq_attr {

    long mq_flags;       /* Flags (ignored for mq_open()) */

    long mq_maxmsg;      /* Max. # of messages on queue */

    long mq_msgsize;     /* Max. message size (bytes) */

    long mq_curmsgs;     /* # of messages currently in queue(ignored for mq_open()) */

};

mq_maxmsg指的是容纳的消息数也就是消息队列的缓冲大小,msgsize指的是每个消息的大小;mq_maxmsg貌似并没有那么重要,因为消息队列是以流的形式来发送和接收的。两个参数的乘积,就是消息队列的总容量。

调用mq_open()时仅使用mq_maxmsg和mq_msgsize字段;其余字段中的值将被忽略。

如果attr为NULL,则使用默认属性创建队列。

关于消息队列名称

资料中说消息队列名称要写斜杠/开头,但是我看有的程序里并没有,而是一个单纯的字符串,为啥?

经过测试,在Linux 2.6.18中,所创建的POSIX消息队列不会在文件系统中创建真正的路径名。且POSIX的名字只能以一个’/’开头,名字中不能包含其他的’/’。

比如,不符合的情况:


报错

对应的错误如下:

另外需要注意以下几点:

1、

mq_receive() 的第三个参数表示读取消息的长度,不能小于能写入队列中消息的最大大小,即一定要大于等于该队列的 mq_attr 结构中 mq_msgsize 的大小。也就是最少要读一个消息。

2、

消息的优先级:它是一个小于 MQ_PRIO_MAX 的数,数值越大,优先级越高。 POSIX 消息队列在调用 mq_receive 时总是返回队列中最高优先级的最早消息。如果消息不需要设定优先级,那么可以在 mq_send 是置 msg_prio 为 0, mq_receive 的 msg_prio 置为 NULL。因为mq_send的优先级是以变量的形式传递的,而mq_receive是以指针的形式传递的。

3、

默认情况下mq_send和mq_receive是阻塞进行调用,可以通过mq_setattr来设置为O_NONBLOCK,如:

struct mq_attr new_attr;

mq_getattr(mqID, &new_attr);//获取当前属性

new_attr.mq_flags = O_NONBLOCK;//设置为非阻塞

mq_setattr(mqID, &new_attr, NULL)//设置属性

4、

mq_getattr用于获取当前消息队列的属性,mq_setattr用于设置当前消息队列的属性。其中mq_setattr中的oldattr用于保存修改前的消息队列的属性,可以为空。

mq_setattr可以设置的属性只有mq_flags,用来设置或清除消息队列的非阻塞标志。newattr结构的其他属性被忽略。mq_maxmsg和mq_msgsize属性只能在创建消息队列时通过mq_open来设置。mq_open只会设置该两个属性,忽略另外两个属性。mq_curmsgs属性只能被获取而不能被设置。

5、

mq_send和mq_recevie的第二个参数,也就是数据指针,是char *类型的,需要时做个强转。

6、

使用POSIX消息队列API的程序必须使用cc -lrt进行编译,以链接到实时库librt。

gcc pthread_5.c -o obj -lpthread -lrt

Linux编译命令-pthread & -lpthread - 邗影 - 博客园 (cnblogs.com)

linux的各种自带库-lz -lrt -lm -lc都是什么库_lm是什么库-CSDN博客

7、

消息队列无需init初始化,只用在第一次mq_open打开时创建即可。

8、

Posix消息队列就是先进先出,但是可以通过优先级来让紧急数据插队。

使用示例

常规示例代码如下: 

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>
#include <errno.h>

#define MQ_NAME "/thisIsOneMqName"

static void *thread_fun1(void *param)
{
    mqd_t mqfd;
    struct mq_attr attr;
    int count;

    attr.mq_maxmsg = 1;
    attr.mq_msgsize = sizeof(int);

    mqfd = mq_open(MQ_NAME, O_WRONLY | O_CREAT, 0666, &attr);
    if(mqfd < 0)
    {
        printf("mq_open errno is %d\n", errno);
        exit(-1);
    }

    while(1)
    {
        count += 10;
        mq_send(mqfd, (char *)&count, sizeof(int), 0);
    }
    
    return NULL;
}

static void *thread_fun2(void *param)
{
    mqd_t mqfd;
    int count;

    mqfd = mq_open(MQ_NAME, O_RDONLY);
    if(mqfd < 0)
    {
        printf("mq_open errno is %d\n", errno);
        exit(-1);
    }

    while(1)
    {
        mq_receive(mqfd, (char *)&count, sizeof(int), NULL);
        printf("count is %d\n", count);
        if(count == 100)
        {
            exit(0);
        }
    }
    
    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    int ret;

    ret = pthread_create(&tid1, NULL, thread_fun1, NULL);
    if (ret < 0)
    {
         printf("ERROR; return code from pthread_create() is %d\n", ret);
         exit(-1);
    }

    ret = pthread_create(&tid2, NULL, thread_fun2, NULL);
    if (ret < 0)
    {
         printf("ERROR; return code from pthread_create() is %d\n", ret);
         exit(-1);
    }

    pthread_exit(NULL);
}

更多待补充

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Mac】iTerm for mac(终端工具)软件介绍及安装教程

软件介绍 iTerm 是 macOS 上一个非常受欢迎的终端仿真器&#xff0c;提供了比默认的 Terminal 应用更多的功能和定制选项。它是一款开源软件&#xff0c;主要用于命令行界面的操作和开发者工具。 主要特点和功能&#xff1a; 分页和标签&#xff1a; iTerm 允许用户在单个窗…

Spring Boot项目的两种发布方式

5.1.方式1&#xff1a;通过jar包发布 步骤1&#xff1a;在pom中添加一个SpringBoot的构建的插件 <build><plugins><plugin><groupId>org.springframework.boot</groupId><!--自动检测项目中的 main 函数--><artifactId>spring-boot…

开发一款直播APP完整指南

直播是一种强大的营销工具&#xff0c;可以让企业与观众进行真实的互动。 根据Grand View Research发布的预测&#xff0c;直播行业规模将从 2021 年的 700 亿美元增长到 2028 年的近 2240 亿美元&#xff0c;七年内增长三倍。 区块链技术和人工智能等技术进步将在未来几年提…

mybatis-plus 实体中空字段更新不上

FieldStrategy 是一个枚举类型&#xff0c;它定义了字段的几种策略&#xff1a; IGNORED&#xff1a;忽略判断&#xff0c;所有字段都进行更新操作 NOT_NULL&#xff1a;非 NULL 判断&#xff08;默认策略&#xff09;&#xff0c;字段非 NULL 才进行更新 NOT_EMPTY&#xff…

数据结构与算法—空间复杂度详解与示例(C#,C++)

文章目录 1. 数据结构概述2. 空间复杂度的定义及影响因素3. 空间复杂度的区分常数空间复杂度&#xff08;O(1)&#xff09;线性空间复杂度&#xff08;O(n)&#xff09;其他空间复杂度 4. 几种典型数据结构的优缺点分析数组&#xff08;Array&#xff09;链表&#xff08;Linke…

专业解析U盘数据恢复:方法、方案与常见问答

一、U盘数据恢复概述 在信息化社会&#xff0c;U盘作为一种便捷的数据存储介质&#xff0c;广泛应用于各种场合。然而&#xff0c;由于其体积小、易携带的特点&#xff0c;U盘数据丢失的风险也随之增加。U盘数据恢复&#xff0c;即是指通过技术手段&#xff0c;将因各种原因导…

【Spine学习16】之 人物面部绑定

1、创建头部骨骼 一根头骨 以头骨为父结点创建一个面部控制器face-holder 2、创建头发和face面部控制结点的变换约束 左右头发的约束指向为face结点 3、设定后发的变换约束&#xff0c;约束指向为face结点&#xff0c;反方向移动 设置参数为-100 同理&#xff0c;耳朵也依…

pytest测试框架pytest-html插件生成HTML格式测试报告

Pytest提供了丰富的插件来扩展其功能&#xff0c;pytest-html插件帮助我们生成HTML格式的测试报告&#xff0c;为我们提供直观、有效的测试结果展示。 为了使用 pytest-html&#xff0c;需要满足以下条件&#xff1a; Python 3.6 或更高版本 pytest-html安装 使用pip命令安…

Kubernetes Prometheus 系例 | kubernetes 部署 Kafka exporter监控Kafka集群

prometheus 监控 kafka 常见的有两种开源方案&#xff1b; 部署 exporter 或 jmx 配置监控。 项目地址&#xff1a; kafka_exporter&#xff1a;https://github.com/danielqsj/kafka_exporter jmx_exporter&#xff1a;https://github.com/prometheus/jmx_exporter 本文采用kaf…

Java宝藏实验资源库(5)字符流

一、实验目的 掌握输入输出流的基本概念。掌握字符流处理类的基本结构。掌握使用字符流进行输入输出的基本方法。 二、实验内容、过程及结果 **12.12 (Reformat Java source code) Write a program that converts the Java source code from the next-line brace style to…

Reactor模型:网络线程模型演进

一&#xff0c;阻塞IO线程池模型&#xff08;BIO&#xff09; 这是传统的网络编程方案所采用的线程模型。 即有一个主循环&#xff0c;socket.accept阻塞等待&#xff0c;当建立连接后&#xff0c;创建新的线程/从线程池中取一个&#xff0c;把该socket连接交由新线程全权处理。…

HarmonyOS NEXT Developer Beta1配套相关说明

一、版本概述 2024华为开发者大会&#xff0c;HarmonyOS NEXT终于在万千开发者的期待下从幕后走向台前。 HarmonyOS NEXT采用全新升级的系统架构&#xff0c;贯穿HarmonyOS全场景体验的底层优化&#xff0c;系统更流畅&#xff0c;隐私安全能力更强大&#xff0c;将给您带来更高…

qmt量化交易策略小白学习笔记第44期【qmt编程之期货行情数据】

qmt编程之获取期货行情数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 获取行情数据 提示 使用该接口时&#xff0c;需要先订阅实时行情(subscribe_quote)或下载过历史行情(download_hi…

WEB界面上使用ChatGPT

&#xff08;作者&#xff1a;陈玓玏&#xff09; 开源项目&#xff0c;欢迎star哦&#xff0c;https://github.com/tencentmusic/cube-studio 随着大模型不断发展&#xff0c;现在无论写代码&#xff0c;做设计&#xff0c;甚至老师备课、评卷都可以通过AI大模型来实现了&…

5分钟带你部署一套Jenkins持续集成环境​

5分钟带你部署一套Jenkins持续集成环境 Jenkins是开源CI&CD软件领导者&#xff0c; 提供超过1000个插件来支持构建、部署、自动化&#xff0c; 满足任何项目的需要。 Jenkins的优点 持续集成和持续交付 作为一个可扩展的自动化服务器&#xff0c;Jenkins 可以用作简单的 CI…

【分布式文件系统HDFS】API 编程基础

目录 一、使用 HDFS API 完成以下程序设计并运行 1. 将 HDFS 文件系统目录/user/账户名下的文件 test1.txt 下载至本地文件系统目录/home/账户名/Desktop 下。 1.1 程序代码 1.2 运行截图 1.3 查看本地的test1.txt文件 2. 在 HDFS 文件系统上创建目录/test1 2.1 程序代码…

230个大模型招投标大单,前三令人意外

大模型市场争夺白热化&#xff0c;前三的座次每个月都在变。 2024年被认为是大模型的应用落地元年&#xff0c;大模型落地的进展一直备受瞩目&#xff0c;而大模型招投标信息被认为是其中的风向标。最近&#xff0c;数智前线通过中国政府采购网、中国招投标公共服务平台、天眼…

PS系统教程27

Photoshop与Camera Raw Camera本身是作为插件存在的&#xff0c;处理对象Raw格式&#xff08;高清格式的图片标准&#xff09; JPG是压缩格式 Camera是源数据包&#xff0c;无损高清数据包 通道 通道只有黑白灰三种颜色&#xff0c;图层类似于前台&#xff0c;通道就是后台…

Unity海面效果——2、菲涅尔水的介绍

Unity引擎制作海面效果 大家好&#xff0c;我是阿赵。 这一篇是说一下菲涅尔水的基本原理。 延续之前的例子&#xff0c;我场景里面有天空盒、小岛和水面。 一、菲涅尔反射原理介绍 从摄像机的角度看去&#xff0c;看不同的海面的点&#xff0c;摄像机和海面形成的夹角会发生变…

electron-builder 打包过慢解决

报错内容如下 > 6-241.0.0 build > electron-builder • electron-builder version24.13.3 os10.0.22631 • loaded configuration filepackage.json ("build" field) • writing effective config filedist\builder-effective-config.yaml • pack…