最可靠方式是两次采样/proc/stat(Linux)或GetSystemTimes(Windows)计算差值:Linux用cpu行各字段和减idle、iowait得忙时间,Windows用kernelTime+userTime除以总时间,二者均需≥100ms间隔,避免getloadavg等不可靠接口。

Linux下用/proc/stat计算总CPU负载率最可靠
直接读取 /proc/stat 是获取 Linux 系统级 CPU 总负载(含 user、nice、system、idle、iowait、irq、softirq、steal)的唯一标准方式。其他接口如 getloadavg() 返回的是运行队列长度均值,不是 CPU 使用率;sysconf(_SC_NPROCESSORS_ONLN) 只给核数,不反映负载。
关键点在于:必须采样两次,间隔一定时间(建议 ≥100ms),用差值计算。单次读取只能得到累计 ticks,无法换算成百分比。
-
/proc/stat第一行以cpu开头的数据包含所有 CPU 的累加值(cpu行,非cpu0等) - 字段顺序固定:
user nice system idle iowait irq softirq steal guest guest_nice(内核 2.6.33+,老版本可能缺最后两项) - 总 tick 数 = 所有字段之和;忙 tick 数 = 总 tick −
idle−iowait(注意:严格来说,iowait属于“空闲但等待 I/O”,通常计入空闲;若要包含中断开销,必须保留irq和softirq在忙时间里) - 实际负载率 = (busy_ticks_delta / total_ticks_delta) × 100%
Windows上没有等效的系统级总CPU负载接口
Windows 没有类似 /proc/stat 的单一聚合指标。GetSystemTimes() 可以拿到 idleTime、kernelTime、userTime,但它返回的是 100ns 单位的 FILETIME,且 kernelTime 包含中断和 DPC 时间——这点符合你“包括内核态及中断时间”的要求。
但要注意:GetSystemTimes() 在 Windows 7+ 才支持,XP 不可用;且它只反映整个系统的 CPU 时间,不区分逻辑处理器,结果与 Linux 的 cpu 行语义一致。
立即学习“C++免费学习笔记(深入)”;
- 必须两次调用 + 差值计算,否则无意义
- 需将
FILETIME转为 64-bit 整数后相减,再统一换算为毫秒或微秒参与运算 - 总活跃时间 =
kernelTime + userTime(kernelTime已含中断、DPC、驱动执行等内核态时间) - 空闲时间 =
idleTime,总时间 =idleTime + kernelTime + userTime - 负载率 = (kernelTime + userTime) / 总时间 × 100%
跨平台封装时别碰POSIX的getloadavg
getloadavg() 看起来跨平台,但它返回的是“1、5、15 分钟平均就绪进程数”,不是 CPU 使用率。在 8 核机器上,1.0 的 loadavg ≈ 12.5% CPU 利用率(仅当所有进程完全 CPU-bound 且调度无抖动时才勉强对应),实际场景下完全不可靠。
尤其在容器或虚拟化环境中,getloadavg() 受 cgroup 限制影响严重,数值与真实 CPU 消耗脱钩。强行用它换算负载率,误差常超过 ±30%。
- Linux/macOS 都有
getloadavg(),但语义完全不同 - 它不包含中断时间统计,也不反映当前瞬时负载
- 无法区分用户态/内核态,更无法提取 irq/softirq 单独占比
采样间隔太短会导致结果跳变甚至负值
两次读取 /proc/stat 或调用 GetSystemTimes() 之间的时间差太小(比如
推荐最小间隔设为 100ms;生产环境建议 500ms 起步。若需高频监控(如每秒多次),应累积多个周期做滑动平均,而非硬压间隔。
- Linux 下
clock_gettime(CLOCK_MONOTONIC, ...)比std::chrono更稳,避免 gettimeofday 时钟跳变干扰 - Windows 下用
QueryPerformanceCounter(),别用GetTickCount64()(精度仅 10–16ms) - 每次读
/proc/stat前用lseek(fd, 0, SEEK_SET)重置文件偏移,否则可能读到旧缓冲
实际部署时,最容易被忽略的是:不同内核版本对 /proc/stat 字段扩展的兼容处理(比如新增 guest_nice 后,老解析逻辑会把后续字段全错位)。别写死字段索引,按空格 split 后跳过首字段,再逐个尝试 parse,遇到非数字就跳过。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/124044.html