Linux POSIX消息队列遇到的问题和使用方法

目录

  • 一、开发环境及消息队列介绍
  • 二、问题描述
  • 三、解决办法
  • 四、测试代码

一、开发环境及消息队列介绍

开发板:nuc980

1.ARM Linux中消息队列的原理
  在ARM Linux中,消息队列是通过POSIX(Portable Operating System Interface)标准实现的。消息队列在内核中维护,通过文件系统(如/dev/mqueue)或系统调用来访问。
消息队列具有以下几个主要特点
异步通信:发送进程和接收进程不需要同时处于活动状态。发送进程可以将消息放入队列,然后继续进行其他操作;接收进程可以在需要时从队列中取出消息。
消息独立性:队列中的每个消息都是独立的,拥有自己的属性和内容。
顺序性:消息队列保证消息按照发送的顺序被接收。

2.在ARM Linux中,使用消息队列通常涉及以下步骤
定义消息队列和消息结构体:需要定义消息队列的名字和消息的结构体。
创建或打开消息队列:使用mq_open函数创建或打开一个已存在的消息队列。该函数返回一个消息队列描述符,用于后续的读写操作。
发送消息:使用mq_send函数将消息发送到消息队列。该函数需要指定消息队列描述符、要发送的消息以及消息的属性(如优先级)。
接收消息:使用mq_receive函数从消息队列中接收消息。该函数需要指定消息队列描述符以及用于存储接收到的消息的缓冲区。
关闭消息队列:使用mq_close函数关闭已打开的消息队列描述符。
删除消息队列:如果不再需要消息队列,可以使用mq_unlink函数将其从文件系统中删除。
ARM Linux中消息队列的应用

3.消息队列在ARM Linux嵌入式系统中具有广泛的应用场景
多任务协同:在嵌入式系统中,经常需要多个任务协同工作。消息队列提供了一种方便的任务间通信方式,使得任务之间可以相互传递数据和控制信息。
数据采集与处理:在数据采集系统中,消息队列可以用于存储从传感器或其他数据源获取的数据。处理任务可以从队列中取出数据进行处理,实现数据的实时处理和分析。
实时通信:在需要实时通信的嵌入式系统中,消息队列可以确保消息的可靠传输和顺序接收。这对于需要保证数据一致性和可靠性的应用至关重要。

二、问题描述

使用了Linux POSIX消息队列用于线程间通信,启动程序报错-mq_open error: Function not implemented

mq_open error: Function not implemented

三、解决办法

内核开启POSIX消息队列的支持
在这里插入图片描述

四、测试代码

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <sys/stat.h>  
#include <mqueue.h>  
#include <pthread.h>  
#include <errno.h>#define QUEUE_NAME "/my_mq"  
#define MSG_MAX_SIZE 256  struct mq_msg {  char text[MSG_MAX_SIZE];  
};  // 发送线程函数  
void *sender_thread(void *arg) {  mqd_t mqdes;  //struct mq_msg msg;  char buf[]="Hello from Sender!";mqdes = mq_open(QUEUE_NAME, O_WRONLY);  if (mqdes == (mqd_t)-1) {  perror("mq_open");  exit(EXIT_FAILURE);  }  //strcpy(msg.text, "Hello from Sender!");  //if (mq_send(mqdes, (const char *)&msg, sizeof(struct mq_msg), 0) == -1) if (mq_send(mqdes, buf, sizeof(buf), 0) == -1) {  perror("mq_send");  exit(EXIT_FAILURE);  }  mq_close(mqdes);  return NULL;  
}  // 接收线程函数  
void *receiver_thread(void *arg) {  mqd_t mqdes;  struct mq_msg msg;  ssize_t bytes_read;  mqdes = mq_open(QUEUE_NAME, O_RDONLY);  if (mqdes == (mqd_t)-1) {  perror("mq_open");  exit(EXIT_FAILURE);  }  //bytes_read = mq_receive(mqdes, (char *)&msg, sizeof(struct mq_msg), NULL);  bytes_read = mq_receive(mqdes, &msg.text[0], sizeof(struct mq_msg), NULL);  if (bytes_read == -1) {  perror("mq_receive");  exit(EXIT_FAILURE);  }  printf("Received message: %s\n", msg.text);  mq_close(mqdes);  return NULL;  
}  int main() {  pthread_t sender_tid, receiver_tid;  mqd_t mqdes;  struct mq_attr attr;  int ret;// 创建消息队列(如果需要)  mqdes = mq_open(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666, NULL);  if (mqdes != (mqd_t)-1) {  ret = mq_getattr(mqdes, &attr);if(ret < 0) {perror("mq_getattr");return (-1);}// 设置队列属性(可选) attr.mq_flags = 0; attr.mq_maxmsg = 10;  attr.mq_msgsize = sizeof(struct mq_msg);  attr.mq_curmsgs = 0;  if (mq_setattr(mqdes, &attr, NULL) == -1) {  perror("mq_setattr");  exit(EXIT_FAILURE);  }  mq_close(mqdes); // 创建后关闭,因为将在线程中重新打开  } else if (errno != EEXIST) {  perror("mq_open");  exit(EXIT_FAILURE);  }  // 创建发送者和接收者线程  // 创建接收者线程(注意:在实际应用中,你可能希望先启动接收者线程)  if (pthread_create(&receiver_tid, NULL, receiver_thread, NULL)) {  perror("pthread_create receiver");  return 1;  }  if (pthread_create(&sender_tid, NULL, sender_thread, NULL)) {  perror("pthread_create sender");  exit(EXIT_FAILURE);  }// 等待线程完成  pthread_join(sender_tid, NULL);  pthread_join(receiver_tid, NULL);  // 在实际应用中,你可能还需要处理消息的清理和队列的删除  return 0;  
}

带互斥量的测试程序,如下:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <sys/stat.h>  
#include <mqueue.h>  
#include <pthread.h>  #define QUEUE_NAME "/my_mq"  
#define MSG_MAX_SIZE 256  struct mq_msg {  char text[MSG_MAX_SIZE];  
};  // 全局变量:消息队列描述符和互斥锁  
mqd_t mqdes;  
pthread_mutex_t mq_mutex;  // 发送消息到队列的函数  
void send_message(const char *msg) {  struct mq_msg mq_msg;  strncpy(mq_msg.text, msg, MSG_MAX_SIZE);  pthread_mutex_lock(&mq_mutex); // 锁定互斥锁  if (mq_send(mqdes, (const char *)&mq_msg, sizeof(struct mq_msg), 0) == -1) {  perror("mq_send");  exit(EXIT_FAILURE);  }  pthread_mutex_unlock(&mq_mutex); // 解锁互斥锁  
}  // 从队列接收消息的函数  
void receive_message() {  struct mq_msg mq_msg;  ssize_t bytes_read;  pthread_mutex_lock(&mq_mutex); // 锁定互斥锁  bytes_read = mq_receive(mqdes, (char *)&mq_msg, sizeof(struct mq_msg), NULL);  if (bytes_read == -1) {  perror("mq_receive");  exit(EXIT_FAILURE);  }  printf("Received message: %s\n", mq_msg.text);  pthread_mutex_unlock(&mq_mutex); // 解锁互斥锁  
}  // 发送者线程函数  
void *sender_thread(void *arg) {  send_message("Hello from Sender!");  return NULL;  
}  // 接收者线程函数  
void *receiver_thread(void *arg) {  receive_message();  return NULL;  
}  int main() {  pthread_t sender_tid, receiver_tid;  // 初始化互斥锁  if (pthread_mutex_init(&mq_mutex, NULL) != 0) {  perror("pthread_mutex_init");  exit(EXIT_FAILURE);  }  // 打开或创建消息队列  mqdes = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0666, NULL);  if (mqdes == (mqd_t)-1) {  perror("mq_open");  exit(EXIT_FAILURE);  }  // 创建发送者和接收者线程  if (pthread_create(&sender_tid, NULL, sender_thread, NULL) != 0) {  perror("pthread_create sender");  exit(EXIT_FAILURE);  }  if (pthread_create(&receiver_tid, NULL, receiver_thread, NULL) != 0) {  perror("pthread_create receiver");  exit(EXIT_FAILURE);  }  // 等待线程完成  pthread_join(sender_tid, NULL);  pthread_join(receiver_tid, NULL);  // 关闭消息队列  mq_close(mqdes);  // 销毁互斥锁  pthread_mutex_destroy(&mq_mutex);  return 0;  
}

编译程序时,需要链接实时库(librt)

-lrt
arm-linux-gcc -o mq_example main.c -lrt -lpthread

测试程序报错,错误提示:

mq_receive: Message too long

在这里插入图片描述
修改代码如下:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <sys/stat.h>  
#include <mqueue.h>  
#include <pthread.h>  
#include <errno.h>
#include <unistd.h>#define MAXSIZE (10)
#define BUFFER (8192)
#define FILE_NAME "/posix"
struct msg_type {int len;char buf[MAXSIZE];
};// 发送线程函数  
void *sender_thread(void *arg) {  mqd_t msgq_id_tx;struct msg_type msg_tx;unsigned int prio_tx = 1;struct mq_attr msgq_attr_tx;int ret_tx;static int i_tx;msgq_id_tx = mq_open(FILE_NAME, O_WRONLY);if(msgq_id_tx == (mqd_t)-1) {perror("mq_open");return NULL;}for(;;){memset(msg_tx.buf, 0, MAXSIZE);sprintf(msg_tx.buf, "%d", i_tx++);strcat(msg_tx.buf,"-hello world");//sprintf(msg_tx.buf, "%s", "hello world");msg_tx.len = strlen(msg_tx.buf);fprintf(stdout, "send msg.buf = %s\n", msg_tx.buf);ret_tx= mq_send(msgq_id_tx, (char*)&msg_tx, sizeof(struct msg_type), prio_tx);if(ret_tx < 0) {perror("mq_send");return NULL;}sleep(1);}sleep(60);ret_tx = mq_close(msgq_id_tx);if(ret_tx < 0) {perror("mq_close");return NULL;}ret_tx = mq_unlink(FILE_NAME);if(ret_tx < 0) {perror("mq_unlink");return NULL;}return NULL;  }  // 接收线程函数  
void *receiver_thread(void *arg) {  mqd_t msgq_id_rx;unsigned int sender_rx;struct msg_type msg_rx;struct mq_attr msgq_attr_rx;long recv_size_rx = BUFFER;int ret_rx;int i_rx;msgq_id_rx = mq_open(FILE_NAME, O_RDWR);if(msgq_id_rx == (mqd_t)-1) {perror("mq_open");return NULL;}ret_rx = mq_getattr(msgq_id_rx, &msgq_attr_rx);if(ret_rx < 0) {perror("mq_getattr");return NULL;}printf("msgq_attr_rx.mq_msgsize=%d\r\n",msgq_attr_rx.mq_msgsize);printf("msgq_attr_rx.mq_maxmsg=%d\r\n",msgq_attr_rx.mq_maxmsg);if(recv_size_rx < msgq_attr_rx.mq_msgsize) {recv_size_rx = msgq_attr_rx.mq_msgsize;}for(;;){msg_rx.len = -1;memset(msg_rx.buf, 0, MAXSIZE);ret_rx = mq_receive(msgq_id_rx, (char*)&msg_rx, recv_size_rx, &sender_rx);if (ret_rx < 0) {perror("mq_receive");return NULL;}fprintf(stdout, "rx msg.len = %d, msg.buf = %s\r\n", msg_rx.len, msg_rx.buf);printf("***********************\r\n");printf("len=%d\r\n",strlen(msg_rx.buf));printf("data=\r\n%s\r\n",msg_rx.buf);printf("$$$$$$$$$$$$$$$$$$$$$$$\r\n");sleep(1);}ret_rx = mq_close(msgq_id_rx);if(ret_rx < 0) {perror("mq_close");return NULL;}return NULL;  
}  int main() {  pthread_t sender_tid, receiver_tid;  mqd_t msgq_id;struct mq_attr msgq_attr;int ret;// 创建消息队列(如果需要)  msgq_id = mq_open(FILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666, NULL);  if (msgq_id != (mqd_t)-1) {  ret = mq_getattr(msgq_id, &msgq_attr);if(ret < 0) {perror("mq_getattr");return (-1);}// 设置队列属性(可选) // msgq_attr.mq_flags = 0; // msgq_attr.mq_maxmsg = 10;  // msgq_attr.mq_msgsize = sizeof(struct msg_type);  // msgq_attr.mq_curmsgs = 0;  ret = mq_setattr(msgq_id, &msgq_attr, NULL);if(ret < 0) {perror("mq_setattr");return (-1);}mq_close(msgq_id); // 创建后关闭,因为将在线程中重新打开  } else if (errno != EEXIST) {  perror("mq_open");  exit(EXIT_FAILURE);  }  // 创建发送者和接收者线程  if (pthread_create(&sender_tid, NULL, sender_thread, NULL)) {  perror("pthread_create sender");  exit(EXIT_FAILURE);  }// 创建接收者线程(注意:在实际应用中,你可能希望先启动接收者线程)  if (pthread_create(&receiver_tid, NULL, receiver_thread, NULL)) {  perror("pthread_create receiver");  return 1;  }  // 等待线程完成  pthread_join(sender_tid, NULL);  pthread_join(receiver_tid, NULL);  // 在实际应用中,你可能还需要处理消息的清理和队列的删除  return 0;  
}

编译,程序正常启动,但是不知道为啥,接收的数据有问题。
在这里插入图片描述

在这里插入图片描述
长度超过12,数据就不全了。将 MAXSIZE 的宏定义 改大即可。

注意:
POSIX消息队列与System V消息队列的差别:
对象引用计数,可以更为安全的删除对象;
与System V消息类型不同,POSIX消息有一个关联的优先级,消息之间是严格的按照优先级排队接收;
提供了一个特性允许队列中的一条消息可异步通知进程;
可选组件,通过CONFIG_POSIX_MQUEUE配置。

参考
Linux系统编程手册/52-POSIX-消息队列/

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

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

相关文章

C++仿函数周边及包装器

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

ASP.NET网络在线考试系统

摘 要 随着计算机技术的发展和互联网时代的到来&#xff0c;人们已经进入了信息时代&#xff0c;也有人称为数字化时代。数在数字化的网络环境下&#xff0c;学生希望得到个性化的满足&#xff0c;根据自己的情况进行学习&#xff0c;同时也希望能够得到科学的评价&#xff0c…

小红书爬虫GUI软件 | API接口封装 | 根据笔记链接批量采集笔记详情,含笔记正文内容、发布时间、转评赞藏等

一、背景介绍 1.1 爬取目标 我用python开发的采集软件&#xff0c;可自动按笔记链接抓取笔记的详情数据。 为什么有了源码还开发界面软件呢&#xff1f;方便不懂编程代码的小白用户使用&#xff0c;无需安装python&#xff0c;无需改代码&#xff0c;双击打开即用&#xff0…

pytorch笔记:ModuleDict

1 介绍 在 PyTorch 中&#xff0c;nn.ModuleDict 是一个方便的容器&#xff0c;用于存储一组子模块&#xff08;即 nn.Module 对象&#xff09;的字典这个容器主要用于动态地管理多个模块&#xff0c;并通过键来访问它们&#xff0c;类似于 Python 的字典 2 特点 组织性 nn…

恶补《操作系统》4_2——王道学习笔记

4.1_5 文件存储空间管理 1、存储空间的划分与初始化 文件卷&#xff08;逻辑卷&#xff09;的概念目录区与文件区 2、几种管理方法 空闲表法&#xff1a;首位置长度&#xff0c;回收时注意修改空闲链表法&#xff08;空闲盘块链、空闲盘区链&#xff09;位示图法 成组链接法…

深度学习500问——Chapter08:目标检测(6)

文章目录 8.3.7 RetinaNet 8.3.7 RetinaNet 研究背景 Two-Stage 检测器&#xff08;如Faster R-CNN、FPN&#xff09;效果好&#xff0c;但速度相对慢。One-Stage 检测器&#xff08;如YOLO、SSD&#xff09;速度快&#xff0c;但效果一般。 作者对one-stage检测器准确率不高…

视频编辑软件pitivi基本功之将三个相关视频合并成一个视频

视频编辑软件pitivi基本功之将三个相关视频合并成一个视频 一、素材来源&#xff1a;网站下载 到http://cpc.people.com.cn/GB/67481/435238/437822/437828/437900/index.html下载以下三个视频&#xff0c;鼠标右击视频——另存视频为 庆祝中国共产党成立100周年大会即将开始—…

基于yolov8的苹果腐败检测系统,系统既支持图像检测,也支持视频和摄像实时检测(pytorch框架)【python源码+UI界面+功能源码详解】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的苹果腐败检测系统&#xff0c;系统既支持图像检测&#xff0c;也支持视频和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的苹果腐败检测系统是在pytorc…

设计模式之组合实体模式

在编程的奇幻森林里&#xff0c;树木与枝叶错综复杂&#xff0c;如何让代码世界井然有序&#xff1f;组合实体模式&#xff08;Composite Pattern&#xff09;就像一位高明的园艺师&#xff0c;它以一种巧妙的方式&#xff0c;将个体与整体统一管理&#xff0c;让无论是单个对象…

如何配置Jupyter Lab以允许远程访问和设置密码保护

如何配置Jupyter Lab以允许远程访问和设置密码保护 当陪你的人要下车时&#xff0c;即使不舍&#xff0c;也该心存感激&#xff0c;然后挥手道别。——宫崎骏《千与千寻》 在数据科学和机器学习工作流中&#xff0c;Jupyter Lab是一个不可或缺的工具&#xff0c;但是默认情况下…

AI图书推荐:杀手级ChatGPT提示词——利用人工智能实现成功与盈利

《杀手级ChatGPT提示词——利用人工智能实现成功与盈利》&#xff08;Killer ChatGPT Prompts_ Harness the Power of AI for Success and Profit &#xff09;一书是作者Guy Hart-Davis关于ChatGPT的指南&#xff0c;ChatGPT是OpenAI开发的大语言模型。这本书提供了各种职业角…

Java_JVM_JVMs

JVM 官方文档说明文档目录 官方文档 JVM Specification 说明 以Java SE 17为标准 文档目录 2&#xff1a;JVM 结构 class文件数据类型 基本数据类型引用数据类型 运行时数据区 栈帧 其他内容 对象的表示浮点数运算特殊方法 初始化方法【实例、类】多态方法 3&#xff…

第10课程 自动驾驶-控制理论

1. 控制模块 planning 规划 要求时时性质100hz 0.01s进行控制车 2. 控制为什么重要&#xff1f; 3. 预处理 lag compensation 滞后补偿 后处理 4 为什么需要控制 5 傅里叶变换

高效时间序列分析的开源利器:QuestDB

QuestDB&#xff1a;探索数据的深度&#xff0c;加速决策的速度- 精选真开源&#xff0c;释放新价值。 概览 时序数据库&#xff08;Time Series Database&#xff0c;简称TSDB&#xff09;是一种专门设计和优化的数据库系统&#xff0c;用于高效地存储、管理和查询带有时间戳…

ElasticSearch01(ES简介,安装ES,操作索引,操作文档,RestAPI)【全详解】

目录 一、ES简介 1. 数据库查询的问题 2. ES简介 1 ElasticSearch简介 2 ElasticSearch发展 3. 倒排索引【面试】 1 正向索引 2 倒排索引 4. ES和MySql 5. 小结 二、安装ES 1. 方式1:使用docker安装 1 准备工作 2 创建ElasticSearch容器 3 给ElasticSearch配置i…

【Mac】Lightroom Classic 2024 v13.1安装教程

软件介绍 Lightroom Classic 2024是Adobe公司推出的一款专业的数字图像处理软件&#xff0c;旨在为摄影师提供强大的工具和功能&#xff0c;以管理、编辑和分享他们的照片作品。以下是Lightroom Classic 2024的主要特点和功能&#xff1a; 数字照片管理&#xff1a; 提供直观…

前端工程化05-初始前端工程化Node基本介绍安装配置基础知识

6、初始前端工程化 6.1、工程化概述 虽然前几篇我的目录标题写的前端工程化&#xff0c;但是那些东西并不属于前端工程化的内容&#xff0c;更倾向于是js、jq当中的东西&#xff0c;下面我们将接触真正的前端工程化。 前端工程化开发其实现在是离不开一个东西的&#xff0c;…

React Native支持Tailwind CSS 语法

React Native支持Tailwind CSS 语法 一、前沿背景 回想下我们平时按照官方的规范进行书写样式是什么样&#xff1f; 是像下面这样&#xff1a; const MyComponent () > {return (<View><Text style{{ fontSize: 20 }}>开发者演示专用</Text></View…

WebDriver使用带用户名密码验证的IP代理解决方案

背景&#xff0c;使用python3 selenium 先定义一个方法&#xff0c;这里主要用到了chrome插件的功能&#xff0c;利用这个插件来放进代理内容。 def create_proxy_auth_extension(proxy_host, proxy_port,proxy_username, proxy_password, schemehttp):manifest_json "…

基于.NET WinForms 数据的CURD实现

开发工具 VS 2022 C#&#xff0c;数据库MS SQL SERVER 2019 1.WinForms界面 2.使用SqlDataApater DataSet DataGridView 读取数据 private void ReadData() {//数据库连接串string strConn "Data Source127.0.0.1;Initial CatalogTEST;Persist Security InfoTrue;Us…