最可靠方式是两次采样/proc/stat中cpu行各字段并计算差值:负载率=100×(total−idle)/total,其中total为所有非空闲时间之和,需用unsigned long long防溢出,间隔≥200ms。

Linux下用/proc/stat计算总CPU负载率最可靠
直接读取/proc/stat是Linux获取全局CPU使用率最轻量、最标准的方式。第一行cpu(不含后缀数字)记录的是所有CPU核心的累计时间,包含user、nice、system、idle、iowait、irq、softirq等字段。负载率不是“当前瞬时值”,必须两次采样做差值计算。
常见错误是只读一次就除以固定时间,或误把idle当负载——实际负载率 = 100 * (total - idle) / total,其中total = user + nice + system + idle + iowait + irq + softirq(部分内核还含steal、guest,需跳过)。
- 两次采样间隔建议≥200ms,太短会导致精度崩坏甚至负值
- 解析
/proc/stat时必须按空格分割并跳过首字段cpu,不能用std::stoi硬转整行 - 注意
unsigned long long类型,32位计数器在高负载机器上几小时就溢出 - 示例关键逻辑:
std::ifstream f("/proc/stat"); std::string line; std::getline(f, line); std::istringstream iss(line); std::string cpu; iss >> cpu; // 跳过"cpu" unsigned long long user, nice, system, idle, iowait, irq, softirq; iss >> user >> nice >> system >> idle >> iowait >> irq >> softirq; auto total = user + nice + system + idle + iowait + irq + softirq; auto used = total - idle;
Windows要用GetSystemTimes,且必须管理员权限
GetSystemTimes返回三个FILETIME:空闲时间、内核时间(含空闲)、用户时间。总CPU时间 = 内核时间 + 用户时间,空闲时间需从内核时间中减去(因为内核时间已含空闲)。但该API在非管理员权限下调用会失败,返回FALSE且GetLastError()为ERROR_ACCESS_DENIED。
- 必须用
SetPrivilege开启SE_INCREASE_QUOTA_NAME等权限,或直接以管理员运行 -
FILETIME是100纳秒单位,要转成毫秒需除以10000,再转double参与浮点运算 - 首次调用后需sleep 100ms再第二次调用,否则差值常为0
- 不能用
GetTickCount64替代,它只提供系统启动时间,和CPU时间无关
跨平台封装别碰std::thread::hardware_concurrency()
这个函数只返回逻辑核心数,和CPU负载毫无关系。有人试图用它配合std::chrono测单线程忙等耗时来反推负载,完全不可靠——现代CPU有睿频、DVFS、调度抢占,空循环时间根本不能映射到真实负载。
立即学习“C++免费学习笔记(深入)”;
- POSIX没有标准API获取全局负载,
sysconf(_SC_NPROCESSORS_ONLN)同理只是查核数 - 第三方库如
libstatgrab或htop源码本质也是读/proc/stat或调GetSystemTimes - 若项目已用
boost::process,也不建议起top -bn1管道解析,效率低且输出格式随locale变化
macOS得用host_processor_info,但开销比Linux大得多
macOS没有/proc,必须走Mach API:host_processor_info获取每个核心的cpu_ticks数组(含user/system/idle/unused),再累加。注意它返回的是processor_cpu_load_info_t结构体指针,需手动vm_deallocate释放内存,否则泄漏。
- 调用前必须先用
host_get_host_port拿到host port,否则返回KERN_INVALID_ARGUMENT - 返回的ticks单位不是时间,是处理器特定计数器,只能用于差值计算
- 相比Linux读文件,这个调用涉及内核态切换,频繁调用(
- 不推荐用
sysctlbyname("hw.ncpu")混用,它只返回核心数
真正难的不是读数据,是两次采样间如何避免被信号中断、时钟跳变、或进程被调度出去导致idle时间虚高——这些边界情况在监控类服务里每天都会触发。


















