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

非排程自動關機新思路:CPU 閒置偵測觸發關機機制

     編輯:關於VC++

傳統定時關機無法應對「作業完成時間不可預期」的場景(如模型訓練、渲染、大數據處理)。本文提出基於 CPU 使用率監控的智慧關機方案:當系統進入持續閒置狀態時自動觸發關機,完美適配長時間運算任務的後續處理需求。

核心邏輯架構

  1. 高精度 CPU 使用率取得:呼叫 NtQuerySystemInformation 存取核心效能計數器
  2. 動態閾值判斷:連續 N 次採樣 CPU 使用率低於門檻值(如 1%)
  3. 安全關機執行:呼叫 ExitWindowsEx 執行強制關機
  4. 資料保護機制:要求前置作業具備自動儲存功能

關鍵技術:NtQuerySystemInformation 深度解析

此未文件化 API 提供比 GetSystemTimes 更豐富的系統效能資料:

// 系統資訊類別常數
#define SystemTimeInformation        3  // 系統時間資訊
#define SystemPerformanceInformation 2  // 效能計數器(含閒置時間)

// 關鍵資料結構
typedef struct _SYSTEM_PERFORMANCE_INFORMATION {
    LARGE_INTEGER liIdleTime;      // 系統閒置時間 (100ns 為單位)
    LARGE_INTEGER liIoReadTime;
    LARGE_INTEGER liIoWriteTime;
    // ... 其他欄位
} SYSTEM_PERFORMANCE_INFORMATION;

typedef struct _SYSTEM_TIME_INFORMATION {
    LARGE_INTEGER liKeSystemTime;  // 系統核心時間
    // ... 其他欄位
} SYSTEM_TIME_INFORMATION;

完整 CPU 使用率計算與關機邏輯

void CAutoShutDownDlg::GetCpuUsage()
{
    NTSTATUS status;
    SYSTEM_TIME_INFORMATION SysTimeInfo;
    SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
    static LARGE_INTEGER liOldIdleTime = {0};
    static LARGE_INTEGER liOldSysTime = {0};
    
    double dbCpuIdleTime, dbSysTime;
    UINT unCpuUsage;
    char CpuUsage[16];
    BOOL bSetAuto = TRUE;  // 啟用自動關機旗標

    // 1. 取得系統時間
    status = NtQuerySystemInformation(SystemTimeInformation, 
                                     &SysTimeInfo, sizeof(SysTimeInfo), 0);
    if (status != NO_ERROR) { MessageBox("failed to get system time!"); return; }

    // 2. 取得 CPU 效能計數器
    status = NtQuerySystemInformation(SystemPerformanceInformation,
                                     &SysPerfInfo, sizeof(SysPerfInfo), NULL);
    if (status != NO_ERROR) { MessageBox("failed to get cpu time"); return; }

    // 3. 計算差值並換算使用率(需至少兩次採樣)
    if (liOldIdleTime.QuadPart != 0)
    {
        dbCpuIdleTime = LI64ToDouble(SysPerfInfo.liIdleTime) - LI64ToDouble(liOldIdleTime);
        dbSysTime = LI64ToDouble(SysTimeInfo.liKeSystemTime) - LI64ToDouble(liOldSysTime);
        
        // 多核心修正:除以處理器數量
        unCpuUsage = 100 - (UINT)(100 * (dbCpuIdleTime / dbSysTime) / 
                       SysBaseInfo.bKeNumberProcessors + 0.5);
        
        wsprintf(CpuUsage, "%d%%", unCpuUsage);
        m_sCpuUsage = (CString)CpuUsage;

        // 4. 閒置判斷與關機觸發
        if (bSetAuto && (UINT)dbCpuIdleTime == 0)  // 完全閒置
        {
            ShutDown();  // 執行關機
        }
    }

    // 5. 更新基準值供下次採樣使用
    liOldIdleTime = SysPerfInfo.liIdleTime;
    liOldSysTime = SysTimeInfo.liKeSystemTime;
}

關機執行與安全性考量

void CAutoShutDownDlg::ShutDown()
{
    // EWX_FORCE: 強制關閉應用程式不提示儲存
    // EWX_POWEROFF: 切斷電源(需硬體支援)
    ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE | EWX_POWEROFF, 0);
}
風險緩解措施
誤判閒置導致資料遺失要求前置程式(如 MATLAB)具備週期性自動儲存;設定連續 3-5 分鐘閒置才觸發
系統背景作業造成誤判排除 System Idle Process 以外的系統程序;監控特定進程而非整體 CPU
多核心環境計算偏差除以處理器邏輯核心數(SysBaseInfo.bKeNumberProcessors)

進階改良方向

  1. 進程級監控:改用 GetProcessTimes 監控特定進程(如 MATLAB.exe)而非系統整體
  2. 複合條件判斷:結合磁碟 I/O、網路活動、記憶體使用率多維度評估
  3. 優雅關機協商:先發送 WM_CLOSE 給目標進程,超時後再強制關機
  4. 狀態持久化:記錄監控日誌與關機原因,便於事後稽核

總結

基於 CPU 閒置偵測的自動關機方案,解決了定時關機無法適應不確定完成時間的痛點。核心在於正確使用 NtQuerySystemInformation 取得高精度效能計數器,並建立可靠的閒置判斷邏輯。實務部署時務必配合前置應用的自動儲存機制,並在受控環境下充分測試後再投入生產使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved