最可靠方式是windows用getprocesstimes+gettickcount64、linux读/proc/self/stat+clock_gettime,均需两次采样并以真实流逝时间作分母,单位换算须严格按filetime(100ns)或sysconf(_sc_clk_tck)动态获取jiffies频率。

Windows下用 GetProcessTimes 获取CPU时间并换算成占用率
直接调用 GetProcessTimes 是最轻量、最可靠的方式,它返回的是内核态+用户态的总CPU时间(100纳秒为单位),不是百分比。要得到“占用率”,必须结合两次采样 + 系统总运行时间差来计算。
关键点在于:不能只看进程自身CPU时间差,必须除以「两次采样之间系统实际经过的时间」(wall-clock time),否则在多核、空闲、调度不均等场景下结果完全失真。
- 调用前先用
GetCurrentProcess获取当前进程句柄 - 两次调用间隔建议 ≥ 500ms,太短会导致精度不足甚至返回0
-
GetProcessTimes返回的FILETIME需转为毫秒:用ULARGE_INTEGER联合体转换,再除以 10000(因为 1 FILETIME = 100ns = 0.0001ms) - 别用
clock()或std::chrono::steady_clock当分母——它们测的是进程挂起/休眠时间,不是系统真实流逝时间
Linux下读取 /proc/self/stat 的第14、15字段算CPU时间
Linux没有API直接提供进程CPU占用率,标准做法是解析 /proc/self/stat,提取 utime(用户态jiffies)和 stime(内核态jiffies),再结合系统启动以来的总jiffies数(来自 /proc/stat 的 btime 和当前jiffies)反推。
注意:jiffies 不是固定频率,现代内核默认使用 HZ=250(即每4ms一个tick),但更稳妥的做法是用 sysconf(_SC_CLK_TCK) 获取真实值,而非硬编码。
-
/proc/self/stat第14字段是 utime,第15是 stime;两者相加即总CPU jiffies -
/proc/stat第一行cpu ...后面的前四个数字之和(user+nice+system+idle)是系统总jiffies,但要注意:这个值包含所有CPU核心,所以单进程占比天然被放大 - 两次采样间的真实时间差必须用
clock_gettime(CLOCK_MONOTONIC, &ts),不能用gettimeofday(可能受NTP调整影响) - 如果进程刚启动,
/proc/self/stat中 utime/stime 可能为0,此时直接计算会得0%,需跳过首采样
为什么不能直接用 top 或 ps 的公式?
top 显示的 %CPU 是基于采样周期内该进程使用的 CPU 时间占「所有 CPU 核心总可用时间」的比例,例如双核机器上满载是 200%,而多数人想要的是“占单核的百分比”(即 0–100%)。ps 的 %cpu 字段则采用更粗糙的估算:用进程生命周期内的平均CPU时间除以运行时长,完全无法反映瞬时负载。
-
top -b -n1 | grep your_process解析出的值是近似值,依赖top自身采样逻辑,不可用于自动化监控 - 跨平台统一计算时,不要试图复刻
top的公式(它还扣除了子进程、处理了调度延迟补偿等),容易引入隐性偏差 - 容器环境(如Docker)中,
/proc/stat和/proc/self/stat仍有效,但 cgroup 限频会影响最大可达到的占用率上限,公式本身不变,只是物理意义受限
跨平台封装时最容易漏掉的兼容细节
同一套逻辑在 Windows 和 Linux 上跑,往往在时间单位换算和采样同步上翻车。最常被忽略的是:Windows 的 FILETIME 是 64 位整数,Linux 的 jiffies 是无符号 long,但 sysconf(_SC_CLK_TCK) 返回值可能为 100(旧内核)或 1000(某些实时补丁),不能假设为 100。
- Windows 下两次
GetProcessTimes之间必须用GetTickCount64测真实耗时,不能用QueryPerformanceCounter后自己除——因为GetProcessTimes本身精度就是 15.6ms 左右 - Linux 下读
/proc/self/stat前最好先fopen再fseek(..., 0, SEEK_SET),避免因文件缓冲导致重复读到旧数据 - 如果程序是多线程且频繁 fork,Linux 下要小心
/proc/self的符号链接在子进程中指向父进程——应改用/proc/[pid]/stat并缓存 getpid() 结果
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











