跳转到主内容
极星编程网:以代码为星,赴技术山海!

C++如何实时获取进程的CPU利用率百分比 _ 内核时间片差值计算【实战】

CPU占用率=(进程时间差/系统工作时间差)×100/逻辑处理器数,需用GetSystemTimes与GetProcessTimes两次采样(间隔250ms),FILETIME须用ULARGE_INTEGER转毫秒,避免DWORD截断导致跳变。 用
GetSystemTimes
和
GetProcessTimes
算 CPU 占用率,不是读注册表或 WMI Windows 下没有现成的“当前进程 CPU 百分比” API,必须靠时间差推算。核心是:CPU 利用率 = 进程总用户态+内核态时间 / 系统总非空闲时间 × 100%。关键在于两次采样间隔要够短(通常 200–500ms),且必须用
GetSystemTimes
获取系统级时间片,不能只看进程自己的
GetProcessTimes
—— 否则会漏掉系统空闲时间基准,结果严重偏高。 常见错误是直接拿两次
GetProcessTimes
的差值除以采样间隔,这算出来的是“进程运行时间占比”,不是“CPU 占用率”。它把进程休眠、阻塞、等待 I/O 的时间也当成了空闲 CPU,导致数值虚低甚至为 0,尤其在轻负载时完全失真。
GetSystemTimes
返回三个
FILETIME
:空闲时间、内核时间(含空闲)、用户时间;真正的系统总工作时间 = 内核时间 + 用户时间 − 空闲时间
GetProcessTimes
返回的内核+用户时间之和,就是该进程实际占用 CPU 的 tick 总和 两次采样间隔建议设为
250
ms,太短(1s)无法反映瞬时波动 FILETIME 转毫秒差值必须用
ULARGE_INTEGER
,别用
DWORD
截断
FILETIME
是 64 位结构体,低 32 位 + 高 32 位。直接 cast 成
DWORD
或
unsigned long
会丢高位,导致时间差突变为负数或极小值,CPU 率跳变到 0% 或 100%。正确做法是用
ULARGE_INTEGER
union 解包:
ULARGE_INTEGER ft; ft.LowPart = filetime.dwLowDateTime; ft.HighPart = filetime.dwHighDateTime; LONGLONG ms = ft.QuadPart / 10000LL; // FILETIME 单位是 100ns
注意:所有时间差计算(进程时间差、系统工作时间差)都必须用
LONGLONG
,否则在长时间运行的进程上,累计的
FILETIME
值很快溢出
DWORD
范围。 立即学习 “ C++免费学习笔记(深入) ”; 单核 vs 多核 CPU 要除以逻辑处理器数量 算出来的百分比默认是“占单个核心的百分比”。比如四核机器上一个线程满载,
GetProcessTimes
差值 / 系统工作时间差值 ≈ 100%,但这其实是“占用了 1 个核的 100%”,对应整机 CPU 利用率为 25%。所以最终公式是: C知道 CSDN推出的一款AI技术问答工具 下载 CPU% = (进程时间差 / 系统工作时间差) × 100 /
GetSystemInfo().dwNumberOfProcessors
不除这个数,多核机器上报的数值永远偏高。别信“WMI 返回的就是整机百分比”——WMI 底层也是这么算的,只是封装好了。自己实现时漏掉这步,监控图表就会持续显示 80%+,哪怕机器明显空闲。 调用
GetSystemInfo
一次即可,结果缓存,无需每次重查 虚拟机或容器环境下,
dwNumberOfProcessors
可能小于物理核数,以该值为准 如果目标是“该进程占用了多少个核”,就不要除;如果是“占整机 CPU 的百分比”,必须除 第一次采样后必须 sleep,否则两帧时间差接近 0 导致除零或 INF 初始化时调一次
GetProcessTimes
和
GetSystemTimes
,然后必须
Sleep(250)
再采第二次。没 sleep 就直接算,差值基本为 0,分母趋近于 0,结果不是
INF
就是极大噪声值。更隐蔽的问题是:如果进程刚启动,前几次采样可能因内核调度延迟导致
GetSystemTimes
返回的时间差异常小(比如 1ms),此时强行计算会得出 300% 这类非法值。 实操建议: 连续 3 次采样结果若 >100%,先丢弃,等系统稳定再计入 用
std::this_thread::sleep_for(std::chrono::milliseconds(250))
替代
Sleep
,避免阻塞整个线程池(如用在服务进程中) 不要在 GUI 线程里做这个循环,会卡界面;开独立 worker 线程,用
PostMessage
或线程安全队列传结果 真正难的不是公式,而是时间采样节奏和数值稳定性控制。系统时间精度、进程调度抖动、多核计时器偏移都会引入噪声,简单平均或硬限幅反而掩盖问题——得留出调试输出打点,比如把原始
FILETIME
差值全打出来,才能分清是算法错还是数据毛刺。

相关文章