自学内容网 自学内容网

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)!