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,一经查实,立即删除!

相关文章

在Scala中对隐式转换格式与作用

隐式对象 格式&#xff1a;implicit object 作用&#xff1a;给函数的默认参数提供隐式值 object Scala12______10 { // case class DataBase(driver: String, url: String) // // implicit object mySql extends DataBase("mysql", "localhost:300") //…

go build command

文章目录 1.简介2.格式3.选项4.示例5.小结参考文献 1.简介 go build 是 Go 语言工具链中的一个命令&#xff0c;它用于编译 Go 源代码并生成可执行文件。 2.格式 go build [-o output] [build flags] [packages]可选的 -o 选项强制 build 将生成的可执行文件或对象写入指定的…

OpenCV实验:图片加水印

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

WinDbg 中使用 !process 命令

PROCESS 81a979d0 SessionId: 0 Cid: 0210 Peb: 7ffda000 ParentCid: 063cDirBase: 145b9000 ObjectTable: e12fed70 HandleCount: 53.Image: Dbgview.exe 1. PROCESS 81a979d0 意义&#xff1a;PROCESS 是该进程对象的内核地址。用途&#xff1a;可以使用这个地址获…

深入解析下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;让你可以更…

铭记一次项目重大事故

在程序的世界里&#xff0c;bug 就像隐藏在暗处的小怪兽&#xff0c;时不时跳出来捣乱。而职业生涯中&#xff0c;总有那么一个或几个 bug 让我们刻骨铭心。它或许让项目差点夭折&#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…

2024年06月中国电子学会青少年软件编程(Python)等级考试试卷(五级)答案 + 解析

青少年软件编程(python)等级考试试卷(五级) 一、单选题(共25题,共50分) range()函数的基本用法是什么?( ) A. 生成一个等差数列 B. 生成一个随机数列 C. 生成一个递增数列 D. 生成一个递减数列 正确答案:A 答案解析:range() 函数用于生成一个等差数列,其中起始值、…

以太网链路详情

文章目录 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…

获取淘宝商品评论数据的API应用:市场调研|产品更新|用户数据

下面是一段我用item_review&#xff08;获取商品评论数据&#xff09;抓来的商品评论数据&#xff1a; "items": {"total_results": 375,"totalpage": 38,"page_size": 10,"page": "1","item": [{&quo…

智算网络中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…