最可靠方法是采样/proc/stat首行cpu字段的user、nice、system、idle四值,两次采样做差后计算busy_delta/total_delta;Windows用GetSystemTimes获取空闲、内核、用户时间,同样差值归一化,注意单位转换与精度保持。

Linux下用/proc/stat计算总CPU负载率最可靠
直接读取/proc/stat是获取包含用户态、内核态、中断(irq)、软中断(softirq)等全部CPU时间的唯一标准方式。系统不提供“总负载率”现成API,必须自己采样两次、做差值再归一化。
关键点:第一行cpu(无后缀)是所有CPU的累加值;字段顺序固定为user nice system idle iowait irq softirq steal guest,其中system含内核态+中断+软中断耗时,irq和softirq已单独统计但已计入system,所以直接用前四项(user、nice、system、idle)就覆盖全部活跃时间。
- 必须采样两次,间隔至少100ms,否则
idle变化太小导致浮点精度失真 - 不要用
clock_gettime(CLOCK_MONOTONIC)做间隔——它不保证与/proc/stat更新节奏同步;用std::this_thread::sleep_for更稳妥 - 解析时跳过空行和以
cpu开头但带数字后缀的行(如cpu0),只处理首行cpu
Windows下没有等效/proc/stat,得靠GetSystemTimes
GetSystemTimes返回三个FILETIME:空闲时间、内核时间(含中断)、用户时间。注意:内核时间=纯内核态 + IRQ + DRIVER + 软中断,Windows不拆分,但已全量包含。
难点在于FILETIME是100纳秒单位,需转为毫秒再做差;且首次调用可能返回FALSE(权限不足或旧系统不支持),必须检查返回值。
立即学习“C++免费学习笔记(深入)”;
- 需要
#include <windows.h>,链接kernel32.lib - 不能直接用
GetTickCount64()算间隔——它和GetSystemTimes时间基不同,会导致归一化错误 - 采样间隔建议≥500ms,Windows的
GetSystemTimes更新粒度比Linux粗
C++跨平台封装要注意std::chrono精度陷阱
用std::chrono::steady_clock测间隔没问题,但计算负载率时别用duration_cast<std::chrono::milliseconds>截断——会丢精度。应全程用double存纳秒级差值,最后除以总时间。
示例核心逻辑:
auto [idle1, kernel1, user1] = read_cpu_times(); // 各自返回uint64_t纳秒 std::this_thread::sleep_for(200ms); auto [idle2, kernel2, user2] = read_cpu_times(); double total_delta = (kernel2 - kernel1) + (user2 - user1) + (idle2 - idle1); double busy_delta = total_delta - (idle2 - idle1); double load = busy_delta / total_delta; // 结果0.0~1.0
- Linux版
read_cpu_times从/proc/stat解析四字段后×10000000转为100ns单位(对齐Windows) - Windows版直接用
GetSystemTimes返回的FILETIME,无需转换 - 别信
top或htop的瞬时值——它们也是采样差值,只是UI做了平滑
别碰sysconf(_SC_NPROCESSORS_ONLN)或std::thread::hardware_concurrency()
这两个只告诉你逻辑CPU数,和负载率计算完全无关。有人误以为要拿总时间除以CPU数,这是错的:/proc/stat首行cpu已是所有CPU累加值,GetSystemTimes返回的也是全局值,不需要、也不应该除以核心数。
常见错误现象:load > 1.0(比如1.2)——说明你把单核时间当总时间用了,或者采样间隔太短导致idle几乎没变,分母趋近于0。
- 验证方法:用
cat /proc/stat | head -1手动看两秒内idle字段是否明显增长 - 如果程序跑在容器里,
/proc/stat仍是宿主机全量数据,不是cgroup限制后的值——这点常被忽略
实际部署时,idle字段溢出(回绕)极少发生,但若监控周期超数天,建议用uint64_t存原始值并检查差值是否为负(此时按溢出处理)。


















