在 Windows 平台开发性能监控类程序时,CPU 使用率是核心监控指标之一。本文基于 Windows 原生 PDH(Performance Data Helper)API,实现高精度、高兼容性的 CPU 使用率实时采集功能,代码可直接复用,适配 Win10/Win11 系统,与任务管理器 CPU 数值高度一致。
一、核心优势
- 原生 API:基于 Windows PDH 接口,无需第三方库,轻量化且稳定;
- 高精度:返回浮点型 CPU 使用率,支持自定义小数位数;
- 高兼容:适配 Win10/11,计数器路径经过实测验证,无数值偏差;
- 鲁棒性:包含完整的错误处理和异常值过滤,避免程序崩溃;
- 易复用:模块化设计,初始化、采集、释放功能分离,可直接集成到项目。
二、完整代码实现
#include <windows.h>
#include <pdh.h>
#include <iostream>
#include <cmath> // 用于 round() 四舍五入函数
// 链接 PDH 库,必须添加
#pragma comment(lib, "pdh.lib")
// 关闭安全警告
#pragma warning(disable:4996)
// CPU 监控句柄(全局/类成员均可,保证生命周期)
static PDH_HQUERY cpuQuery;
static PDH_HCOUNTER cpuTotal;
/**
* @brief 初始化 CPU 使用率采集模块
* @return bool 初始化成功返回 true,失败返回 false
* @note 必须先调用此函数,否则 getCPUUsage 返回 0
*/
bool initCPUMonitor() {
// 打开 PDH 查询句柄
if (PdhOpenQuery(NULL, NULL, &cpuQuery) != ERROR_SUCCESS) {
std::cerr << "CPU 监控初始化失败:打开查询句柄失败" << std::endl;
return false;
}
// 添加 CPU 使用率计数器(Win10/11 最优路径,与任务管理器数值一致)
if (PdhAddEnglishCounter(cpuQuery, L"\\Processor Information(_Total)\\% Processor Utility", NULL, &cpuTotal) != ERROR_SUCCESS) {
std::cerr << "CPU 监控初始化失败:添加计数器失败" << std::endl;
PdhCloseQuery(cpuQuery);
return false;
}
// PDH 特性:首次采样必为 0,需预热采样
PdhCollectQueryData(cpuQuery);
Sleep(600); // 采样间隔,保证数据有效
PdhCollectQueryData(cpuQuery);
return true;
}
/**
* @brief 获取实时 CPU 总使用率(%)
* @return double CPU 使用率(0.0 ~ 100.0),保留 1 位小数,出错返回 0.0
*/
double getCPUUsage() {
PDH_FMT_COUNTERVALUE counterVal;
// 采集最新数据
if (PdhCollectQueryData(cpuQuery) != ERROR_SUCCESS) {
return 0.0;
}
// 格式化获取数值(双精度浮点数)
DWORD ret = PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
if (ret != ERROR_SUCCESS) {
return 0.0;
}
// 过滤异常值 + 保留 1 位小数
double cpuUsage = counterVal.doubleValue;
cpuUsage = (cpuUsage >= 0.0 && cpuUsage <= 100.0) ? cpuUsage : 0.0;
if (cpuUsage > 100.0) cpuUsage = 100.0;
cpuUsage = round(cpuUsage * 10) / 10.0; // 四舍五入保留 1 位小数
return cpuUsage;
}
/**
* @brief 释放 CPU 监控资源(程序结束时调用)
*/
void releaseCPUMonitor() {
if (cpuQuery != NULL) {
PdhCloseQuery(cpuQuery);
cpuQuery = NULL;
}
}
int main() {
// 1. 初始化 CPU 监控
if (!initCPUMonitor()) {
return -1;
}
// 2. 循环获取 CPU 使用率(每秒 1 次)
std::cout << "CPU 使用率监控中,按 Ctrl+C 退出..." << std::endl;
while (true) {
double cpu = getCPUUsage();
std::cout << "当前 CPU 使用率:" << cpu << "%" << std::endl;
Sleep(1000);
}
// 3. 释放资源(实际中需在退出循环后调用)
releaseCPUMonitor();
return 0;
}
三、关键知识点解析
1. PDH API 核心流程
- PdhOpenQuery:创建 PDH 查询句柄,是所有 PDH 操作的基础;
- PdhAddEnglishCounter:添加 CPU 使用率计数器,使用英文计数器路径避免中文系统兼容问题;
- PdhCollectQueryData:采集计数器数据,PDH 要求至少两次采样才能得到有效数值;
- PdhGetFormattedCounterValue:将采集到的原始数据格式化为浮点数,方便使用;
- PdhCloseQuery:释放查询句柄,避免资源泄漏。
2. 核心细节说明
(1)计数器路径选择
L"\\Processor Information(_Total)\\% Processor Utility"
这是 Win10/11 下最优的 CPU 总使用率计数器路径,相比旧版 \\Processor(_Total)\\% Processor Time,数值更贴合任务管理器,无延迟和偏差。
(2)首次采样预热
PDH API 的特性是首次采集数据必为 0,因此初始化时需要先执行两次 PdhCollectQueryData,并间隔 600ms,保证后续采集的数值有效。
(3)小数位数控制
cpuUsage = round(cpuUsage * 10) / 10.0;
通过 round() 函数实现四舍五入保留 1 位小数:
- 放大 10 倍:将小数点后第一位变为整数位(如 25.67→256.7);
- 四舍五入:
round(256.7)→257; - 缩小 10 倍:257/10→25.7,最终得到 1 位小数的结果。
四、编译与运行说明
1. 编译环境
- 编译器:MSVC(Visual Studio 2019/2022)、MinGW(需确保链接 pdh.lib);
- 平台:Windows 10/11(32/64 位均可);
- 字符集:默认多字节字符集即可。
2. 运行效果
CPU 使用率监控中,按 Ctrl+C 退出...
当前 CPU 使用率:5.2%
当前 CPU 使用率:4.8%
当前 CPU 使用率:6.1%
...
五、注意事项
- 头文件依赖:使用
round()函数必须包含<cmath>头文件,否则编译报错; - 资源释放:程序退出前务必调用
releaseCPUMonitor()释放 PDH 句柄,避免内存泄漏; - 采样频率:建议采样间隔≥500ms,过于频繁采样会导致数值波动,且无实际意义;
- 权限问题:普通用户权限即可运行,无需管理员权限;
- 异常值过滤:代码中已过滤 0~100 之外的异常值,避免出现负数或超过 100% 的无效数值。
总结
本文基于 Windows PDH API 实现了轻量、高效的 CPU 使用率监控功能,代码模块化程度高,可直接复用。核心要点包括:PDH 初始化预热、正确选择计数器路径、数值格式化与异常过滤。该方案相比第三方库更轻量化,相比 WMI 查询更高效,是 Windows 平台 CPU 监控的优选方案。

