【Qt】进程间通信之QSharedMemory示例

00. 目录

01. 概述

QSharedMemory提供了多个线程和进程对共享内存段的访问。它还提供了一种方法,让单个线程或进程锁定内存以进行独占访问。

当使用这个共享内存类时,请注意以下平台差异:

Windows:QSharedMemory 不“拥有”共享内存段。当所有具有连接到特定共享内存段的 QSharedMemory 实例的线程或进程已销毁其 QSharedMemory 实例或退出时,Windows 内核会自动释放共享内存段。

Unix:QSharedMemory“拥有”共享内存段。当将 QSharedMemory 实例附加到特定共享内存段的最后一个线程或进程通过销毁其 QSharedMemory 实例与该段分离时,Unix 内核会释放共享内存段。但是如果最后一个线程或进程在没有运行 QSharedMemory 析构函数的情况下崩溃,共享内存段会在崩溃中幸存下来。

HP-UX:每个进程只允许一个连接到共享内存段。这意味着 QSharedMemory 不应跨 HP-UX 中同一进程中的多个线程使用。

记得在对共享内存进行读写之前用lock ()锁住共享内存,完成后记得用unlock ()释放锁。

当 QSharedMemory 的最后一个实例与段分离时,QSharedMemory 会自动销毁共享内存段,并且不会保留对该段的引用。

02. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

03. 编程步骤

共享内存中数据提供方:

A、定义QSharedMemory shareMemory,并设置标志名shareMemory.setKey();
B、将共享内存与主进程分离 shareMemory.detach();
C、创建共享内存 shareMemory.create();
D、将共享内存上锁shareMemory.lock();
E、将进程中要共享的数据拷贝到共享内存中;
F、将共享内存解锁shareMemory.unlock();

共享内存中数据使用方:

A、定义QSharedMemory shareMemory,并设置与共享内存提供方一致的标志名shareMemory.setKey()。
B、将共享内存与主进程绑定shareMemory.attach(),使主进程可以访问共享内存的数据;
C、将共享内存上锁shareMemory.lock();
D、从共享内存中取数据;
E、使用完后将共享内存解锁shareMemory.unlock(),并将共享内存与进程分离shareMemory.detach();

04. 写端程序示例

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QSharedMemory>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;

    QSharedMemory *m_sharedMemory = nullptr;
};
#endif // WIDGET_H

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QString>
#include <QFileDialog>
#include <QImage>
#include <QBuffer>
#include <QDataStream>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //创建对象 设置Key
    m_sharedMemory = new QSharedMemory;
    m_sharedMemory->setKey("Kitty");

}

Widget::~Widget()
{
    delete ui;
}


//选择图片按钮槽函数
void Widget::on_pushButton_clicked()
{

    //如果指定Key共享内存已经关联,则解除关联
    if (m_sharedMemory->isAttached())
    {
        if (!m_sharedMemory->detach())
        {
            qDebug() << m_sharedMemory->errorString();
            return;
        }
    }


    //选择图片文件
    QString fileName = QFileDialog::getOpenFileName(this, "", "", "Images(*.*)");

    QImage image(fileName);
    ui->label->setPixmap(QPixmap::fromImage(image).scaled(256, 256));

    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);
    QDataStream out(&buffer);

    out << image;


    //创建共享内存
    if (!m_sharedMemory->create(buffer.size()))
    {
        qDebug() << m_sharedMemory->errorString();
        return;
    }

    //加锁
    m_sharedMemory->lock();

    char *data = (char *)m_sharedMemory->data();

    const char *from = buffer.data().data();
    memcpy(data, from, qMin(m_sharedMemory->size(), (int)buffer.size()));

    //解锁
    m_sharedMemory->unlock();

}

main.cpp文件

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

执行结果如下:
在这里插入图片描述

05. 读端程序示例

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QSharedMemory>



QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QSharedMemory *m_sharedMemory = nullptr;

};
#endif // WIDGET_H

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QBuffer>
#include <QDataStream>
#include <QImage>
#include <QPixmap>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //m_sharedMemory = new QSharedMemory("Kitty");

    m_sharedMemory = new QSharedMemory;
    m_sharedMemory->setKey("Kitty");


}

Widget::~Widget()
{
    delete ui;
}


//读取共享内存槽函数
void Widget::on_pushButton_clicked()
{
    //关联共享内存
    if (m_sharedMemory->attach())
    {
        qDebug() << "关联共享内存成功";
    }
    else
    {
        qDebug() << m_sharedMemory->errorString();
        return;
    }

    QBuffer buffer;
    QDataStream in(&buffer);
    QImage image;

    //加锁
    m_sharedMemory->lock();


    buffer.setData((char*)m_sharedMemory->constData(), m_sharedMemory->size());
    buffer.open(QBuffer::ReadOnly);
    in >> image;

    //解锁
    m_sharedMemory->unlock();

    //共享内存解除关联
    if (!m_sharedMemory->detach())
    {
        qDebug() << m_sharedMemory->errorString();
        return;
    }

    ui->label->setPixmap(QPixmap::fromImage(image));

}

main.cpp文件

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

执行结果如下
在这里插入图片描述

06. 附录

6.1 Qt教程汇总
网址:https://dengjin.blog.csdn.net/article/details/115174639

6.2 程序下载
下载:【Qt】进程间通信之QSharedMemory程序.rar

© 版权声明
THE END
喜欢就支持一下吧
点赞578 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容