1. 项目概述
最近研究了一下Qt/C++框架下,windows版本的多进程编写方法,实现了一个小demo。下面详细介绍一下。
MultiProcessDemo是一个基于Qt框架实现的多进程应用程序示例,展示了如何在Windows平台上通过共享内存和事件机制实现进程间通信。该项目主要由一个带GUI的主进程和一个后台存储子进程组成,实现了进程间数据传输、子进程监控与自动重启、优雅退出等功能。
2. 项目架构设计
2.1 整体架构图
┌───────────────────────────┐ ┌─────────────────────────┐
│ 主进程 (GUI) │ │ 存储子进程 │
│ ┌─────────────────────┐ │ │ ┌───────────────────┐ │
│ │ │ │ │ │ │ │
│ │ MainWindow │ │ │ │ Storage │ │
│ │ │ │ │ │ │ │
│ └───────────┬─────────┘ │ │ └───────────┬───────┘ │
│ │ │ │ │ │
│ │ 写入数据 │ │ │ 读取数据 │
│ ▼ │ │ ▼ │
│ ┌─────────────────────┐ │ │ ┌───────────────────┐ │
│ │ │ │ │ │ │ │
│ │ SharedMemoryManager │<─┼──────┼─>│ SharedMemoryManager │ │
│ │ (创建共享内存) │ │ │ │ (打开共享内存) │ │
│ └─────────────────────┘ │ │ └───────────────────┘ │
│ │ │ │ │ │
│ │ 触发事件 │ │ │ 等待事件 │
│ ▼ │ │ ▼ │
│ ┌─────────────────────┐ │ │ ┌───────────────────┐ │
│ │ │ │ │ │ │ │
│ │ 数据事件 (DataEvent)│<─┼──────┼─>│ 数据事件 (DataEvent)│ │
│ │ 退出事件 (ExitEvent)│<─┼──────┼─>│ 退出事件 (ExitEvent)│ │
│ └─────────────────────┘ │ │ └───────────────────┘ │
└───────────────────────────┘ └─────────────────────────┘▲ ▲│ │└──────────────────────────────────┘进程间通信
2.2 架构分层
-
应用层
- 主进程:提供用户界面,管理子进程生命周期
- 存储子进程:后台处理数据,响应主进程指令
-
通信层
- 共享内存:使用Windows API实现高效的进程间数据共享
- 事件机制:用于进程间同步和通知
-
公共组件层
- 共享定义和工具类:为多进程提供统一的接口和数据结构
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类创建和管理子进程,实现了子进程的自动重启和监控机制。
主要流程:
- 主进程启动时创建全局事件对象
- 解析命令行参数,决定是以主进程还是子进程模式运行
- 如果是主进程,则创建GUI并启动存储子进程
- 设置子进程信号连接,监控其状态
- 实现定时器定期检查子进程状态,异常退出时自动重启
关键代码:
// 启动 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 优雅退出机制
项目实现了优雅退出机制,确保主进程退出时能够正确通知子进程并等待其退出。
主要流程:
- 主进程接收到退出信号时,设置关闭标志并停止监控定时器
- 触发退出事件通知子进程
- 等待子进程在指定时间内正常退出
- 如果子进程无响应,则强制终止
关键代码:
// 优雅退出 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. 多进程架构的优势
本项目采用多进程架构而非传统的多线程架构,主要基于以下技术优势:
- 更高的稳定性和容错性:一个进程崩溃不会影响其他进程的运行,提高了整个应用的稳定性
- 更好的资源隔离:进程间内存空间完全隔离,避免了共享内存访问冲突和资源竞争问题
- 充分利用多核性能:多进程可以更有效地利用多核CPU资源,实现真正的并行计算
虽然多进程架构在进程间通信上会有一定开销,但对于需要高稳定性、强隔离性的应用场景,这些优势远大于其带来的额外成本。
8. 程序输出展示
9. 总结与展望
MultiProcessDemo项目成功实现了基于Qt的多进程应用架构,展示了如何在Windows平台上实现高效的进程间通信。该项目的设计理念和实现方法可以应用于需要将UI和后台处理分离的应用场景,有助于提高应用程序的稳定性和响应性能。
未来改进方向
- 共享内存队列:目前共享内存通信使用的是简单的字符串传递,考虑引入队列机制,支持批量数据传输。
- 增加其他子进程:本demo只是实现了基本的功能,后续可根据需求新增其他子进程。。