Qt/C++,windows多進程demo

1. 項目概述

最近研究了一下Qt/C++框架下,windows版本的多進程編寫方法,實現了一個小demo。下面詳細介紹一下。
MultiProcessDemo是一個基于Qt框架實現的多進程應用程序示例,展示了如何在Windows平臺上通過共享內存和事件機制實現進程間通信。該項目主要由一個帶GUI的主進程和一個后臺存儲子進程組成,實現了進程間數據傳輸、子進程監控與自動重啟、優雅退出等功能。

2. 項目架構設計

2.1 整體架構圖

┌───────────────────────────┐      ┌─────────────────────────┐
│        主進程 (GUI)        │      │       存儲子進程        │
│  ┌─────────────────────┐  │      │  ┌───────────────────┐  │
│  │                     │  │      │  │                   │  │
│  │    MainWindow       │  │      │  │     Storage       │  │
│  │                     │  │      │  │                   │  │
│  └───────────┬─────────┘  │      │  └───────────┬───────┘  │
│              │            │      │              │         │
│              │ 寫入數據   │      │              │ 讀取數據 │
│              ▼            │      │              ▼         │
│  ┌─────────────────────┐  │      │  ┌───────────────────┐  │
│  │                     │  │      │  │                   │  │
│  │ SharedMemoryManager │<─┼──────┼─>│ SharedMemoryManager │  │
│  │  (創建共享內存)      │  │      │  │  (打開共享內存)      │  │
│  └─────────────────────┘  │      │  └───────────────────┘  │
│              │            │      │              │         │
│              │ 觸發事件   │      │              │ 等待事件 │
│              ▼            │      │              ▼         │
│  ┌─────────────────────┐  │      │  ┌───────────────────┐  │
│  │                     │  │      │  │                   │  │
│  │  數據事件 (DataEvent)│<─┼──────┼─>│  數據事件 (DataEvent)│  │
│  │  退出事件 (ExitEvent)│<─┼──────┼─>│  退出事件 (ExitEvent)│  │
│  └─────────────────────┘  │      │  └───────────────────┘  │
└───────────────────────────┘      └─────────────────────────┘▲                                  ▲│                                  │└──────────────────────────────────┘進程間通信

2.2 架構分層

  1. 應用層

    • 主進程:提供用戶界面,管理子進程生命周期
    • 存儲子進程:后臺處理數據,響應主進程指令
  2. 通信層

    • 共享內存:使用Windows API實現高效的進程間數據共享
    • 事件機制:用于進程間同步和通知
  3. 公共組件層

    • 共享定義和工具類:為多進程提供統一的接口和數據結構

3. 核心組件介紹

3.1 SharedMemoryManager

SharedMemoryManager是項目中實現共享內存通信的核心類,封裝了Windows API中與共享內存相關的操作。

主要功能

  • 創建/打開共享內存區域
  • 寫入數據到共享內存
  • 從共享內存讀取數據

關鍵實現

class SharedMemoryManager {
public:SharedMemoryManager(bool create);  // create=true表示創建共享內存,false表示打開已有共享內存~SharedMemoryManager();bool write(const std::string &data);  // 寫入數據std::string read();  // 讀取數據private:HANDLE m_hMapFile = nullptr;  // 共享內存句柄bool m_isOwner = false;  // 是否是共享內存的創建者
};

3.2 MainWindow

MainWindow是主進程的GUI界面,負責與用戶交互并向子進程發送數據。

主要功能

  • 提供用戶交互界面
  • 寫入數據到共享內存
  • 觸發數據事件通知子進程

關鍵實現

class MainWindow : public QMainWindow {Q_OBJECT
public:explicit MainWindow(HANDLE dataEvent, QWidget* parent = nullptr);
protected slots:void onButtonClicked();  // 處理按鈕點擊事件private:HANDLE m_dataEvent;  // 數據事件句柄SharedMemoryManager* m_sharedMemory;  // 共享內存管理器
};

3.3 Storage

Storage是存儲子進程的核心類,負責監聽事件和處理數據。

主要功能

  • 監聽退出事件和數據事件
  • 從共享內存讀取數據
  • 處理數據并執行相應操作

關鍵實現

class Storage {
public:explicit Storage(HANDLE exitEvent, HANDLE dataEvent);int run();  // 運行子進程的主循環private:HANDLE m_exitEvent;  // 退出事件句柄HANDLE m_dataEvent;  // 數據事件句柄SharedMemoryManager* m_sharedMemory;  // 共享內存管理器
};

4. 技術實現細節

4.1 進程創建與管理

項目使用Qt的QProcess類創建和管理子進程,實現了子進程的自動重啟和監控機制。

主要流程

  1. 主進程啟動時創建全局事件對象
  2. 解析命令行參數,決定是以主進程還是子進程模式運行
  3. 如果是主進程,則創建GUI并啟動存儲子進程
  4. 設置子進程信號連接,監控其狀態
  5. 實現定時器定期檢查子進程狀態,異常退出時自動重啟

關鍵代碼

// 啟動 storage 子進程
void startStorage(QProcess *proc, QApplication *app, bool isShuttingDown, std::function<void()> retryFunc) {if (isShuttingDown || proc->state() == QProcess::Running) {return;}QStringList args{"--storage"};proc->start(app->applicationFilePath(), args);if (!proc->waitForStarted(3000)) {QTimer::singleShot(2000, retryFunc);  // 啟動失敗時重試}
}// 監控 storage 子進程
void setupMonitor(QProcess *proc, QTimer *timer, std::function<void()> restartFunc, bool &isShuttingDown) {QObject::connect(timer, &QTimer::timeout, [=, &isShuttingDown]() {if (isShuttingDown) return;if (proc->state() != QProcess::Running) {restartFunc();  // 檢測到子進程未運行,嘗試重啟}});timer->start(5000);  // 每5秒檢查一次
}

4.2 進程間通信機制

項目使用Windows的共享內存和事件機制實現進程間通信,這種方式具有高效、低延遲的特點。

共享內存實現

  • 主進程創建共享內存區域
  • 子進程打開已創建的共享內存區域
  • 通過內存映射文件實現數據共享

事件機制實現

  • 使用全局命名事件實現進程間同步和通知
  • 定義兩種事件:數據事件(通知子進程有新數據)和退出事件(通知子進程退出)

關鍵代碼

// 創建全局退出事件
HANDLE createExitEvent() {return CreateEventW(nullptr, TRUE, FALSE, STORAGE_EXIT_EVENT_NAME);
}// 寫入數據并通知子進程
void MainWindow::onButtonClicked() {if (m_sharedMemory->write("abc")) {// 通知 storage 有新數據SetEvent(m_dataEvent);}
}// 子進程等待事件并處理
int Storage::run() {HANDLE handles[2] = {m_exitEvent, m_dataEvent};while (true) {DWORD ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);if (ret == WAIT_OBJECT_0)  // 退出事件{break;}else if (ret == WAIT_OBJECT_0 + 1)  // 數據事件{std::string data = m_sharedMemory->read();// 處理數據...ResetEvent(m_dataEvent);  // 重置事件}}return 0;
}

4.3 優雅退出機制

項目實現了優雅退出機制,確保主進程退出時能夠正確通知子進程并等待其退出。

主要流程

  1. 主進程接收到退出信號時,設置關閉標志并停止監控定時器
  2. 觸發退出事件通知子進程
  3. 等待子進程在指定時間內正常退出
  4. 如果子進程無響應,則強制終止

關鍵代碼

// 優雅退出 storage
void shutdownStorage(QProcess *proc, HANDLE exitEvent, QTimer *timer, bool &isShuttingDown) {isShuttingDown = true;timer->stop();if (proc->state() == QProcess::Running) {SetEvent(exitEvent);  // 通知子進程退出if (!proc->waitForFinished(5000)) {proc->kill();  // 強制終止proc->waitForFinished(1000);}}if (exitEvent) {CloseHandle(exitEvent);  // 關閉事件句柄}
}

5. 項目結構說明

項目采用清晰的目錄結構,將不同功能模塊分離,便于維護和擴展。

├── CMakeLists.txt       # 項目構建配置
├── main.cpp             # 程序入口點
├── common/              # 公共組件
│   ├── common.h         # 共享定義和常量
│   ├── sharedmemory_manager.cpp  # 共享內存管理器實現
│   └── sharedmemory_manager.h    # 共享內存管理器定義
├── dataview/            # 主進程界面相關
│   ├── mainwindow.cpp   # 主窗口實現
│   └── mainwindow.h     # 主窗口定義
└── storage/             # 存儲子進程相關├── storage.cpp      # 存儲子進程實現└── storage.h        # 存儲子進程定義

6. 關鍵技術點分析

6.1 共享內存的安全性考慮

共享內存在提供高效通信的同時,也帶來了一些安全性問題,本項目主要考慮了以下幾點:

  • 使用互斥事件確保數據讀寫的同步
  • 限制共享內存大小,防止內存濫用
  • 進程異常退出時的資源清理

6.2 子進程監控與自動恢復

項目實現了完善的子進程監控機制,確保系統的穩定性和可靠性:

  • 定時檢查子進程狀態
  • 捕獲子進程異常退出信號
  • 實現自動重啟邏輯,保證服務可用性

6.3 Windows API與Qt框架的融合

項目成功融合了Windows API和Qt框架的優勢:

  • 使用Qt框架快速構建GUI和管理應用程序生命周期
  • 利用Windows原生API實現高效的進程間通信
  • 通過信號槽機制簡化事件處理和組件間通信

6.4 為何不使用QSharedMemory

項目選擇自行實現基于Windows API的SharedMemoryManager而非使用Qt提供的QSharedMemory類,主要是通過直接調用底層 API(如 CreateFileMappingW),可以針對 Windows 系統特性進行優化,減少 Qt 封裝帶來的開銷,同時獲得更靈活的共享內存控制和更高效的進程間同步能力。

7. 多進程架構的優勢

本項目采用多進程架構而非傳統的多線程架構,主要基于以下技術優勢:

  1. 更高的穩定性和容錯性:一個進程崩潰不會影響其他進程的運行,提高了整個應用的穩定性
  2. 更好的資源隔離:進程間內存空間完全隔離,避免了共享內存訪問沖突和資源競爭問題
  3. 充分利用多核性能:多進程可以更有效地利用多核CPU資源,實現真正的并行計算

雖然多進程架構在進程間通信上會有一定開銷,但對于需要高穩定性、強隔離性的應用場景,這些優勢遠大于其帶來的額外成本。

8. 程序輸出展示

在這里插入圖片描述

9. 總結與展望

MultiProcessDemo項目成功實現了基于Qt的多進程應用架構,展示了如何在Windows平臺上實現高效的進程間通信。該項目的設計理念和實現方法可以應用于需要將UI和后臺處理分離的應用場景,有助于提高應用程序的穩定性和響應性能。

未來改進方向

  1. 共享內存隊列:目前共享內存通信使用的是簡單的字符串傳遞,考慮引入隊列機制,支持批量數據傳輸。
  2. 增加其他子進程:本demo只是實現了基本的功能,后續可根據需求新增其他子進程。。

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

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

相關文章

Android SystemServer 系列專題【篇五:UserController用戶狀態控制】

本篇接著SystemServer的啟動流程&#xff0c;圍繞SystemServer最后階段關于主用戶的啟動和解鎖的流程&#xff0c;作為切入點&#xff0c;來看看SystemServer是如何講用戶狀態同步到所有的系統級服務中。ssm.onStartUserssm.onUnlockingUserssm.onUnlockedUser本篇先介紹UserCo…

推薦使用 pnpm 而不是 npm

npm 的局限性 磁盤空間浪費在 npm 早期版本中&#xff0c;每個項目的node_modules目錄都會完整復制所有依賴包&#xff0c;即使多個項目依賴同一個包的相同版本&#xff0c;也會重復存儲。這導致磁盤空間被大量占用&#xff0c;隨著項目數量的增加&#xff0c;存儲成本顯著上升…

Transformer實戰(18)——微調Transformer語言模型進行回歸分析

Transformer實戰&#xff08;18&#xff09;——微調Transformer語言模型進行回歸分析0. 前言1. 回歸模型2. 數據處理3. 模型構建與訓練4. 模型推理小結系列鏈接0. 前言 在自然語言處理領域中&#xff0c;預訓練 Transformer 模型不僅能勝任離散類別預測&#xff0c;也可用于連…

【Linux】【實戰向】Linux 進程替換避坑指南:從理解 bash 阻塞等待,到親手實現能執行 ls/cd 的 Shell

前言&#xff1a;歡迎各位光臨本博客&#xff0c;這里小編帶你直接手撕&#xff0c;文章并不復雜&#xff0c;愿諸君耐其心性&#xff0c;忘卻雜塵&#xff0c;道有所長&#xff01;&#xff01;&#xff01;&#xff01; IF’Maxue&#xff1a;個人主頁&#x1f525; 個人專欄…

linux常用命令 (3)——系統包管理

博客主頁&#xff1a;christine-rr-CSDN博客 ????? ?? hi&#xff0c;大家好&#xff0c;我是christine-rr ! 今天來分享一下linux常用命令——系統包管理 目錄linux常用命令---系統包管理&#xff08;一&#xff09;Debian 系發行版&#xff08;Ubuntu、Debian、Linux …

YOLOv8 mac-intel芯片 部署指南

&#x1f680; 在 Jupyter Notebook 和 PyCharm 中使用 Conda 虛擬環境&#xff08;YOLOv8 部署指南&#xff0c;Python 3.9&#xff09; YOLOv8 是 Ultralytics 開源的最新目標檢測模型&#xff0c;輕量高效&#xff0c;支持分類、檢測、分割等多種任務。 在 Mac&#xff08;…

【高等數學】第十一章 曲線積分與曲面積分——第六節 高斯公式 通量與散度

上一節&#xff1a;【高等數學】第十一章 曲線積分與曲面積分——第五節 對坐標的曲面積分 總目錄&#xff1a;【高等數學】 目錄 文章目錄1. 高斯公式2. 沿任意閉曲面的曲面積分為零的條件3. 通量與散度1. 高斯公式 設空間區域ΩΩΩ是由分片光滑的閉曲面ΣΣΣ所圍成&#x…

IDEA試用過期,無法登錄,重置方法

IDEA過期&#xff0c;重置方法: IntelliJ IDEA 2024.2.0.2 (親測有效) 最新Idea重置辦法!&#xff1a; 方法一&#xff1a; 1、刪除C:\Users\{用戶名}\AppData\Local\JetBrains\IntelliJIdea2024.2 下所有文件(注意&#xff1a;是子目錄全部刪除) 2、刪除C:\Users\{用戶名}\App…

創建用戶自定義橋接網絡并連接容器

1.創建用戶自定義的 alpine-net 網絡[roothost1 ~]# docker network create --driver bridge alpine-net 9f6d634e6bd7327163a9d83023e435da6d61bc6cf04c9d96001d1b64eefe4a712.列出 Docker 主機上的網絡[roothost1 ~]# docker network ls NETWORK ID NAME DRIVER …

Vue3 + Vite + Element Plus web轉為 Electron 應用,解決無法登錄、隱藏自定義導航欄

如何在vue3 Vite Element Plus搭好的架構下轉為 electron應用呢&#xff1f; https://www.electronjs.org/zh/docs/latest/官方文檔 https://www.electronjs.org/zh/docs/latest/ 第一步&#xff1a;安裝 electron相關依賴 npm install electron electron-builder concurr…

qt QAreaLegendMarker詳解

1. 概述QAreaLegendMarker 是 Qt Charts 模塊中的一部分&#xff0c;用于在圖例&#xff08;Legend&#xff09;中表示 QAreaSeries 的標記。它負責顯示區域圖的圖例項&#xff0c;通常包含區域顏色樣例和對應的描述文字。圖例標記和對應的區域圖關聯&#xff0c;顯示區域的名稱…

linux 函數 kstrtoul

kstrtoul 函數概述 kstrtoul 是 Linux 內核中的一個函數&#xff0c;用于將字符串轉換為無符號長整型&#xff08;unsigned long&#xff09;。該函數定義在 <linux/kernel.h> 頭文件中&#xff0c;常用于內核模塊中解析用戶空間傳遞的字符串參數。 函數原型 int kstrtou…

LLM(三)

一、人類反饋的強化學習&#xff08;RLHF&#xff09;微調的目標是通過指令&#xff0c;包括路徑方法&#xff0c;進一步訓練你的模型&#xff0c;使他們更好地理解人類的提示&#xff0c;并生成更像人類的回應。RLHF&#xff1a;使用人類反饋微調型語言模型&#xff0c;使用強…

DPO vs PPO,偏好優化的兩條技術路徑

1. 背景在大模型對齊&#xff08;alignment&#xff09;里&#xff0c;常見的兩類方法是&#xff1a;PPO&#xff1a;強化學習經典算法&#xff0c;OpenAI 在 RLHF 里用它來“用獎勵模型更新策略”。DPO&#xff1a;2023 年提出的新方法&#xff08;參考論文《Direct Preferenc…

BLE6.0信道探測,如何重構物聯網設備的距離感知邏輯?

在物聯網&#xff08;IoT&#xff09;無線通信技術快速滲透的當下&#xff0c;實現人與物、物與物之間對物理距離的感知響應能力已成為提升設備智能高度與人們交互體驗的關鍵所在。當智能冰箱感知用戶靠近而主動亮屏顯示內部果蔬時、當門禁系統感知到授權人士靠近而主動開門時、…

【計算機 UTF-8 轉換為本地編碼的含義】

UTF-8 轉換為本地編碼的含義 詳細解釋一下"UTF-8轉換為本地編碼"的含義以及為什么在處理中文時這很重要。 基本概念 UTF-8 編碼 國際標準&#xff1a;UTF-8 是一種能夠表示世界上幾乎所有字符的 Unicode 編碼方式跨平臺兼容&#xff1a;無論在哪里&#xff0c;UTF-8 …

4.6 變體

1.變體簡介 2.為什么需要變體 3.變體是如何產生的 4.變體帶來的麻煩 5.multi_compile和shader_feature1.變體簡介 比如我們開了一家餐廳, 你有一本萬能的菜單(Shader源代碼), 上面包含了所有可能的菜式; 但是顧客每次來點餐時, 不可能將整本菜單都做一遍, 他們會根據今天有沒有…

猿輔導Android開發面試題及參考答案(下)

為什么開發中要使用線程池,而不是直接創建線程(如控制線程數量、復用線程、降低開銷)? 開發中優先使用線程池而非直接創建線程,核心原因是線程池能優化線程管理、降低資源消耗、提高系統穩定性,而直接創建線程存在難以解決的缺陷,具體如下: 控制線程數量,避免資源耗盡…

【網絡通信】IP 地址深度解析:從技術原理到企業級應用?

IP 地址深度解析&#xff1a;從技術原理到企業級應用? 文章目錄IP 地址深度解析&#xff1a;從技術原理到企業級應用?前言一、基礎認知&#xff1a;IP 地址的技術定位與核心特性?1.1 定義與網絡層角色1.2 核心屬性與表示法深化二、地址分類&#xff1a;從類別劃分到無類別路…

grafana實踐

一、如何找到grafana的插件目錄 whereis grafana grafana: /etc/grafana /usr/share/grafana插件安裝目錄、默認安裝目錄&#xff1a; 把vertamedia-clickhouse-datasource-3.4.4.zip解壓到下面目錄&#xff0c;然后重啟就可以了 /var/lib/grafana/plugins# 6. 設置權限 sudo …