傳統定時關機無法應對「作業完成時間不可預期」的場景(如模型訓練、渲染、大數據處理)。本文提出基於 CPU 使用率監控的智慧關機方案:當系統進入持續閒置狀態時自動觸發關機,完美適配長時間運算任務的後續處理需求。
NtQuerySystemInformation 存取核心效能計數器ExitWindowsEx 執行強制關機此未文件化 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;
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) |
GetProcessTimes 監控特定進程(如 MATLAB.exe)而非系統整體WM_CLOSE 給目標進程,超時後再強制關機基於 CPU 閒置偵測的自動關機方案,解決了定時關機無法適應不確定完成時間的痛點。核心在於正確使用 NtQuerySystemInformation 取得高精度效能計數器,並建立可靠的閒置判斷邏輯。實務部署時務必配合前置應用的自動儲存機制,並在受控環境下充分測試後再投入生產使用。