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