开源 C++ QT QML 开发(十六)进程--共享内存
文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C++ QT QML 开发(一)基本介绍
开源 C++ QT QML 开发(二)工程结构
开源 C++ QT QML 开发(三)常用控件
开源 C++ QT QML 开发(四)复杂控件--Listview
开源 C++ QT QML 开发(五)复杂控件--Gridview
开源 C++ QT QML 开发(六)自定义控件--波形图
开源 C++ QT QML 开发(七)自定义控件--仪表盘
开源 C++ QT QML 开发(八)自定义控件--圆环
开源 C++ QT QML 开发(九)文件--文本和二进制
开源 C++ QT QML 开发(十)通讯--串口
开源 C++ QT QML 开发(十一)通讯--TCP服务器端
开源 C++ QT QML 开发(十二)通讯--TCP客户端
开源 C++ QT QML 开发(十三)多线程
开源 C++ QT QML 开发(十四)进程用途
开源 C++ QT QML 开发(十五)通讯--http下载
开源 C++ QT QML 开发(十六)进程--共享内存
推荐链接:
开源 C# 快速开发(一)基础知识
开源 C# 快速开发(二)基础控件
开源 C# 快速开发(三)复杂控件
开源 C# 快速开发(四)自定义控件--波形图
开源 C# 快速开发(五)自定义控件--仪表盘
开源 C# 快速开发(六)自定义控件--圆环
开源 C# 快速开发(七)通讯--串口
开源 C# 快速开发(八)通讯--Tcp服务器端
开源 C# 快速开发(九)通讯--Tcp客户端
开源 C# 快速开发(十)通讯--http客户端
开源 C# 快速开发(十一)线程
开源 C# 快速开发(十二)进程监控
开源 C# 快速开发(十三)进程--管道通讯
开源 C# 快速开发(十四)进程--内存映射
开源 C# 快速开发(十五)进程--windows消息
开源 C# 快速开发(十六)数据库--sqlserver增删改查
本章节主要内容是:Qml使用共享内存实现IPC通讯。例子为2个进程,通过创建共享内存,实现了双向实时通讯。
共享内存(QSharedMemory)主要用于进程间通信(IPC),允许不同的进程访问和操作同一块内存区域。
主要用途:
1. 进程间数据共享
多个进程可以读取和写入同一块内存
适用于需要高效数据传输的场景
避免进程间复杂的数据序列化和反序列化
2. 大数据传输
适合传输较大的数据块(如图像、音频等)
比传统的IPC方式(如信号/槽、TCP)更高效
3. 系统级数据交换
不同应用程序之间的数据交换
插件系统间的通信
服务进程与客户端进程的数据共享
4. 实时数据同步
需要快速响应的实时系统
监控系统数据共享
多进程协作处理
1.代码分析
2.所有源码
3.效果演示
一、代码分析1. main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "SharedMemoryManager.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // 启用高DPI缩放QGuiApplication app(argc, argv); // 创建GUI应用实例// 注册共享内存管理器到QMLSharedMemoryManager sharedMemoryManager; // 创建共享内存管理器实例QQmlApplicationEngine engine; // 创建QML引擎engine.rootContext()->setContextProperty("sharedMemoryManager", &sharedMemoryManager); // 注册到QML上下文engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // 加载QML文件if (engine.rootObjects().isEmpty()) // 检查加载是否成功return -1;return app.exec(); // 进入事件循环
}
函数分析:
应用初始化:设置高DPI支持,创建应用实例
对象注册:将C++对象暴露给QML引擎
资源加载:从qrc资源文件加载QML界面
错误处理:检查QML加载是否成功
2. SharedMemoryManager.h
#ifndef SHAREDMEMORYMANAGER_H
#define SHAREDMEMORYMANAGER_H#include <QObject>
#include <QSharedMemory>
#include <QTimer>
#include <QBuffer>
#include <QDataStream>
#include <QDateTime>class SharedMemoryManager : public QObject
{Q_OBJECT// QML属性声明Q_PROPERTY(QString status READ status NOTIFY statusChanged) // 状态属性Q_PROPERTY(QString lastMessage READ lastMessage NOTIFY lastMessageChanged) // 最后消息属性Q_PROPERTY(bool hasNewMessage READ hasNewMessage NOTIFY hasNewMessageChanged) // 新消息标志属性public:explicit SharedMemoryManager(QObject *parent = nullptr); // 构造函数~SharedMemoryManager(); // 析构函数// 属性读取函数QString status() const { return m_status; }QString lastMessage() const { return m_lastMessage; }bool hasNewMessage() const { return m_hasNewMessage; }public slots:void sendMessage(const QString &message); // 发送消息槽函数void receiveMessage(); // 接收消息槽函数 void clearStatus(); // 清除状态槽函数void startNewInstance(); // 启动新实例槽函数private slots:void checkSharedMemory(); // 检查共享内存私有槽函数private:void setupSharedMemory(); // 设置共享内存私有函数void updateStatus(const QString &status); // 更新状态私有函数// 成员变量QSharedMemory *m_sharedMemory; // 共享内存指针QTimer *m_checkTimer; // 检查定时器QString m_status; // 状态字符串QString m_lastMessage; // 最后消息内容bool m_hasNewMessage; // 新消息标志static const QString SHARED_MEMORY_KEY; // 共享内存键值常量signals:// 信号声明void statusChanged(); // 状态改变信号void lastMessageChanged(); // 最后消息改变信号void hasNewMessageChanged(); // 新消息标志改变信号void newMessageReceived(const QString &message, const QString ×tamp); // 新消息接收信号
};#endif // SHAREDMEMORYMANAGER_H
3. SharedMemoryManager.cpp
构造函数
SharedMemoryManager::SharedMemoryManager(QObject *parent): QObject(parent) // 调用父类构造函数, m_sharedMemory(new QSharedMemory(SHARED_MEMORY_KEY, this)) // 创建共享内存对象, m_checkTimer(new QTimer(this)) // 创建定时器对象, m_hasNewMessage(false) // 初始化新消息标志
{setupSharedMemory(); // 初始化共享内存连接connect(m_checkTimer, &QTimer::timeout, this, &SharedMemoryManager::checkSharedMemory); // 连接定时器信号m_checkTimer->start(1000); // 启动定时器,每秒检查一次
}
析构函数
cpp
SharedMemoryManager::~SharedMemoryManager()
{
if (m_sharedMemory->isAttached()) { // 检查是否已附加到共享内存
m_sharedMemory->detach(); // 分离共享内存
}
}
共享内存设置函数
void SharedMemoryManager::setupSharedMemory()
{// 尝试创建1024字节的共享内存if (!m_sharedMemory->create(1024) && m_sharedMemory->error() == QSharedMemory::AlreadyExists) {// 创建失败,但原因是已存在 → 尝试附加if (m_sharedMemory->attach()) {updateStatus("已连接到现有共享内存"); // 附加成功} else {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString()); // 附加失败}} else if (m_sharedMemory->isAttached()) {// 创建成功 → 新创建共享内存updateStatus("已创建新的共享内存");} else {// 创建失败且原因不是已存在 → 其他错误updateStatus("无法创建共享内存: " + m_sharedMemory->errorString());}
}
发送消息函数
void SharedMemoryManager::sendMessage(const QString &message)
{// 1. 连接检查if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());return;}// 2. 输入验证if (message.isEmpty()) {updateStatus("消息不能为空!");return;}// 3. 数据序列化QBuffer buffer;buffer.open(QBuffer::ReadWrite); // 打开缓冲区QDataStream out(&buffer); // 创建数据流// 序列化消息和时间戳out << message;out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");// 4. 写入共享内存m_sharedMemory->lock(); // 加锁char *to = static_cast<char*>(m_sharedMemory->data()); // 获取共享内存指针const char *from = buffer.data().data(); // 获取缓冲区数据指针memcpy(to, from, qMin(m_sharedMemory->size(), static_cast<int>(buffer.size()))); // 内存拷贝m_sharedMemory->unlock(); // 解锁// 5. 状态更新updateStatus("消息已发送: " + message);m_hasNewMessage = false; // 重置新消息标志emit hasNewMessageChanged(); // 发射标志改变信号
}
接收消息函数
void SharedMemoryManager::receiveMessage()
{// 1. 连接检查if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());return;}// 2. 读取数据m_sharedMemory->lock();QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());m_sharedMemory->unlock();// 3. 数据反序列化QBuffer buffer(&byteArray);buffer.open(QBuffer::ReadOnly);QDataStream in(&buffer);QString message;QString timestamp;in >> message >> timestamp; // 反序列化消息和时间戳// 4. 处理结果if (message.isEmpty()) {updateStatus("没有可用的消息");} else {m_lastMessage = QString("[%1] %2").arg(timestamp, message); // 格式化消息emit lastMessageChanged(); // 发射消息改变信号emit newMessageReceived(message, timestamp); // 发射新消息接收信号updateStatus("收到新消息: " + message);m_hasNewMessage = false; // 重置新消息标志emit hasNewMessageChanged(); // 发射标志改变信号}
}
定时检查函数
void SharedMemoryManager::checkSharedMemory()
{// 静默连接检查if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {return;}// 读取和解析数据m_sharedMemory->lock();QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());m_sharedMemory->unlock();QBuffer buffer(&byteArray);buffer.open(QBuffer::ReadOnly);QDataStream in(&buffer);QString message;QString timestamp;in >> message >> timestamp;// 检测新消息if (!message.isEmpty() && !m_hasNewMessage) {m_hasNewMessage = true; // 设置新消息标志emit hasNewMessageChanged(); // 发射标志改变信号}
}
启动新实例函数
void SharedMemoryManager::startNewInstance()
{QProcess *newProcess = new QProcess(this);QString program = QCoreApplication::applicationFilePath(); // 获取当前程序路径bool success = newProcess->startDetached(program); // 分离模式启动新进程if (success) {updateStatus("新实例启动成功");qDebug() << "启动新实例成功";} else {updateStatus("无法启动新实例");qDebug() << "启动新实例失败";}
}
状态管理函数
void SharedMemoryManager::clearStatus()
{updateStatus("就绪");m_hasNewMessage = false;emit hasNewMessageChanged();
}void SharedMemoryManager::updateStatus(const QString &status)
{if (m_status != status) { // 只在状态改变时更新m_status = status;emit statusChanged(); // 发射状态改变信号}
}
前台QML文件分析
main.qml 主要组件和函数
应用窗口定义
ApplicationWindow {id: windowwidth: 700height: 700minimumWidth: 600minimumHeight: 600title: "QML 共享内存演示 - PID: " + Qt.application.pidvisible: trueMaterial.theme: Material.LightMaterial.accent: Material.Blue
}
背景设置
Rectangle {anchors.fill: parentgradient: Gradient {GradientStop { position: 0.0; color: "#f5f7fa" }GradientStop { position: 1.0; color: "#c3cfe2" }}
}
头部标题组件
Item {Layout.fillWidth: trueLayout.preferredHeight: 80Rectangle {anchors.fill: parentcolor: Material.color(Material.Blue, Material.Shade50)radius: 15border.color: Material.color(Material.Blue, Material.Shade200)border.width: 2layer.enabled: truelayer.effect: DropShadow { // 阴影效果transparentBorder: trueradius: 8samples: 17color: "#40000000"}// ... 内部布局}
}
状态卡片组件
Rectangle {Layout.fillWidth: trueLayout.preferredHeight: 70radius: 12color: "white"border.color: sharedMemoryManager.hasNewMessage ? "#4CAF50" : "#E0E0E0" // 条件样式border.width: sharedMemoryManager.hasNewMessage ? 2 : 1layer.enabled: truelayer.effect: DropShadow {transparentBorder: trueradius: 6samples: 13color: "#20000000"}// ... 状态显示逻辑
}
控制面板按钮函数
Button {text: "🚀 启动新实例"Material.background: Material.BlueMaterial.foreground: "white"font.bold: trueonClicked: sharedMemoryManager.startNewInstance() // 调用C++函数
}
发送消息功能
TextField {id: messageInputLayout.fillWidth: trueplaceholderText: "💭 输入要发送的消息..."text: "👋 你好!这是来自进程 " + Qt.application.pid + " 的消息"font.pixelSize: 14background: Rectangle {radius: 8border.color: messageInput.activeFocus ? Material.color(Material.Blue) : "#E0E0E0"border.width: 2color: messageInput.activeFocus ? "#E3F2FD" : "#FAFAFA" // 焦点状态样式}
}Button {text: "📨 发送消息"onClicked: {if (messageInput.text.trim() !== "") { // 输入验证sharedMemoryManager.sendMessage(messageInput.text) // 调用发送函数messageInput.clear()}}
}
接收消息显示
TextArea {id: receivedTextreadOnly: trueplaceholderText: "💬 接收到的消息将显示在这里..."wrapMode: Text.Wrapfont.pixelSize: 13selectByMouse: truetextFormat: TextEdit.RichText // 支持富文本显示
}
自动接收定时器
Timer {id: autoReceiveTimerinterval: 1500 // 1.5秒间隔repeat: trueonTriggered: sharedMemoryManager.receiveMessage() // 定时调用接收函数
}
消息接收处理函数
Connections {target: sharedMemoryManageronNewMessageReceived: {var timestamp = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss")var formattedMessage = `<div style="margin: 8px 0; padding: 8px; background: #E8F5E8; border-radius: 6px; border-left: 4px solid #4CAF50;"><div style="font-weight: bold; color: #2E7D32;">📩 新消息 [${timestamp}]</div><div style="color: #1B5E20; margin-top: 4px;">${message}</div><div style="font-size: 11px; color: #689F38; margin-top: 2px;">⏰ ${timestamp}</div></div>`if (receivedText.text === receivedText.placeholderText) {receivedText.text = formattedMessage} else {receivedText.text += formattedMessage}receivedText.cursorPosition = receivedText.length // 自动滚动到底部}
}
键盘快捷键
Shortcut {sequence: "Ctrl+N"onActivated: sharedMemoryManager.startNewInstance() // 启动新实例快捷键
}Shortcut {sequence: "Ctrl+S"onActivated: {if (messageInput.text.trim() !== "") {sharedMemoryManager.sendMessage(messageInput.text) // 发送消息快捷键messageInput.clear()}}
}
二、所有源码
SharedMemoryManager.h文件源码
#ifndef SHAREDMEMORYMANAGER_H
#define SHAREDMEMORYMANAGER_H#include <QObject>
#include <QSharedMemory>
#include <QTimer>
#include <QBuffer>
#include <QDataStream>
#include <QDateTime>class SharedMemoryManager : public QObject
{Q_OBJECTQ_PROPERTY(QString status READ status NOTIFY statusChanged)Q_PROPERTY(QString lastMessage READ lastMessage NOTIFY lastMessageChanged)Q_PROPERTY(bool hasNewMessage READ hasNewMessage NOTIFY hasNewMessageChanged)public:explicit SharedMemoryManager(QObject *parent = nullptr);~SharedMemoryManager();QString status() const { return m_status; }QString lastMessage() const { return m_lastMessage; }bool hasNewMessage() const { return m_hasNewMessage; }public slots:void sendMessage(const QString &message);void receiveMessage();void clearStatus();private slots:void checkSharedMemory();private:void setupSharedMemory();void updateStatus(const QString &status);QSharedMemory *m_sharedMemory;QTimer *m_checkTimer;QString m_status;QString m_lastMessage;bool m_hasNewMessage;static const QString SHARED_MEMORY_KEY;signals:void statusChanged();void lastMessageChanged();void hasNewMessageChanged();void newMessageReceived(const QString &message, const QString ×tamp);
};#endif // SHAREDMEMORYMANAGER_H
SharedMemoryManager.cpp文件源码
#include "SharedMemoryManager.h"const QString SharedMemoryManager::SHARED_MEMORY_KEY = "QMLSharedMemoryDemo";SharedMemoryManager::SharedMemoryManager(QObject *parent): QObject(parent), m_sharedMemory(new QSharedMemory(SHARED_MEMORY_KEY, this)), m_checkTimer(new QTimer(this)), m_hasNewMessage(false)
{setupSharedMemory();connect(m_checkTimer, &QTimer::timeout, this, &SharedMemoryManager::checkSharedMemory);m_checkTimer->start(1000); // 每秒检查一次
}SharedMemoryManager::~SharedMemoryManager()
{if (m_sharedMemory->isAttached()) {m_sharedMemory->detach();}
}void SharedMemoryManager::setupSharedMemory()
{if (!m_sharedMemory->create(1024) && m_sharedMemory->error() == QSharedMemory::AlreadyExists) {if (m_sharedMemory->attach()) {updateStatus("已连接到现有共享内存");} else {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());}} else if (m_sharedMemory->isAttached()) {updateStatus("已创建新的共享内存");} else {updateStatus("无法创建共享内存: " + m_sharedMemory->errorString());}
}void SharedMemoryManager::sendMessage(const QString &message)
{if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());return;}if (message.isEmpty()) {updateStatus("消息不能为空!");return;}// 准备数据QBuffer buffer;buffer.open(QBuffer::ReadWrite);QDataStream out(&buffer);// 写入消息和时间戳out << message;out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");// 写入共享内存m_sharedMemory->lock();char *to = static_cast<char*>(m_sharedMemory->data());const char *from = buffer.data().data();memcpy(to, from, qMin(m_sharedMemory->size(), static_cast<int>(buffer.size())));m_sharedMemory->unlock();updateStatus("消息已发送: " + message);m_hasNewMessage = false;emit hasNewMessageChanged();
}void SharedMemoryManager::receiveMessage()
{if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {updateStatus("无法附加到共享内存: " + m_sharedMemory->errorString());return;}// 从共享内存读取数据m_sharedMemory->lock();QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());m_sharedMemory->unlock();QBuffer buffer(&byteArray);buffer.open(QBuffer::ReadOnly);QDataStream in(&buffer);QString message;QString timestamp;in >> message >> timestamp;if (message.isEmpty()) {updateStatus("没有可用的消息");} else {m_lastMessage = QString("[%1] %2").arg(timestamp, message);emit lastMessageChanged();emit newMessageReceived(message, timestamp);updateStatus("收到新消息: " + message);m_hasNewMessage = false;emit hasNewMessageChanged();}
}void SharedMemoryManager::checkSharedMemory()
{if (!m_sharedMemory->isAttached() && !m_sharedMemory->attach()) {return;}m_sharedMemory->lock();QByteArray byteArray(static_cast<const char*>(m_sharedMemory->constData()), m_sharedMemory->size());m_sharedMemory->unlock();QBuffer buffer(&byteArray);buffer.open(QBuffer::ReadOnly);QDataStream in(&buffer);QString message;QString timestamp;in >> message >> timestamp;if (!message.isEmpty() && !m_hasNewMessage) {m_hasNewMessage = true;emit hasNewMessageChanged();}
}void SharedMemoryManager::clearStatus()
{updateStatus("就绪");m_hasNewMessage = false;emit hasNewMessageChanged();
}void SharedMemoryManager::updateStatus(const QString &status)
{if (m_status != status) {m_status = status;emit statusChanged();}
}
main.qml文件源码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12ApplicationWindow {id: windowwidth: 600height: 500title: "QML 共享内存演示"visible: trueColumnLayout {anchors.fill: parentanchors.margins: 20spacing: 15// 状态显示Rectangle {Layout.fillWidth: trueheight: 50color: sharedMemoryManager.hasNewMessage ? "lightgreen" : "lightgray"border.color: "gray"radius: 5RowLayout {anchors.fill: parentanchors.margins: 10Label {text: "状态:"font.bold: true}Label {Layout.fillWidth: truetext: sharedMemoryManager.statuselide: Text.ElideRight}Button {text: "清除"onClicked: sharedMemoryManager.clearStatus()}}}// 发送消息区域GroupBox {Layout.fillWidth: truetitle: "发送消息"ColumnLayout {width: parent.widthTextField {id: messageInputLayout.fillWidth: trueplaceholderText: "输入要发送的消息..."text: "你好,这是来自QML共享内存的消息!"}Button {Layout.alignment: Qt.AlignRighttext: "发送消息"highlighted: trueonClicked: {sharedMemoryManager.sendMessage(messageInput.text)messageInput.clear()}}}}// 接收消息区域GroupBox {Layout.fillWidth: trueLayout.fillHeight: truetitle: "接收消息"ColumnLayout {width: parent.widthheight: parent.heightScrollView {Layout.fillWidth: trueLayout.fillHeight: trueclip: trueTextArea {id: receivedTextreadOnly: trueplaceholderText: "接收到的消息将显示在这里..."text: sharedMemoryManager.lastMessagewrapMode: Text.Wrap}}RowLayout {Layout.fillWidth: trueButton {text: "接收消息"onClicked: sharedMemoryManager.receiveMessage()}Button {text: "清空"onClicked: receivedText.clear()}Item { Layout.fillWidth: true }Label {text: sharedMemoryManager.hasNewMessage ? "● 有新消息" : "○ 无新消息"color: sharedMemoryManager.hasNewMessage ? "green" : "gray"}}}}// 消息历史GroupBox {Layout.fillWidth: trueLayout.preferredHeight: 120title: "消息历史"ListView {id: messageHistoryanchors.fill: parentclip: truemodel: ListModel {}delegate: Rectangle {width: parent.widthheight: 40color: index % 2 === 0 ? "white" : "#f0f0f0"Column {anchors.fill: parentanchors.margins: 5Text {text: messagefont.bold: true}Text {text: "时间: " + timestampfont.pixelSize: 10color: "gray"}}}}}}// 新消息接收处理Connections {target: sharedMemoryManageronNewMessageReceived: {messageHistory.model.append({message: message,timestamp: timestamp})}}// 初始化完成提示Component.onCompleted: {console.log("QML共享内存演示程序已启动")}
}
main.cpp文件源码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "SharedMemoryManager.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);// 注册共享内存管理器到QMLSharedMemoryManager sharedMemoryManager;QQmlApplicationEngine engine;engine.rootContext()->setContextProperty("sharedMemoryManager", &sharedMemoryManager);engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;return app.exec();
}
三、效果演示
将工程复制1个,然后打开2个工程,先运行第1个工程打开第1个进程,再把2个工程右键设为活动运行后则打开第2个进程,可以2个进程之间通过共享内存通讯。