Qt之进程间通信(共享内存)

一、简介

 在Qt中,共享内存(Shared Memory)是一种进程间通信(Inter-Process Communication, IPC)机制,允许多个进程共享同一块内存区域。共享内存提供了高效的数据交换方式,适用于需要频繁传递大量数据的场景。

 Qt中的共享内存机制主要依赖于QSharedMemory类。该类提供了用于创建和管理共享内存区域的接口,允许进程在内存中创建一个共享的数据缓冲区。共享内存的原理如下:

  1. 创建共享内存: 使用QSharedMemory类的create()函数可以创建一个共享内存对象,并指定一个唯一的键(key)来标识共享内存区域。如果该键对应的共享内存已经存在,则会返回false

  2. 分配内存: 一旦创建共享内存对象,可以使用QSharedMemory类的attach()函数将共享内存附加到当前进程的地址空间。这样,进程就可以访问共享内存中的数据了。

  3. 写入和读取数据: 通过共享内存附加到的地址,进程可以直接读取或写入共享内存中的数据。可以使用任何数据结构,如数组、结构体等来组织共享的数据。

  4. 分离和删除共享内存: 当进程不再需要访问共享内存时,可以使用QSharedMemory类的detach()函数将共享内存从当前进程的地址空间中分离。而使用QSharedMemory类的remove()函数可以删除共享内存区域,释放相关资源。

 需要注意的是,共享内存并不提供进程同步和互斥的机制。在使用共享内存进行进程间通信时,需要采用其他的同步机制,如信号量、互斥锁等,来确保数据的正确读写。

二、QSharedMemory介绍

QSharedMemory在读写内存的时候,需要使用lock()来实现数据的同步,通过使用attach()访问共享内存,如果附加操作成功,则返回 true。 如果返回 false,则调用 error() 来确定发生了哪个错误。 附加共享内存段后,可以通过调用data()获得一个指向共享内存的指针。

QSharedMemory分为ReadOnly模式和ReadWrite模式;QSharedMemory::ReadOnly模式只能通过只读模式访问共享内存,而使用QSharedMemory::ReadWrite模式则可以通过读写模式访问共享内存。

QSharedMemory拥有进程并提供可以返回共享内存区域指针的成员函数。在共享内存区域,成员函数constData()可以通过void类型返回进程正在使用的内存区域指针。创建共享时,QSharedMemory可以以字节为单位分配共享内存区域,还可以通过第二个参数设置函数attach()提供的模式,使用函数setKey()可以设置与独立与平台的键。函数setKey()可以为共享内存创建唯一的标志key,通过这个key来查询到相对应的共享内存。

三、数据写入到共享内存中

复制代码
#define SHARED_MEMORY_KEY  "shared_memory"

typedef struct {
    int status;
    int width;
    int height;
    char buffer[1024];
} MemoryInfo;

class MainWindow : public QObject
{
    Q_OBJECT
public:
    explicit MainWindow(QObject *parent = nullptr);
    ~MainWindow();

private slots:
    void on_start_timer();

private:
    QSharedMemory *m_shared_memory;
    QTimer *m_start_timer;
    MemoryInfo *m_memory_data;

    int m_screen_width;
    int m_screen_height;
};
复制代码
复制代码
MainWindow::MainWindow(QObject *parent) : QObject(parent)
{
    m_screen_width = GetSystemMetrics(SM_CXSCREEN);
    m_screen_height = GetSystemMetrics(SM_CYSCREEN);

    m_memory_data = new MemoryInfo;

    m_shared_memory = new QSharedMemory;
    m_shared_memory->setKey(SHARED_MEMORY_KEY);
    if (!m_shared_memory->attach(QSharedMemory::ReadWrite)) {
        m_shared_memory->create(sizeof(MemoryInfo), QSharedMemory::ReadWrite);
    }

    m_start_timer = new QTimer(this);
    connect(m_start_timer, &QTimer::timeout, this, &MainWindow::on_start_timer);
    m_start_timer->start(5000);

}

MainWindow::~MainWindow()
{
    delete m_memory_data;
    delete m_shared_memory;
}

void MainWindow::on_start_timer()
{
    qDebug() << "start shared memory...";

    const char *shared_info = "shared memory";

    m_memory_data->status = 1;
    m_memory_data->width = m_screen_width;
    m_memory_data->height = m_screen_height;
    memcpy(m_memory_data->buffer, shared_info, strlen(shared_info));

    m_shared_memory->lock();
    memcpy(m_shared_memory->data(), m_memory_data, sizeof(MemoryInfo));
    m_shared_memory->unlock();
}
复制代码

四、从共享内存中读数据

复制代码
#include <QThread>
#include <QSharedMemory>

#define SHARED_MEMORY_KEY  "shared_memory"

typedef struct {
    int status;
    int width;
    int height;
    char buffer[1024];
} MemoryInfo;

class MainWindow : public QThread
{
    Q_OBJECT

public:
    explicit MainWindow();
    ~MainWindow();

protected:
    void run() override;

private:
    QSharedMemory *m_shared_memory;
    MemoryInfo *m_memory_info;
};
复制代码
复制代码
MainWindow::MainWindow()
{
    m_shared_memory = new QSharedMemory;
    m_shared_memory->setKey(SHARED_MEMORY_KEY);
}

MainWindow::~MainWindow()
{
    delete  m_shared_memory;
}

void MainWindow::run()
{
    while (true) {
        if (!m_shared_memory->attach(QSharedMemory::ReadOnly)) {
            qDebug() << "waiting write_memory process start... ";
            QThread::sleep(5);
        } else {
            break;
        }
    }

    while (true) {
        m_shared_memory->lock();
        m_memory_info = (MemoryInfo*)m_shared_memory->constData();
        int status = m_memory_info->status;
        if (status == 1) {
            int width = m_memory_info->width;
            int height = m_memory_info->height;
            char buffer[1024] = {0};
            memcpy(buffer, m_memory_info->buffer, sizeof (buffer) / sizeof (buffer[0]));
            
            qDebug() <<"---------------------start---------------------";
            qDebug() << width << "*" << height;
            qDebug() << "status:" << status;
            qDebug() << "buffer:" << buffer;
            qDebug() <<"---------------------end-----------------------";
            
            QThread::sleep(5);
        }
        m_shared_memory->unlock();
    }
}
复制代码

五、效果展示

 

posted @   TechNomad  阅读(5301)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek “源神”启动!「GitHub 热点速览」
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示