QT 使用共享内存 实现进程间通讯

QSharedMemory如果两个进程运行在同一台机器上,且对性能要求非常高(如实时数据共享、图像渲染等),建议使用共享内存。

优点:
  • 高性能: 共享内存是进程间通信的最快方式之一,因为数据直接在内存中共享,不需要经过内核的系统调用或网络协议栈。
  • 低延迟: 由于数据直接在内存中传递,延迟非常低,适合需要高性能的场景(如实时数据处理、图像渲染等)。
  • 简单数据共享: 适合两个进程需要频繁访问相同数据的场景。

设计思路

  1. 共享内存区:用于存储数据。
  2. 互斥量:用于保护共享内存区,防止多个进程同时访问导致数据不一致。
  3. 信号量:用于通知对方有数据可用。

服务器实现

头文件

#ifndef SHAREDMEMORYSERVICE_H
#define SHAREDMEMORYSERVICE_H#include <QObject>
#include <QSharedMemory>
#include <QBuffer>
#include <QDataStream>
#include <QDebug>
#include <QThread>
#include <QSystemSemaphore>class SharedMemoryService : public QObject
{Q_OBJECT
public:explicit SharedMemoryService(QObject* parent = nullptr);~SharedMemoryService();// 向共享内存中写入数据bool writeToSharedMemory(const QByteArray& data);signals:// 当读取到共享内存中的数据时发出信号void signalRead(QBuffer& buffer);private slots:// 检查共享内存中的数据void checkSharedMemory();private:std::shared_ptr<QSharedMemory> m_sharedMemory; // 共享内存std::shared_ptr<QSystemSemaphore> m_semaphoreClient; // 信号量 - 客户端发送std::shared_ptr<QSystemSemaphore> m_semaphoreService; // 信号量- 服务器发送bool m_bCreate = false;                        // 是否创建成功bool m_bExit = false;                        // 是否退出QThread m_listenThread;                        // 监听线程
};#endif // SHAREDMEMORYSERVICE_H

cpp

#include "SharedMemoryService.h"SharedMemoryService::SharedMemoryService(QObject* parent): QObject(parent),m_sharedMemory(std::make_shared<QSharedMemory>("MySharedMemoryKey_XXX")),m_semaphoreClient(std::make_shared<QSystemSemaphore>("MySemaphoreKey_XXX", 0)),m_semaphoreService(std::make_shared<QSystemSemaphore>("MySemaphoreKey_XXX2", 0))
{// 创建共享内存,大小为1024字节if (!m_sharedMemory->create(1024)) {qDebug() << "无法创建共享内存:" << m_sharedMemory->errorString();return;}m_bCreate = true;// 移动监听线程到单独的线程中QObject::connect(&m_listenThread, &QThread::started, this, &SharedMemoryService::checkSharedMemory, Qt::DirectConnection);m_listenThread.start();
}SharedMemoryService::~SharedMemoryService()
{m_bExit = true;m_semaphoreClient->release(1);// 停止监听线程m_listenThread.quit();m_listenThread.wait();
}void SharedMemoryService::checkSharedMemory()
{if (!m_bCreate || !m_sharedMemory->isAttached())return;while (true){// 等待信号量if (m_semaphoreClient->acquire()) {if (m_bExit){break;}if (m_sharedMemory->lock()) {// 读取共享内存中的数据QBuffer buffer;buffer.setData((char*)m_sharedMemory->data(), m_sharedMemory->size());buffer.open(QIODevice::ReadOnly);// 如果共享内存中有数据,则发出信号if (buffer.size() > 0) {emit signalRead(buffer);// 清空共享内存内容memset(m_sharedMemory->data(), 0, m_sharedMemory->size());}// 解锁共享内存m_sharedMemory->unlock();}}}
}bool SharedMemoryService::writeToSharedMemory(const QByteArray& data)
{if (!m_bCreate || !m_sharedMemory->isAttached()){qDebug() << "共享内存未创建或未附加";return false;}if (m_sharedMemory->lock()) {// 将数据写入共享内存memcpy(m_sharedMemory->data(), data.data(), qMin(data.size(), m_sharedMemory->size()));// 释放锁m_sharedMemory->unlock();// 增加信号量计数,通知监听线程有数据可用m_semaphoreService->release(1);return true;}qDebug() << "无法锁定共享内存";return false;
}

调用


/// 创建共享内存
void MainWindow::slotCrateBtn()
{if (m_service){return;}ui->btnCreate->setEnabled(false);m_service = new SharedMemoryService();// 连接信号槽,监听共享内存中的数据QObject::connect(m_service, &SharedMemoryService::signalRead, this, &MainWindow::slotRecv, Qt::DirectConnection);
}/// 发送内容
void MainWindow::slotSendBtn()
{if (m_service == nullptr){return;}    // 向共享内存中写入数据QByteArray data = ui->textEditSend->toPlainText().toLocal8Bit();if (m_service->writeToSharedMemory(data)){qDebug() << "数据已成功写入共享内存";}else{qDebug() << "写入共享内存失败";}
}/// 收到数据
void MainWindow::slotRecv(QBuffer& buffer)
{QString text = buffer.data();if (text.isEmpty()){return;}qDebug() << "接收到共享内存中的数据:" << text;ui->textEdit->append(text);
}

客户端实现

头文件

#ifndef SHAREDMEMORYCLIENT_H
#define SHAREDMEMORYCLIENT_H#include <QObject>
#include <QSharedMemory>
#include <QBuffer>
#include <QDataStream>
#include <QDebug>
#include <QThread>
#include <QSystemSemaphore>#include <cstdio>
#include <iostream>
#include <list>
#include <memory>
#include <string>class SharedMemoryClient : public QObject
{Q_OBJECT
public:explicit SharedMemoryClient(QObject* parent = nullptr);~SharedMemoryClient();// 向共享内存中写入数据bool writeToSharedMemory(const QByteArray& data);signals:// 当读取到共享内存中的数据时发出信号void signalRead(QBuffer& buffer);private slots:// 处理共享内存中的数据void processSharedMemory();private:std::shared_ptr<QSharedMemory> m_sharedMemory; // 共享内存std::shared_ptr<QSystemSemaphore> m_semaphoreClient; // 信号量 - 客户端发送std::shared_ptr<QSystemSemaphore> m_semaphoreService; // 信号量- 服务器发送bool m_bCreate = false;                        // 是否创建成功bool m_bExit = false;                        // 是否退出QThread m_listenThread;                        // 监听线程
};#endif // SHAREDMEMORYCLIENT_H

cpp

#include "SharedMemoryClient.h"SharedMemoryClient::SharedMemoryClient(QObject* parent): QObject(parent), m_sharedMemory(std::make_shared<QSharedMemory>("MySharedMemoryKey_XXX")),m_semaphoreClient(std::make_shared<QSystemSemaphore>("MySemaphoreKey_XXX", 0)),m_semaphoreService(std::make_shared<QSystemSemaphore>("MySemaphoreKey_XXX2", 0))
{if (!m_sharedMemory->attach()) {qDebug() << "无法附加到共享内存:" << m_sharedMemory->errorString();return;}m_bCreate = true;// 将处理方法移动到监听线程中moveToThread(&m_listenThread);connect(&m_listenThread, &QThread::started, this, &SharedMemoryClient::processSharedMemory, Qt::DirectConnection);// 启动监听线程m_listenThread.start();
}SharedMemoryClient::~SharedMemoryClient()
{m_bExit = true;m_semaphoreService->release(1);// 停止监听线程m_listenThread.quit();m_listenThread.wait();
}void SharedMemoryClient::processSharedMemory()
{while (true) {if (m_semaphoreService->acquire()){if (m_bExit){break;}if (!m_bCreate || !m_sharedMemory->isAttached())continue;// 锁定共享内存if (m_sharedMemory->lock()){// 检查共享内存是否有数据QBuffer buffer;buffer.setData((char*)m_sharedMemory->data(), m_sharedMemory->size());buffer.open(QIODevice::ReadOnly);// 如果共享内存中有数据,则发出信号if (buffer.size() > 0){emit signalRead(buffer);// 清空共享内存内容memset(m_sharedMemory->data(), 0, m_sharedMemory->size());}// 解锁共享内存m_sharedMemory->unlock();}}}
}bool SharedMemoryClient::writeToSharedMemory(const QByteArray& data)
{if (!m_bCreate || !m_sharedMemory->isAttached()){qDebug() << "共享内存未创建或未附加";return false;}// 锁定共享内存if (m_sharedMemory->lock()){// 将数据写入共享内存memcpy(m_sharedMemory->data(), data.data(), qMin(data.size(), m_sharedMemory->size()));// 解锁共享内存m_sharedMemory->unlock();// 释放信号量,通知监听线程m_semaphoreClient->release(1);return true;}qDebug() << "无法锁定共享内存";return false;
}

调用


/// 连接共享内存
void MainWindow::slotCrateBtn()
{if (m_client){return;}ui->btnCreate->setEnabled(false);m_client = new SharedMemoryClient();// 连接信号槽,监听共享内存中的数据QObject::connect(m_client, &SharedMemoryClient::signalRead, this, &MainWindow::slotRecv, Qt::DirectConnection);}/// 发送内容
void MainWindow::slotSendBtn()
{if (m_client == nullptr){return;}// 向共享内存中写入数据QByteArray data = ui->textEditSend->toPlainText().toLocal8Bit();if (m_client->writeToSharedMemory(data)){qDebug() << "数据已成功写入共享内存";}else{qDebug() << "写入共享内存失败";}
}
/// 收到数据
void MainWindow::slotRecv(QBuffer& buffer)
{QString text = buffer.data();if (text.isEmpty()){return;}qDebug() << "接收到共享内存中的数据:" << text;ui->textEdit->append(text);
}

运行效果:

在这里插入图片描述

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

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

相关文章

OpenCV实验:图片加水印

第二篇&#xff1a;图片添加水印&#xff08;加 logo&#xff09; 1. 实验原理 水印原理&#xff1a; 图片添加水印是图像叠加的一种应用&#xff0c;分为透明水印和不透明水印。水印的实现通常依赖于像素值操作&#xff0c;将水印图片融合到目标图片中&#xff0c;常用的方法…

深入解析下oracle的number底层存储格式

oracle数据库中&#xff0c;number数据类型用来存储数值数据&#xff0c;它既可以存储负数数值&#xff0c;也可以存储正数数值。相对于其他类型数据&#xff0c;number格式的数据底层存储格式要复杂得多。今天我们就详细探究下oracle的number底层存储格式。 一、环境搭建 1.…

SparkSQL与Hive的整合

文章目录 SparkSQL与Hive的整合1.1. Spark On Hive1.1.1. Hive的准备工作1.1.2. Spark的准备工作1.1.3. Spark代码开发1.1.4. Spark On Hive案例 1.2. Hive On Spark1.3. SparkSQL命令行1.4. SparkSQL分布式查询引擎1.4.1. 开启ThriftServer服务1.4.2. beeline连接ThriftServer…

(持续更新)linux网络编程中需要注意的内核参数与网络机制

目录 零、基本说明 一、内核参数 二、相关机制 1、GRO &#xff08;1&#xff09;适用场景 &#xff08;2&#xff09;优缺点 &#xff08;3&#xff09;相关操作 2、Nagle 算法 &#xff08;1&#xff09;基本规则 &#xff08;2&#xff09;优缺点 &#xff08;3&…

DevExpress WPF中文教程:Grid - 如何移动和调整列大小?(一)

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

Matlab笔记---clear、clc、clear all应用

在MATLAB中&#xff0c;clear、clc 和 clear all 是三个常用的命令&#xff0c;它们各自有不同的作用&#xff1a; clc&#xff1a; clc 命令用于清除MATLAB命令窗口中的所有输出。它不会删除任何变量、函数或文件&#xff0c;只是清除屏幕上的显示内容&#xff0c;让你可以更…

Qt 一个简单的QChart 绘图

Qt 一个简单的QChart 绘图 先上程序运行结果图&#xff1a; “sample9_1QChart.h” 文件代码如下&#xff1a; #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample9_1QChart.h"#include <QtCharts> //必须这么设置 QT_CHARTS_USE_NAME…

分布式事物XA、BASE、TCC、SAGA、AT

分布式事务——Seata 一、Seata的架构&#xff1a; 1、什么是Seata&#xff1a; 它是一款分布式事务解决方案。官网查看&#xff1a;Seata 2.执行过程 在分布式事务中&#xff0c;会有一个入口方法去调用各个微服务&#xff0c;每一个微服务都有一个分支事务&#xff0c;因…

MySQL为什么使用B+树来作索引

我来详细解释一下B树的结构和特点。 graph TDA[根节点 40|70] --> B[20|30]A --> C[50|60]A --> D[80|90]B --> E[10|15]B --> F[25|28]B --> G[35|38]C --> H[45|48]C --> I[55|58]C --> J[65|68]D --> K[75|78]D --> L[85|88]D --> M[9…

python 下载 b站视频 和音频

video_bvid&#xff1a; import os import requests import json import re from bs4 import BeautifulSoup import subprocess # from detail_video import video_bvid# video_bvid 是一个从外部得到的单个视频ID video_bvid BV1cx421Q7veclass BilibiliVideoAudio:def __in…

以太网链路详情

文章目录 1、交换机1、常见的概念1、冲突域2、广播域3、以太网卡1、以太网卡帧 4、mac地址1、mac地址表示2、mac地址分类3、mac地址转换为二进制 2、交换机的工作原理1、mac地址表2、交换机三种数据帧处理行为3、为什么会泛洪4、转发5、丢弃 3、mac表怎么获得4、同网段数据通信…

Shell编程 脚本的运行方式与注释

目录 shell脚本的运行方式 1. 路径运行 2.bash或sh加脚本运行 ​编辑 3.source在加脚本路径运行 shell脚本注释 单行注释 多行注释 shell脚本的运行方式 我们在/usr/etc/demo01目录下新建了一个脚本 a.sh &#xff0c;脚本内容是要求输出数字1&#xff0c;怎么运行呢 1…

智算网络中Scale-out和Scale-up网络的技术原理

智算网络中Scale-out网络和Scale-up网络的本质区别是什么&#xff1f; 一、什么是智算中心的Scale-out网络和Scale-up网络 数据中心网络总体上可分为两大类&#xff1a;通算网络和智算网络。通算网络主要用于支持传统的计算任务和应用&#xff0c;如企业的IT系统、网站托管、电…

HCIA笔记7--OSPF协议入门

文章目录 0. 路由分类1. OSPF介绍1.1 概念1.2 报文类型 2. 邻接关系的建立2.1 邻居关系的建立2.2 邻接关系的形成2.3 ospf状态机 3. DR与BDR3.1 为什么要有DR和BDR&#xff1f;3.2 DR和BDR的选举原则 4. ospf的配置4.1 内部优先级 5. 问题5.1 三层环路如何解决&#xff1f; Ref…

mysql排序问题

mysql 建数据库时&#xff0c;需要指定 字符集 和 排序规则 建表时&#xff0c;也可以指定 也可以指定具体的字段 安照下面的sql顺序执行插入&#xff0c;它们的排序是什么样的&#xff1f; INSERT into test_sort (uid,create_time) VALUE (d,now()) INSERT into test_sort (u…

vulhub复现CVE-2021-44228log4j漏洞

目录 一&#xff1a;漏洞概述 二&#xff1a;漏洞原理 三&#xff1a;漏洞利用 lookup功能&#xff1a; JNDI解析器&#xff1a; ldap服务&#xff1a; RMI&#xff1a; 四&#xff1a;漏洞复现 4.1靶场 4.2dnslog测试 4.3部署jndi-injection-exploit 4.4打开监听端口 4.5触发请…

ip地址获取失败啥意思?ip地址获取失败怎么回事

在日常的网络使用中&#xff0c;我们时常依赖于稳定的IP地址来确保数据的顺畅传输和设备的正常识别。然而&#xff0c;有时我们会遇到“IP地址获取失败”的困扰&#xff0c;这不仅阻碍了我们的网络访问&#xff0c;还可能带来一系列的网络连接问题。那么&#xff0c;IP地址获取…

OpenGL ES详解——多个纹理实现混叠显示

目录 一、获取图片纹理数据 二、着色器编写 1. 顶点着色器 2. 片元着色器 三、绑定和绘制纹理 1. 绑定纹理 2. 绘制纹理 四、源码下载 一、获取图片纹理数据 获取图片纹理数据代码如下&#xff1a; //获取图片1纹理数据 mTextureId loadTexture(mContext, R.mipmap.…

十一、容器化 vs 虚拟化-Docker

文章目录 前言一、Docker 介绍1. 简介2. 应用场景3. 特点4. Docker和虚拟机之间的区别5. 解决痛点1. 解决依赖兼容2. 解决操作系统环境差异3. 小结 二、Docker 架构三、工作流程五、Docker 核心组件及其工作机制1. Docker 客户端&#xff08;Docker Client&#xff09;2. Docke…

linux学习笔记01 基础命令

目录 创建 touch 创建文件 &#xff08;创建但是不打开&#xff09; vi / vim 创建文件 (创建一个文件并打开) mkdir 创建文件夹 切换目录 cd 查看 pwd 查看当前目录完整路径 ls 查看目录信息 dir 查看目录信息 ll 表示查看目标目录下的信息 ls -a 查看当前目录下的…