qt应用程序崩溃后自动拉起进程且保存dmp文件
接上一篇继续,上一篇提到如果程序崩溃不容易复现难以短时间定位解决,希望崩溃后自动拉起进程,有几种方案可供选择。
1. 使用监控进程(推荐方案)
// monitor.cpp (监控程序)
#include <QCoreApplication>
#include <QProcess>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
class ProcessMonitor : public QObject
{
Q_OBJECT
public:
ProcessMonitor(const QString& programPath)
: m_programPath(programPath)
{
startProcess();
}
private slots:
void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "进程退出,代码:" << exitCode << "状态:" << exitStatus;
// 延迟1秒后重启进程
QTimer::singleShot(1000, this, &ProcessMonitor::startProcess);
}
private:
void startProcess()
{
if (m_process) {
delete m_process;
}
m_process = new QProcess(this);
// 设置工作目录
QFileInfo fi(m_programPath);
m_process->setWorkingDirectory(fi.absolutePath());
// 连接信号
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &ProcessMonitor::handleProcessFinished);
// 启动进程
m_process->start(m_programPath);
qDebug() << "启动程序:" << m_programPath;
}
private:
QString m_programPath;
QProcess* m_process = nullptr;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 指定要监控的程序路径
QString programPath = "YourApp.exe";
ProcessMonitor monitor(programPath);
return a.exec();
}
2. 使用批处理脚本:
:: restart.bat
:start
start /wait YourApp.exe
goto start
3. 自恢复方案(在主程序中实现)
// main.cpp
#include <QApplication>
#include <QProcess>
#include <QDebug>
void restartApplication()
{
QProcess::startDetached(QApplication::applicationFilePath());
}
class CrashHandler
{
public:
static void installHandler()
{
SetUnhandledExceptionFilter(handleCrash);
}
private:
static LONG WINAPI handleCrash(EXCEPTION_POINTERS* pExp)
{
// 生成 DMP 文件
createMiniDump(pExp);
// 启动新进程
restartApplication();
return EXCEPTION_EXECUTE_HANDLER;
}
static void createMiniDump(EXCEPTION_POINTERS* pExp)
{
// DMP 生成代码(同前例)
}
};
int main(int argc, char *argv[])
{
// 安装崩溃处理器
CrashHandler::installHandler();
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
4. 使用 Windows 服务
// service.cpp
#include <windows.h>
#include <QCoreApplication>
#include <QProcess>
class WindowsService : public QObject
{
Q_OBJECT
public:
void start()
{
// 创建定时器检查进程
m_checkTimer = new QTimer(this);
connect(m_checkTimer, &QTimer::timeout, this, &WindowsService::checkProcess);
m_checkTimer->start(5000); // 每5秒检查一次
startProcess();
}
private slots:
void checkProcess()
{
if (m_process && m_process->state() == QProcess::NotRunning) {
qDebug() << "进程已停止,正在重启...";
startProcess();
}
}
private:
void startProcess()
{
if (m_process) {
delete m_process;
}
m_process = new QProcess(this);
m_process->start("YourApp.exe");
}
private:
QTimer* m_checkTimer = nullptr;
QProcess* m_process = nullptr;
};
5. 进程互相监控方案
// 在主程序中添加监控功能
class MainApp : public QMainWindow
{
Q_OBJECT
public:
MainApp()
{
// 启动监控进程
startMonitor();
// 创建心跳定时器
m_heartbeatTimer = new QTimer(this);
connect(m_heartbeatTimer, &QTimer::timeout, this, &MainApp::sendHeartbeat);
m_heartbeatTimer->start(1000); // 每秒发送心跳
}
private:
void startMonitor()
{
QProcess::startDetached("monitor.exe", QStringList() << QString::number(QCoreApplication::applicationPid()));
}
void sendHeartbeat()
{
// 通过共享内存或其他IPC机制发送心跳
// ...
}
private:
QTimer* m_heartbeatTimer = nullptr;
};
注意事项:
1.避免无限重启循环
// 添加重启次数限制
int restartCount = 0;
const int MAX_RESTARTS = 3;
if (restartCount < MAX_RESTARTS) {
restartCount++;
startProcess();
} else {
qDebug() << "达到最大重启次数,停止重启";
}
2.记录崩溃日志
void logCrash(const QString& reason)
{
QFile file("crash_log.txt");
if (file.open(QIODevice::Append | QIODevice::Text)) {
QTextStream stream(&file);
stream << QDateTime::currentDateTime().toString()
<< ": " << reason << "\n";
}
}
3.清理资源
// 在重启前确保资源被正确释放
void cleanupBeforeRestart()
{
// 关闭文件句柄
// 释放共享资源
// 保存必要的状态
}
选择建议:
- 对于普通应用程序,推荐使用独立的监控进程方案
- 对于服务器程序,可以考虑使用 Windows 服务
- 对于简单应用,可以使用批处理脚本方案
- 需要考虑崩溃原因,避免无限重启导致的问题
实战
下面展示一个会崩溃的 Qt 程序示例,并说明如何生成dmp文件并且重新将进程拉起,我使用的是 自恢复方案(在主程序中实现)。
1. 示例程序
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QDebug>
#include <windows.h>
#include <dbghelp.h>
#include <QDateTime>
#include <QProcess>
class CrashHandler
{
public:
static void installHandler()
{
SetUnhandledExceptionFilter(handleCrash);
}
private:
static LONG WINAPI handleCrash(EXCEPTION_POINTERS* pExp)
{
// 生成 DMP 文件
createMiniDump(pExp);
// 启动新进程
restartApplication();
return EXCEPTION_EXECUTE_HANDLER;
}
static void createMiniDump(EXCEPTION_POINTERS* pExp)
{
QString dumpPath = QCoreApplication::applicationDirPath() +
"/crash_" +
QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") +
".dmp";
HANDLE hDumpFile = CreateFileW(dumpPath.toStdWString().c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDumpFile != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pExp;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
// 生成更详细的DMP文件
MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)(
MiniDumpNormal |
MiniDumpWithFullMemory |
MiniDumpWithHandleData |
MiniDumpWithThreadInfo |
MiniDumpWithProcessThreadData
);
MiniDumpWriteDump(GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
dumpType,
&dumpInfo,
NULL,
NULL);
CloseHandle(hDumpFile);
}
}
static void restartApplication()
{
QProcess::startDetached(QApplication::applicationFilePath());
exit(1);
}
};
// 故意制造崩溃的类
class CrashTest : public QMainWindow
{
public:
CrashTest()
{
QPushButton* btn = new QPushButton("click", this);
setCentralWidget(btn);
connect(btn, &QPushButton::clicked, this, &CrashTest::makeCrash);
resize(200, 100);
}
void makeCrash()
{
// 方式1:空指针访问
int* p = nullptr;
*p = 100;
// 方式2:数组越界
// int arr[5];
// arr[1000000] = 1;
// 方式3:除零错误
// int a = 0;
// int b = 100 / a;
}
};
int main(int argc, char *argv[])
{
// 安装崩溃处理器
CrashHandler::installHandler();
QApplication a(argc, argv);
CrashTest w;
w.show();
return a.exec();
}
2. 项目文件配置
# crash_test.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
CONFIG += force_debug_info # 强制生成调试信息
SOURCES += main.cpp
# 添加 dbghelp 库
LIBS += -ldbghelp
# 生成PDB文件的配置
QMAKE_CXXFLAGS_RELEASE += /Zi
QMAKE_LFLAGS_RELEASE += /DEBUG /OPT:REF
3. 编译和运行步骤
1.使用 Qt Creator 打开项目
2.选择 Release 模式编译
3.运行程序
4.点击"点击崩溃"按钮
5.程序会崩溃并在程序目录生成 .dmp 文件
这个例程提供了一个完整的崩溃捕获和进程自动拉起的功能。完整工程我放在了
项目链接
原文地址:https://blog.csdn.net/qq385105501/article/details/144311237
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!