最可靠方式是windows用getsystemtimes、linux读/proc/stat前7字段,跨平台应封装统一接口并处理权限与采样间隔(建议200–500ms),避免瞬时抖动和环境差异导致的统计失真。

Windows下用GetSystemTimes计算CPU使用率最可靠
直接调用GetSystemTimes是Windows平台获取整机CPU使用率最轻量、最准确的方式。它不依赖WMI或性能计数器,避免了权限问题和初始化延迟。关键在于两次采样间隔不能太短(建议≥100ms),否则容易得到0%或100%的抖动值。
实操要点:
-
GetSystemTimes返回的是内核态、用户态、空闲态三组64位时间(单位为100纳秒),需自己做差值和归一化 - 第一次调用后必须sleep一段时间再第二次调用,否则
idleTime变化极小,除法结果溢出或为NaN - 注意
FILETIME到ULARGE_INTEGER的转换:先用CopyMemory或联合体,别直接强转指针 - 总使用率 = 1 − (本次idle差值 / 总时间差值),其中总时间差值 = 用户态差 + 内核态差 + 空闲态差
Linux下读/proc/stat时别只看第一行
/proc/stat首行cpu是所有CPU核心的累加值,但直接解析它容易漏掉关键细节:该行包含user、nice、system、idle、iowait、irq、softirq七列(内核≥2.5.41),而很多旧代码只取前四列,导致iowait被忽略,高IO负载时CPU使用率偏低。
实操要点:
- 逐行读取
/proc/stat,匹配以cpu开头且第二个字符不是空格的行(即cpu而非cpu0) - 至少解析前7个字段,把它们全加起来作为总活动时间;
idle和iowait都算空闲(Linux社区共识) - 两次采样间隔建议≥200ms,用
clock_gettime(CLOCK_MONOTONIC, ...)测真实时间,别信sleep() - 注意字段可能动态增长(如cgroups v2新增
guest_nice),用sscanf带宽度限制,或按空格split后取前7项
跨平台封装时别硬写#ifdef _WIN32
直接在业务逻辑里塞平台判断会让代码难以测试和维护。更合理的方式是定义统一接口,例如double get_total_cpu_usage(),并在编译期链接对应实现——Windows走GetSystemTimes,Linux走/proc/stat,macOS走host_processor_info。这样单元测试可mock该函数,CI也能覆盖多平台路径。
实操要点:
- 把采样逻辑封装成独立cpp文件(如
cpu_usage_win.cpp、cpu_usage_linux.cpp),头文件只暴露get_total_cpu_usage() - 避免在头文件里写
#ifdef,否则模板实例化或inline函数会出问题 - Linux版本务必检查
/proc/stat是否可读(容器环境可能挂载受限),失败时返回-1.0表示不可用,别抛异常 - Windows版要检查
GetSystemTimes返回值,失败时也返回-1.0,常见原因是低权限进程无法访问系统时间
精度和刷新频率的取舍很实际
CPU使用率本质是统计值,不是瞬时物理量。频繁采样(如每10ms)不仅没意义,还会因系统调用开销反向抬高自身CPU占用;过长间隔(如5秒)又失去监控价值。生产环境推荐200–500ms区间,且应允许运行时调整。
实操要点:
- 不要用
std::this_thread::sleep_for精确卡点,它受系统调度影响大;改用循环+clock_gettime判断已过时间 - 首次采样后立即sleep再采第二次,否则第一次的“历史累计值”和第二次差值毫无意义
- 如果程序本身是实时性要求高的服务(如音视频编码),采样线程优先级别设太高,否则干扰主线程
- 注意
GetSystemTimes在Win7以下系统可能返回错误值,需fallback到PDH(但PDH初始化慢且需PdhOpenQuery)
真正难的不是拿到数字,而是让这个数字在不同机器、不同负载、不同内核版本下保持行为一致。比如Linux容器里/proc/stat的数值可能被cgroup限频扭曲,Windows上Hyper-V虚拟机的空闲时间统计也有特殊处理逻辑——这些细节不会报错,但会让监控曲线看起来“不太对”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











