QT使用共享內(nèi)存實(shí)現(xiàn)進(jìn)程間通訊
QSharedMemory:如果兩個(gè)進(jìn)程運(yùn)行在同一臺(tái)機(jī)器上,且對(duì)性能要求非常高(如實(shí)時(shí)數(shù)據(jù)共享、圖像渲染等),建議使用共享內(nèi)存。
優(yōu)點(diǎn):
- 高性能: 共享內(nèi)存是進(jìn)程間通信的最快方式之一,因?yàn)閿?shù)據(jù)直接在內(nèi)存中共享,不需要經(jīng)過內(nèi)核的系統(tǒng)調(diào)用或網(wǎng)絡(luò)協(xié)議棧。
- 低延遲: 由于數(shù)據(jù)直接在內(nèi)存中傳遞,延遲非常低,適合需要高性能的場(chǎng)景(如實(shí)時(shí)數(shù)據(jù)處理、圖像渲染等)。
- 簡(jiǎn)單數(shù)據(jù)共享: 適合兩個(gè)進(jìn)程需要頻繁訪問相同數(shù)據(jù)的場(chǎng)景。
設(shè)計(jì)思路
共享內(nèi)存區(qū):用于存儲(chǔ)數(shù)據(jù)。
互斥量:用于保護(hù)共享內(nèi)存區(qū),防止多個(gè)進(jìn)程同時(shí)訪問導(dǎo)致數(shù)據(jù)不一致。
信號(hào)量:用于通知對(duì)方有數(shù)據(jù)可用。
服務(wù)器實(shí)現(xiàn)
頭文件
#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();
// 向共享內(nèi)存中寫入數(shù)據(jù)
bool writeToSharedMemory(const QByteArray& data);
signals:
// 當(dāng)讀取到共享內(nèi)存中的數(shù)據(jù)時(shí)發(fā)出信號(hào)
void signalRead(QBuffer& buffer);
private slots:
// 檢查共享內(nèi)存中的數(shù)據(jù)
void checkSharedMemory();
private:
std::shared_ptr<QSharedMemory> m_sharedMemory; // 共享內(nèi)存
std::shared_ptr<QSystemSemaphore> m_semaphoreClient; // 信號(hào)量 - 客戶端發(fā)送
std::shared_ptr<QSystemSemaphore> m_semaphoreService; // 信號(hào)量- 服務(wù)器發(fā)送
bool m_bCreate = false; // 是否創(chuàng)建成功
bool m_bExit = false; // 是否退出
QThread m_listenThread; // 監(jiān)聽線程
};
#endif // SHAREDMEMORYSERVICE_Hcpp
#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))
{
// 創(chuàng)建共享內(nèi)存,大小為1024字節(jié)
if (!m_sharedMemory->create(1024)) {
qDebug() << "無法創(chuàng)建共享內(nèi)存:" << m_sharedMemory->errorString();
return;
}
m_bCreate = true;
// 移動(dòng)監(jiān)聽線程到單獨(dú)的線程中
QObject::connect(&m_listenThread, &QThread::started, this, &SharedMemoryService::checkSharedMemory, Qt::DirectConnection);
m_listenThread.start();
}
SharedMemoryService::~SharedMemoryService()
{
m_bExit = true;
m_semaphoreClient->release(1);
// 停止監(jiān)聽線程
m_listenThread.quit();
m_listenThread.wait();
}
void SharedMemoryService::checkSharedMemory()
{
if (!m_bCreate || !m_sharedMemory->isAttached())
return;
while (true)
{
// 等待信號(hào)量
if (m_semaphoreClient->acquire())
{
if (m_bExit)
{
break;
}
if (m_sharedMemory->lock())
{
// 讀取共享內(nèi)存中的數(shù)據(jù)
QBuffer buffer;
buffer.setData((char*)m_sharedMemory->data(), m_sharedMemory->size());
buffer.open(QIODevice::ReadOnly);
// 如果共享內(nèi)存中有數(shù)據(jù),則發(fā)出信號(hào)
if (buffer.size() > 0) {
emit signalRead(buffer);
// 清空共享內(nèi)存內(nèi)容
memset(m_sharedMemory->data(), 0, m_sharedMemory->size());
}
// 解鎖共享內(nèi)存
m_sharedMemory->unlock();
}
}
}
}
bool SharedMemoryService::writeToSharedMemory(const QByteArray& data)
{
if (!m_bCreate || !m_sharedMemory->isAttached())
{
qDebug() << "共享內(nèi)存未創(chuàng)建或未附加";
return false;
}
if (m_sharedMemory->lock()) {
// 將數(shù)據(jù)寫入共享內(nèi)存
memcpy(m_sharedMemory->data(), data.data(), qMin(data.size(), m_sharedMemory->size()));
// 釋放鎖
m_sharedMemory->unlock();
// 增加信號(hào)量計(jì)數(shù),通知監(jiān)聽線程有數(shù)據(jù)可用
m_semaphoreService->release(1);
return true;
}
qDebug() << "無法鎖定共享內(nèi)存";
return false;
}
調(diào)用
/// 創(chuàng)建共享內(nèi)存
void MainWindow::slotCrateBtn()
{
if (m_service)
{
return;
}
ui->btnCreate->setEnabled(false);
m_service = new SharedMemoryService();
// 連接信號(hào)槽,監(jiān)聽共享內(nèi)存中的數(shù)據(jù)
QObject::connect(m_service, &SharedMemoryService::signalRead, this, &MainWindow::slotRecv, Qt::DirectConnection);
}
/// 發(fā)送內(nèi)容
void MainWindow::slotSendBtn()
{
if (m_service == nullptr)
{
return;
}
// 向共享內(nèi)存中寫入數(shù)據(jù)
QByteArray data = ui->textEditSend->toPlainText().toLocal8Bit();
if (m_service->writeToSharedMemory(data))
{
qDebug() << "數(shù)據(jù)已成功寫入共享內(nèi)存";
}
else
{
qDebug() << "寫入共享內(nèi)存失敗";
}
}
/// 收到數(shù)據(jù)
void MainWindow::slotRecv(QBuffer& buffer)
{
QString text = buffer.data();
if (text.isEmpty())
{
return;
}
qDebug() << "接收到共享內(nèi)存中的數(shù)據(jù):" << text;
ui->textEdit->append(text);
}
客戶端實(shí)現(xiàn)
頭文件
#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();
// 向共享內(nèi)存中寫入數(shù)據(jù)
bool writeToSharedMemory(const QByteArray& data);
signals:
// 當(dāng)讀取到共享內(nèi)存中的數(shù)據(jù)時(shí)發(fā)出信號(hào)
void signalRead(QBuffer& buffer);
private slots:
// 處理共享內(nèi)存中的數(shù)據(jù)
void processSharedMemory();
private:
std::shared_ptr<QSharedMemory> m_sharedMemory; // 共享內(nèi)存
std::shared_ptr<QSystemSemaphore> m_semaphoreClient; // 信號(hào)量 - 客戶端發(fā)送
std::shared_ptr<QSystemSemaphore> m_semaphoreService; // 信號(hào)量- 服務(wù)器發(fā)送
bool m_bCreate = false; // 是否創(chuàng)建成功
bool m_bExit = false; // 是否退出
QThread m_listenThread; // 監(jiān)聽線程
};
#endif // SHAREDMEMORYCLIENT_Hcpp
#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() << "無法附加到共享內(nèi)存:" << m_sharedMemory->errorString();
return;
}
m_bCreate = true;
// 將處理方法移動(dòng)到監(jiān)聽線程中
moveToThread(&m_listenThread);
connect(&m_listenThread, &QThread::started, this, &SharedMemoryClient::processSharedMemory, Qt::DirectConnection);
// 啟動(dòng)監(jiān)聽線程
m_listenThread.start();
}
SharedMemoryClient::~SharedMemoryClient()
{
m_bExit = true;
m_semaphoreService->release(1);
// 停止監(jiān)聽線程
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;
// 鎖定共享內(nèi)存
if (m_sharedMemory->lock())
{
// 檢查共享內(nèi)存是否有數(shù)據(jù)
QBuffer buffer;
buffer.setData((char*)m_sharedMemory->data(), m_sharedMemory->size());
buffer.open(QIODevice::ReadOnly);
// 如果共享內(nèi)存中有數(shù)據(jù),則發(fā)出信號(hào)
if (buffer.size() > 0)
{
emit signalRead(buffer);
// 清空共享內(nèi)存內(nèi)容
memset(m_sharedMemory->data(), 0, m_sharedMemory->size());
}
// 解鎖共享內(nèi)存
m_sharedMemory->unlock();
}
}
}
}
bool SharedMemoryClient::writeToSharedMemory(const QByteArray& data)
{
if (!m_bCreate || !m_sharedMemory->isAttached())
{
qDebug() << "共享內(nèi)存未創(chuàng)建或未附加";
return false;
}
// 鎖定共享內(nèi)存
if (m_sharedMemory->lock())
{
// 將數(shù)據(jù)寫入共享內(nèi)存
memcpy(m_sharedMemory->data(), data.data(), qMin(data.size(), m_sharedMemory->size()));
// 解鎖共享內(nèi)存
m_sharedMemory->unlock();
// 釋放信號(hào)量,通知監(jiān)聽線程
m_semaphoreClient->release(1);
return true;
}
qDebug() << "無法鎖定共享內(nèi)存";
return false;
}
調(diào)用
/// 連接共享內(nèi)存
void MainWindow::slotCrateBtn()
{
if (m_client)
{
return;
}
ui->btnCreate->setEnabled(false);
m_client = new SharedMemoryClient();
// 連接信號(hào)槽,監(jiān)聽共享內(nèi)存中的數(shù)據(jù)
QObject::connect(m_client, &SharedMemoryClient::signalRead, this, &MainWindow::slotRecv, Qt::DirectConnection);
}
/// 發(fā)送內(nèi)容
void MainWindow::slotSendBtn()
{
if (m_client == nullptr)
{
return;
}
// 向共享內(nèi)存中寫入數(shù)據(jù)
QByteArray data = ui->textEditSend->toPlainText().toLocal8Bit();
if (m_client->writeToSharedMemory(data))
{
qDebug() << "數(shù)據(jù)已成功寫入共享內(nèi)存";
}
else
{
qDebug() << "寫入共享內(nèi)存失敗";
}
}
/// 收到數(shù)據(jù)
void MainWindow::slotRecv(QBuffer& buffer)
{
QString text = buffer.data();
if (text.isEmpty())
{
return;
}
qDebug() << "接收到共享內(nèi)存中的數(shù)據(jù):" << text;
ui->textEdit->append(text);
}
運(yùn)行效果

以上就是QT使用共享內(nèi)存實(shí)現(xiàn)進(jìn)程間通訊的詳細(xì)內(nèi)容,更多關(guān)于QT進(jìn)程間通訊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用udp發(fā)送>=128K的消息會(huì)報(bào)ENOBUFS的錯(cuò)誤的解決方法
在項(xiàng)目中選擇了unix域的數(shù)據(jù)報(bào)套接口。在使用過程中碰到了如下,問題:發(fā)送<128K的消息時(shí),客戶、進(jìn)程可以正常收發(fā)消息;發(fā)送>=128K的消息時(shí),發(fā)送端(sendto)返回ENOBUFS的錯(cuò)誤。下面小編來詳細(xì)說下2019-05-05
OpenCV實(shí)戰(zhàn)之基于Hu矩實(shí)現(xiàn)輪廓匹配
這篇文章主要介紹了利用C++ OpenCV實(shí)現(xiàn)基于Hu矩的輪廓匹配,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)OpenCV有一定的幫助,感興趣的可以學(xué)習(xí)一下2022-01-01
詳解C/C++實(shí)現(xiàn)各種字符轉(zhuǎn)換方法合集
這篇文章主要為大家詳細(xì)介紹了C/C++中實(shí)現(xiàn)各種字符轉(zhuǎn)換的方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++具有一定借鑒價(jià)值,需要的可以參考一下2022-09-09
新舊MFC版本實(shí)現(xiàn)CEdit透明的2種方法的實(shí)例代碼
新舊MFC版本實(shí)現(xiàn)CEdit透明的2種方法的實(shí)例代碼,需要的朋友可以參考一下2013-03-03

