首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

軟件看門狗實現程序存活監控與自動重啟

     編輯:VC 教學

架構設計

看門狗作為獨立進程監控目標應用,核心職責:進程存在性檢查、響應性檢測、超閾值重啟、系統級恢復。採用"分離關注點"設計,看門狗與被監控程序解耦。

關鍵技術實現

1. 進程存在性檢測

BOOL IsProcessRunning(DWORD pid) {
    HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    if (!hProcess) return FALSE;
    DWORD result = WaitForSingleObject(hProcess, 0);
    CloseHandle(hProcess);
    return result == WAIT_TIMEOUT;  // 仍在運行
}

2. 響應性檢測 (Hung App Detection)

// 動態導入未文檔API
typedef BOOL (WINAPI *PFN_IsHungAppWindow)(HWND);
typedef BOOL (WINAPI *PFN_IsHungThread)(DWORD);

PFN_IsHungAppWindow pIsHungAppWindow = nullptr;
PFN_IsHungThread pIsHungThread = nullptr;

void InitHungDetection() {
    HMODULE hUser32 = GetModuleHandleW(L"USER32.DLL");
    pIsHungAppWindow = (PFN_IsHungAppWindow)GetProcAddress(hUser32, "IsHungAppWindow");
    pIsHungThread = (PFN_IsHungThread)GetProcAddress(hUser32, "IsHungThread");
}

BOOL IsWindowHung(HWND hwnd) {
    if (pIsHungAppWindow) return pIsHungAppWindow(hwnd);
    return FALSE;
}

BOOL IsThreadHung(DWORD threadId) {
    if (pIsHungThread) return pIsHungThread(threadId);
    return FALSE;
}

3. 綜合監控邏輯

struct WatchdogConfig {
    std::wstring targetExePath;
    DWORD checkIntervalMs = 5000;      // 檢查間隔
    DWORD maxHungCount = 3;            // 最大無響應容忍次數
    BOOL rebootOnExceed = FALSE;       // 超限是否重啟系統
};

class Watchdog {
    WatchdogConfig config;
    DWORD hungCount = 0;
    DWORD targetPid = 0;
    HANDLE hTargetProcess = nullptr;

public:
    void Run() {
        while (true) {
            Sleep(config.checkIntervalMs);
            if (!EnsureTargetRunning()) continue;
            if (CheckHung()) {
                if (++hungCount >= config.maxHungCount) {
                    if (config.rebootOnExceed) InitiateSystemReboot();
                    else RestartTarget();
                    hungCount = 0;
                }
            } else {
                hungCount = 0;  // 重置計數器
            }
        }
    }

private:
    BOOL EnsureTargetRunning() {
        if (targetPid && IsProcessRunning(targetPid)) return TRUE;
        // 啟動新進程
        STARTUPINFOW si = { sizeof(si) };
        PROCESS_INFORMATION pi;
        if (CreateProcessW(config.targetExePath.c_str(), NULL, NULL, NULL, FALSE,
                           CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
            targetPid = pi.dwProcessId;
            hTargetProcess = pi.hProcess;
            CloseHandle(pi.hThread);
            return TRUE;
        }
        return FALSE;
    }

    BOOL CheckHung() {
        // 遍歷目標進程所有可見窗口
        EnumThreadWindows(targetPid, [](HWND hwnd, LPARAM lParam) -> BOOL {
            Watchdog* self = (Watchdog*)lParam;
            if (IsWindowVisible(hwnd) && IsWindowHung(hwnd)) {
                *(BOOL*)lParam = TRUE;  // 發現無響應窗口
                return FALSE; // 停止枚舉
            }
            return TRUE;
        }, (LPARAM)&hungDetected);
        return hungDetected;
    }

    void RestartTarget() {
        if (hTargetProcess) {
            TerminateProcess(hTargetProcess, 0xDEAD);
            WaitForSingleObject(hTargetProcess, 5000);
            CloseHandle(hTargetProcess);
            hTargetProcess = nullptr;
        }
        EnsureTargetRunning();
    }

    void InitiateSystemReboot() {
        // 需SE_SHUTDOWN_NAME特權
        HANDLE hToken;
        OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
        TOKEN_PRIVILEGES tp = { 1, {{SE_SHUTDOWN_NAME, SE_PRIVILEGE_ENABLED}} };
        AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
        ExitWindowsEx(EWX_REBOOT | EWX_FORCE, SHTDN_REASON_MAJOR_SOFTWARE);
    }
};

部署最佳實踐

  1. 隱藏運行:服務模式部署(參考《Windows NT服務開發指南》),或GUI程序設置CREATE_NO_WINDOW、ShowWindow(hWnd, SW_HIDE)
  2. 單例模式:使用命名互斥體CreateMutex(NULL, FALSE, L"Global\\MyWatchdogMutex")防止多實例
  3. 日誌記錄:輸出至事件日誌ReportEvent或ETW,便於事後分析
  4. 配置外部化:INI/JSON/註冊表存儲配置,支持熱加載

局限性與替代方案

  • 無法檢測無UI後台線程死鎖 → 結合心跳機制(IPC/共享內存/命名管道)
  • 系統重啟屬極端措施 → 優先嘗試進程重啟、服務重啟、用戶會話注銷
  • 現代替代:Windows服務恢復操作(SC_ACTION_RESTART)、任務調度器觸發器、Kubernetes liveness probe(容器化場景)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved