最可靠方法是两次采样/proc/stat中cpu行的累计ticks差值比:总时间=user+nice+system+idle+iowait+irq+softirq+steal,活跃时间=总时间−idle−iowait,间隔≥200ms。

Linux 下用 /proc/stat 计算总 CPU 负载率最可靠
直接读取 /proc/stat 是 Linux 上获取系统级总 CPU 使用率(用户态 + 内核态 + 中断等)的唯一标准方式,top、htop 都基于它。关键不是“实时瞬时值”,而是两次采样间的增量比。
第一行 cpu 后的 10 个数字分别代表 user、nice、system、idle、iowait、irq、softirq、steal、guest、guest_nice。总 CPU 时间 = 前 8 项之和(user + system + idle + iowait + irq + softirq + steal + nice),活动时间 = 总时间 − idle − iowait。
实操建议:
- 必须做两次采样(间隔 ≥ 200ms),否则结果无意义甚至为负
- 用
std::ifstream逐行读/proc/stat,匹配以"cpu "开头的首行(注意空格,避免匹配到cpu0) - 用
std::stoull解析数值,unsigned long long才能容纳高负载长时间运行后的计数器溢出 - 别用
clock_gettime(CLOCK_MONOTONIC)做间隔基准——只要两次读取时间差在 100ms~1s 区间内,精度足够
Windows 下只能用 GetSystemTimes,且结果不包含内核线程调度开销
GetSystemTimes 返回三个 FILETIME:空闲时间、内核时间、用户时间。但要注意:内核时间包含空闲时间,所以实际活动时间为 kernel_time - idle_time + user_time;总时间为三者之和。
立即学习“C++免费学习笔记(深入)”;
这个 API 的限制很实在:
- 仅 Windows XP SP1+ 可用,旧系统需检查函数指针是否为
nullptr - 返回的是自系统启动以来的 100ns 单位计数,需转为
ULONGLONG后做减法 - 它无法反映 DPC、中断服务例程(ISR)等真正底层的 CPU 消耗,所以数值通常略低于 Linux 的
/proc/stat结果 - 没有“采样间隔控制”机制,你得自己 sleep + 重试,且最小可靠间隔建议 ≥ 500ms
跨平台封装时,别碰 std::thread::hardware_concurrency() 或 sysconf(_SC_NPROCESSORS_ONLN)
这两个函数只返回逻辑 CPU 核心数,和负载率完全无关。曾有人误以为用当前活跃线程数除以核心数就能估算负载——这是典型错误:单个线程可因 I/O 阻塞长期不占 CPU,而一个死循环线程能把 1 个核跑满 100%。
真正要规避的陷阱:
- 不要用
std::this_thread::sleep_for精确控制采样间隔——系统调度延迟会导致实际间隔偏差大,影响分母精度 - 不要把多次采样的结果简单取平均——负载是瞬态过程,应每次独立计算再滑动窗口处理
- 避免在容器或 WSL2 中直接复用 Linux 代码:
/proc/stat在 WSL2 里反映的是子系统虚拟层,不是宿主 Windows 的真实负载
MacOS 没有等价接口,host_processor_info 返回的是每个 CPU 的独立快照
macOS 不提供类似 /proc/stat 的聚合视图。host_processor_info 返回的是数组形式的每核数据,必须手动累加所有 CPU 的 cpu_ticks(含 USER_STATE、SYSTEM_STATE、IDLE_STATE、WAIT_STATE)。但问题在于:Apple 自己的 Activity Monitor 也不显示“总负载率”,只显示各核曲线。
务实做法:
- 若只需粗略参考,取所有核中最高单核使用率(即“最忙的那个核”),它至少反映了系统瓶颈所在
- 若坚持要总和,需调用
host_processor_info两次,对每个状态字段分别求和再算百分比,但要注意WAIT_STATE在 macOS 中语义模糊,部分版本将其计入空闲 - 放弃在 macOS 上获取与 Linux/Windows 对齐的“标准总负载率”——这不是实现问题,是设计差异
最易被忽略的一点:所有平台的“总 CPU 负载率”本质上都是估算值,依赖采样时机和计数器更新频率。生产环境若需精确归因,应该转向 eBPF(Linux)或 ETW(Windows)这类内核级追踪机制,而不是靠用户态轮询 /proc/stat 或 GetSystemTimes。


















