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

 更新时间:2024年12月13日 09:17:22   作者:hss2799  
这篇文章主要为大家详细介绍了QT如何使用共享内存实现进程间通讯,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

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

优点:

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

设计思路

共享内存区:用于存储数据。

互斥量:用于保护共享内存区,防止多个进程同时访问导致数据不一致。

信号量:用于通知对方有数据可用。

服务器实现

头文件

#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);
}

运行效果

以上就是QT使用共享内存实现进程间通讯的详细内容,更多关于QT进程间通讯的资料请关注脚本之家其它相关文章!

相关文章

  • 详解C++模板编程中typename用法

    详解C++模板编程中typename用法

    typename在C++类模板或者函数模板中经常使用的关键字,此时作用和class相同,只是定义模板参数,下面通过例子给大家介绍c++模板typename的具体用法,一起看看吧
    2021-07-07
  • C语言二维数组应用之扫雷游戏

    C语言二维数组应用之扫雷游戏

    这篇文章主要为大家详细介绍了C语言二维数组应用之扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++实现单例模式的自动释放

    C++实现单例模式的自动释放

    这篇文章主要为大家详细介绍了C++实现单例模式的自动释放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C语言详细分析贪心策略中最小生成树的Prime算法设计与实现

    C语言详细分析贪心策略中最小生成树的Prime算法设计与实现

    最小生成树的问题还是比较热门的,最经典的莫过于Prime算法和Kruskal算法了,这篇博文我会详细讲解Prime算法的设计思想与具体代码的实现,不要求数据结构学的有多好,只要跟着我的思路来,一步一步的分析,调试,终能成就自己,那就让我们开始吧
    2022-05-05
  • VScode搭建OpenCV环境的详细步骤

    VScode搭建OpenCV环境的详细步骤

    用vscode来写opencv代码需要自己编译OpenCV,主要用到MinGW-w64和CMake工具。接下来通过本文给大家介绍VScode搭建OpenCV环境的相关知识,需要的朋友可以参考下
    2021-11-11
  • C语言实现带头结点的链表的创建、查找、插入、删除操作

    C语言实现带头结点的链表的创建、查找、插入、删除操作

    这篇文章主要介绍了C语言实现带头结点的链表的创建、查找、插入、删除操作方法,对于了解数据结构中链表的各项操作有很好的借鉴价值,需要的朋友可以参考下
    2014-09-09
  • c实现linux下的数据库备份

    c实现linux下的数据库备份

    本文给大家简单介绍下c实现linux下的数据库备份的方法和具体的源码,十分的实用,有需要的小伙伴可以参考下。
    2015-07-07
  • C语言实现哈夫曼树的方法

    C语言实现哈夫曼树的方法

    这篇文章主要为大家详细介绍了C语言实现哈夫曼树的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • C++中的整形字节数

    C++中的整形字节数

    这篇文章主要介绍了C++中的整形字节数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C++实现简单校园导游系统

    C++实现简单校园导游系统

    这篇文章主要为大家详细介绍了C++实现简单校园导游系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论