linux下用clock_gettime(clock_thread_cputime_id, ...)可获取线程自启动以来实际消耗的cpu纳秒数,而非调度器分配的时间片配额;该值线程局部、开销极小,但仅限linux,且无法获知剩余配额或调度周期。

Linux下用clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...)获取线程CPU时间
严格来说,C++标准库不提供“获取当前线程CPU时间切片配额”的接口——操作系统并不向应用暴露调度器分配的“配额”数值(比如毫秒级时间片长度),它只提供已消耗的CPU时间。你真正能拿到的是该线程自启动以来在CPU上实际运行的纳秒数,而非剩余配额或调度周期。
在Linux上,最直接的方式是调用clock_gettime配合CLOCK_THREAD_CPUTIME_ID:
#include <time.h>
struct timespec ts;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) {
long nanos = ts.tv_sec * 1000000000L + ts.tv_nsec;
// nanos 即为该线程已使用的CPU纳秒数
}
</time.h>
-
CLOCK_THREAD_CPUTIME_ID是线程局部的,每个线程调用返回自身消耗的CPU时间,无需传入线程ID - 该调用开销极小(通常为几纳秒),可高频采样
- 需要链接
-lrt(但现代glibc默认已隐式链接,显式加更稳妥) - 不支持在macOS或Windows上使用——macOS用
thread_info+host_statistics(复杂且非实时),Windows需GetThreadTimes
为什么没有“时间切片配额”API?
因为“时间切片”不是固定值,而是调度策略与负载共同决定的动态结果。Linux CFS调度器根本不使用固定时间片,而是基于虚拟运行时间(vruntime)和红黑树公平调度;即使在SCHED_FIFO/SCHED_RR模式下,RLIMIT_RTTIME或sched_rr_get_interval()也只能查到实时策略的轮转间隔,而非当前线程“还剩多少”,且该值对普通线程无效。
-
sched_rr_get_interval(0)只对SCHED_RR线程有意义,且返回的是理论轮转周期(如2ms),不是剩余时间 -
getrusage(RUSAGE_SELF, ...)中的ru_stime/ru_utime精度低(微秒级)、更新延迟高,不适合实时监测 - 试图从
/proc/self/status里读utime/stime字段本质同getrusage,且涉及文件I/O,不可靠
想监控CPU使用率?别依赖“配额”,用差分+时钟
如果你的真实需求是判断线程是否快“用完配额”或是否被节流,正确做法是周期性采样clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...),再结合真实流逝时间(clock_gettime(CLOCK_MONOTONIC, ...))算出CPU使用率:
// 伪代码:每10ms采样一次 auto start_cpu = get_thread_cputime(); auto start_wall = get_monotonic_time(); sleep_ms(10); auto end_cpu = get_thread_cputime(); auto end_wall = get_monotonic_time(); double usage = double(end_cpu - start_cpu) / double(end_wall - start_wall);
- 若
usage ≈ 1.0,说明该线程在这段时间几乎独占CPU;若长期,可能被频繁抢占或休眠 - 注意:两次
clock_gettime调用本身耗时约20–50ns,对10ms以上周期无影响 - 不要用
std::chrono::steady_clock替代CLOCK_MONOTONIC——虽然通常等价,但POSIX标准不保证其对应同一时钟源,跨平台时行为可能不一致
Windows和macOS上的替代方案
Windows下必须用GetThreadTimes,它返回四个FILETIME值,其中lpKernelTime和lpUserTime需合并换算:
- 结果单位是100纳秒,需乘以100转换为纳秒
- 必须传入目标线程句柄,
GetCurrentThread()返回伪句柄,调用前需用DuplicateHandle转为有效句柄(否则GetThreadTimes失败) - macOS只能通过
task_info或thread_info获取粗粒度统计,且需要host_priv_port权限(沙盒App无法使用) - 跨平台封装时,建议抽象为
get_thread_cpu_nanos(),内部按#ifdef __linux__分支实现,其他平台返回-1或抛异常
调度器不会告诉你“还剩多少”,只会记录“已经用了多少”。所有声称能取到“剩余时间片”的方案,要么是误解了调度模型,要么在模拟估算——而估算的前提,是你得先知道调度策略、当前负载、nice值、cgroup限制等一堆运行时上下文。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











