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.xdnf.cn/news/1411228.html

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

相关文章

idea 新建spring maven项目、ioc和依赖注入

文章目录 一、新建Spring-Maven项目二、在Spring-context使用IOC和依赖注入 一、新建Spring-Maven项目 在pom.xml文件中添加插件管理依赖 <build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</ver…

来一篇错题集(虽然简单吧)

一.Assembly via Remainders #include<bits/stdc.h> using namespace std; typedef long long ll; int a[2000]; int b[2000]; int main(){int t;cin>>t;while(t--){int n;cin>>n;for(int i1;i<n-1;i){cin>>b[i];}int x1000000000;//使用1000000000…

算法打卡day40

今日任务&#xff1a; 1&#xff09;139.单词拆分 2&#xff09;多重背包理论基础&#xff08;卡码网56携带矿石资源&#xff09; 3&#xff09;背包问题总结 4&#xff09;复习day15 139单词拆分 题目链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; …

LLaVA:分析图像和文本数据的开源模型

原文地址&#xff1a;analyzing-images-with-llava 2024 年 3 月 20 日 在过去的几个月里&#xff0c;ChatGPT 等各种大型语言模型&#xff08;LLM&#xff09;已进入商业市场&#xff0c;许多公司已成功地将 LLM 集成到其产品和服务中&#xff0c;极大地改变了我们与设备和互…

RocketMQ SpringBoot 3.0不兼容解决方案

很多小伙伴在项目升级到springBoot3.0版本以上之后&#xff0c;整合很多中间件会有很多问题&#xff0c;下面带小伙伴解决springBoot3.0版本以上对于RocketMQ 不兼容问题 报错信息 *************************** APPLICATION FAILED TO START *************************** Des…

【JVM】JMM 内存模型

JMM 概述 内存模型 java[内存模型](Java Memory Model) 和 [内存结构]JMM规定了在多线程下对共享数据的读写时&#xff0c;对数据的原子性 有序性 可见性的规则和保障。 原子性 原子性问题: i和i–不是原子性操作! 所以一个i指令会在执行过程中被另一个线程执行! 问题分…

C++ | Leetcode C++题解之第67题二进制求和

题目&#xff1a; 题解&#xff1a; class Solution { public:string addBinary(string a, string b) {string ans;reverse(a.begin(), a.end());reverse(b.begin(), b.end());int n max(a.size(), b.size()), carry 0;for (size_t i 0; i < n; i) {carry i < a.siz…

最佳实践|Apifox 中通过 CryptoJS 给请求参数进行 AES 加密!

假如现在要在 Apifox 中发送一个「登录」的请求&#xff0c;然后我需要将接口中的 password 参数使用 AES 加密算法加密以后&#xff0c;再传给后台服务&#xff0c;这要怎么做&#xff1f; 要在 Apifox 中使用 AES 加密算法对 password 参数进行加密&#xff0c;你需要在「前置…

4 Spring AOP

目录 AOP 简介 传统开发模式 先来看一个需求 解决方案 AOP 图示 Spring 启用 AspectJ 基于 xml 配置 创建 pom.xml 创建 UserService 借口和 UserServiceImpl实现类 创建 LogAdvice 日志通知 创建 log4j.properties 重点&#xff1a;创建 spring-context-xml.xml 配…

如何让 PDF 书签从杂乱无序整洁到明丽清新

1、拉取书签&#xff08;详细步骤看文末扩展阅读&#xff09; 原状态 —— 杂乱无序 自动整理后的状态 —— 错落有致&#xff0c;但摩肩接踵 2、开始整理 全选自动整理后的书签&#xff0c;剪切 访问中英混排排版优化 - 油条工具箱 https://utils.fun/cn-en 1 粘贴 → 2 …

国科大模版修订模式冲突

定位到 \documentclass[twoside]{Style/ucasthesis}%前添加\PassOptionsToPackage{changes,usenames,dvipsnames,table}{xcolor} 完整如下&#xff1a; \PassOptionsToPackage{changes,usenames,dvipsnames,table}{xcolor} \documentclass[twoside]{Style/ucasthesis}% \us…

Sarcasm detection论文解析 |A2Text-Net:一种用于讽刺检测的新型深度神经网络

论文地址 论文地址&#xff1a;A2Text-Net: A Novel Deep Neural Network for Sarcasm Detection | IEEE Conference Publication | IEEE Xplore github:lliyuan1117/A2Text-Net (github.com) 论文首页 A2Text-Net&#xff1a;一种用于讽刺检测的新型深度神经网络 &#x1f4c5…

QT:label标签/进度条的使用

文章目录 设置不同格式的文本显示图片文本对齐/自动换行/缩进/边距LCDNumber倒计时 ProgressBar进度条 设置不同格式的文本 在文本格式中&#xff0c;存在富文本&#xff0c;makedown格式的文本&#xff0c;还有纯文本&#xff0c;下面就依据这三个进行举例 #include "w…

数据库基础--MySQL多表查询之外键约束

MySQL多表关系 一对一 顾名思义即一个对应一个的关系&#xff0c;例如身份证号对于每个人来说都是唯一的&#xff0c;即个人信息表与身份证号信息表是一对一的关系。车辆信息表与车牌信息表也是属于一对一的关系。 一对多 即一个表当中的一个字段信息&#xff0c;对应另一张…

MLP手写数字识别(1)-MNIST数据集下载与可视化(tensorflow)

1.下载与查看MNIST数据集 from keras.datasets import mnist(x_train_image,y_train_label),(x_test_image,y_test_label) mnist.load_data() print("train images:",x_train_image.shape) print("test images:",x_test_image.shape) print("train …

WAAP动态安全解决方案

随着企业数字化进程不断加速&#xff0c;应用安全面临多重威胁&#xff0c;新型攻击方式层出不穷&#xff0c;常见的攻击形式包括Web应用攻击、DDoS攻击、API攻击、恶意爬虫攻击等。企业正面临严峻的安全防护挑战&#xff0c;需寻找一个可靠、全面的安全解决方案。在此情况下&a…

基于Springboot的校园食堂订餐系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园食堂订餐系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

P9422 [蓝桥杯 2023 国 B] 合并数列

P9422 [蓝桥杯 2023 国 B] 合并数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 用队列即可 当两个队列队首&#xff1a;a b &#xff0c;弹出 当a < b&#xff0c;把a加给其后一个元素&#xff0c;弹出a 当b < a&#xff0c;把b加给其后一个元素&#xff0c;弹出…

亚马逊云科技AWS免费证书-EC2服务器设计(含题库)

亚马逊云AWS官方程序员专属免费证书又来了&#xff01;这次证书是关于AWS EC2实例的设计和搭建&#xff0c;EC2作为AWS服务的核心&#xff0c;是学好AWS的第一步。强推没有任何AWS背景和转码的小伙伴去学&#xff01;学完也能变成AWS开发大神&#xff01; 证书名字叫Getting St…

C++---入门基础

一、命名空间 在C/C中&#xff0c;有大量的函数&#xff0c;变量乃至类&#xff0c;这些函数&#xff0c;变量和类的名称都将作用于全局作用域中&#xff0c;这可能会导致命名冲突。针对这个问题&#xff0c;我们就会使用命名空间&#xff0c;命名空间的目的就是对标识符及名称…