QT 使用共享內存 實現進程間通訊

QSharedMemory如果兩個進程運行在同一臺機器上,且對性能要求非常高(如實時數據共享、圖像渲染等),建議使用共享內存。

優點:
  • 高性能: 共享內存是進程間通信的最快方式之一,因為數據直接在內存中共享,不需要經過內核的系統調用或網絡協議棧。
  • 低延遲: 由于數據直接在內存中傳遞,延遲非常低,適合需要高性能的場景(如實時數據處理、圖像渲染等)。
  • 簡單數據共享: 適合兩個進程需要頻繁訪問相同數據的場景。

設計思路

  1. 共享內存區:用于存儲數據。
  2. 互斥量:用于保護共享內存區,防止多個進程同時訪問導致數據不一致。
  3. 信號量:用于通知對方有數據可用。

服務器實現

頭文件

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

運行效果:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/62717.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/62717.shtml
英文地址,請注明出處:http://en.pswp.cn/web/62717.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在Scala中對隱式轉換格式與作用

隱式對象 格式&#xff1a;implicit object 作用&#xff1a;給函數的默認參數提供隱式值 object Scala12______10 { // case class DataBase(driver: String, url: String) // // implicit object mySql extends DataBase("mysql", "localhost:300") //…

go build command

文章目錄 1.簡介2.格式3.選項4.示例5.小結參考文獻 1.簡介 go build 是 Go 語言工具鏈中的一個命令&#xff0c;它用于編譯 Go 源代碼并生成可執行文件。 2.格式 go build [-o output] [build flags] [packages]可選的 -o 選項強制 build 將生成的可執行文件或對象寫入指定的…

OpenCV實驗:圖片加水印

第二篇&#xff1a;圖片添加水印&#xff08;加 logo&#xff09; 1. 實驗原理 水印原理&#xff1a; 圖片添加水印是圖像疊加的一種應用&#xff0c;分為透明水印和不透明水印。水印的實現通常依賴于像素值操作&#xff0c;將水印圖片融合到目標圖片中&#xff0c;常用的方法…

WinDbg 中使用 !process 命令

PROCESS 81a979d0 SessionId: 0 Cid: 0210 Peb: 7ffda000 ParentCid: 063cDirBase: 145b9000 ObjectTable: e12fed70 HandleCount: 53.Image: Dbgview.exe 1. PROCESS 81a979d0 意義&#xff1a;PROCESS 是該進程對象的內核地址。用途&#xff1a;可以使用這個地址獲…

深入解析下oracle的number底層存儲格式

oracle數據庫中&#xff0c;number數據類型用來存儲數值數據&#xff0c;它既可以存儲負數數值&#xff0c;也可以存儲正數數值。相對于其他類型數據&#xff0c;number格式的數據底層存儲格式要復雜得多。今天我們就詳細探究下oracle的number底層存儲格式。 一、環境搭建 1.…

SparkSQL與Hive的整合

文章目錄 SparkSQL與Hive的整合1.1. Spark On Hive1.1.1. Hive的準備工作1.1.2. Spark的準備工作1.1.3. Spark代碼開發1.1.4. Spark On Hive案例 1.2. Hive On Spark1.3. SparkSQL命令行1.4. SparkSQL分布式查詢引擎1.4.1. 開啟ThriftServer服務1.4.2. beeline連接ThriftServer…

(持續更新)linux網絡編程中需要注意的內核參數與網絡機制

目錄 零、基本說明 一、內核參數 二、相關機制 1、GRO &#xff08;1&#xff09;適用場景 &#xff08;2&#xff09;優缺點 &#xff08;3&#xff09;相關操作 2、Nagle 算法 &#xff08;1&#xff09;基本規則 &#xff08;2&#xff09;優缺點 &#xff08;3&…

DevExpress WPF中文教程:Grid - 如何移動和調整列大小?(一)

DevExpress WPF擁有120個控件和庫&#xff0c;將幫助您交付滿足甚至超出企業需求的高性能業務應用程序。通過DevExpress WPF能創建有著強大互動功能的XAML基礎應用程序&#xff0c;這些應用程序專注于當代客戶的需求和構建未來新一代支持觸摸的解決方案。 無論是Office辦公軟件…

Matlab筆記---clear、clc、clear all應用

在MATLAB中&#xff0c;clear、clc 和 clear all 是三個常用的命令&#xff0c;它們各自有不同的作用&#xff1a; clc&#xff1a; clc 命令用于清除MATLAB命令窗口中的所有輸出。它不會刪除任何變量、函數或文件&#xff0c;只是清除屏幕上的顯示內容&#xff0c;讓你可以更…

銘記一次項目重大事故

在程序的世界里&#xff0c;bug 就像隱藏在暗處的小怪獸&#xff0c;時不時跳出來搗亂。而職業生涯中&#xff0c;總有那么一個或幾個 bug 讓我們刻骨銘心。它或許讓項目差點夭折&#xff0c;或許讓你熬了無數個通宵&#xff0c;或許有著離奇的出現方式和曲折的解決過程。無論是…

Qt 一個簡單的QChart 繪圖

Qt 一個簡單的QChart 繪圖 先上程序運行結果圖&#xff1a; “sample9_1QChart.h” 文件代碼如下&#xff1a; #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample9_1QChart.h"#include <QtCharts> //必須這么設置 QT_CHARTS_USE_NAME…

分布式事物XA、BASE、TCC、SAGA、AT

分布式事務——Seata 一、Seata的架構&#xff1a; 1、什么是Seata&#xff1a; 它是一款分布式事務解決方案。官網查看&#xff1a;Seata 2.執行過程 在分布式事務中&#xff0c;會有一個入口方法去調用各個微服務&#xff0c;每一個微服務都有一個分支事務&#xff0c;因…

MySQL為什么使用B+樹來作索引

我來詳細解釋一下B樹的結構和特點。 graph TDA[根節點 40|70] --> B[20|30]A --> C[50|60]A --> D[80|90]B --> E[10|15]B --> F[25|28]B --> G[35|38]C --> H[45|48]C --> I[55|58]C --> J[65|68]D --> K[75|78]D --> L[85|88]D --> M[9…

python 下載 b站視頻 和音頻

video_bvid&#xff1a; import os import requests import json import re from bs4 import BeautifulSoup import subprocess # from detail_video import video_bvid# video_bvid 是一個從外部得到的單個視頻ID video_bvid BV1cx421Q7veclass BilibiliVideoAudio:def __in…

2024年06月中國電子學會青少年軟件編程(Python)等級考試試卷(五級)答案 + 解析

青少年軟件編程(python)等級考試試卷(五級) 一、單選題(共25題,共50分) range()函數的基本用法是什么?( ) A. 生成一個等差數列 B. 生成一個隨機數列 C. 生成一個遞增數列 D. 生成一個遞減數列 正確答案:A 答案解析:range() 函數用于生成一個等差數列,其中起始值、…

以太網鏈路詳情

文章目錄 1、交換機1、常見的概念1、沖突域2、廣播域3、以太網卡1、以太網卡幀 4、mac地址1、mac地址表示2、mac地址分類3、mac地址轉換為二進制 2、交換機的工作原理1、mac地址表2、交換機三種數據幀處理行為3、為什么會泛洪4、轉發5、丟棄 3、mac表怎么獲得4、同網段數據通信…

Shell編程 腳本的運行方式與注釋

目錄 shell腳本的運行方式 1. 路徑運行 2.bash或sh加腳本運行 ?編輯 3.source在加腳本路徑運行 shell腳本注釋 單行注釋 多行注釋 shell腳本的運行方式 我們在/usr/etc/demo01目錄下新建了一個腳本 a.sh &#xff0c;腳本內容是要求輸出數字1&#xff0c;怎么運行呢 1…

獲取淘寶商品評論數據的API應用:市場調研|產品更新|用戶數據

下面是一段我用item_review&#xff08;獲取商品評論數據&#xff09;抓來的商品評論數據&#xff1a; "items": {"total_results": 375,"totalpage": 38,"page_size": 10,"page": "1","item": [{&quo…

智算網絡中Scale-out和Scale-up網絡的技術原理

智算網絡中Scale-out網絡和Scale-up網絡的本質區別是什么&#xff1f; 一、什么是智算中心的Scale-out網絡和Scale-up網絡 數據中心網絡總體上可分為兩大類&#xff1a;通算網絡和智算網絡。通算網絡主要用于支持傳統的計算任務和應用&#xff0c;如企業的IT系統、網站托管、電…

HCIA筆記7--OSPF協議入門

文章目錄 0. 路由分類1. OSPF介紹1.1 概念1.2 報文類型 2. 鄰接關系的建立2.1 鄰居關系的建立2.2 鄰接關系的形成2.3 ospf狀態機 3. DR與BDR3.1 為什么要有DR和BDR&#xff1f;3.2 DR和BDR的選舉原則 4. ospf的配置4.1 內部優先級 5. 問題5.1 三層環路如何解決&#xff1f; Ref…