Linux下应通过/proc/[pid]/task/[tid]/stat读取各线程utime+stime累计值,两次采样求差并除以sysconf(_SC_CLK_TCK)得CPU时间占比;clock_gettime(CLOCK_THREAD_CPUTIME_ID)仅限当前线程,无法跨线程获取。

Linux 下用 /proc/[pid]/task/ 读取线程列表和 CPU 时间
Linux 内核把每个线程(LWP)都暴露为 /proc/[pid]/task/[tid]/ 下的子目录,其中 stat 文件包含完整的调度统计信息。关键字段是第 14–17 个(空格分隔):utime(用户态 jiffies)、stime(内核态 jiffies)、cutime、cstime。总 CPU 时间 = utime + stime。
实操建议:
- 用
getpid()获取当前进程 PID,拼出/proc/self/task/路径(self更安全,避免竞态) - 遍历该目录下所有数字命名的子目录(即
tid),跳过非数字项(如comm、status) - 对每个
[tid]/stat,用fopen+fscanf读取前 17 个字段;注意字段可能含空格(如可执行名在第 2 字段),必须按格式严格解析 - 累加所有线程的
utime + stime得到进程总 CPU 时间,再算单个线程占比
clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) 只能查当前线程
这个 API 看似直接,但只能获取调用它的那个线程自身的 CPU 时间,无法跨线程查询。它返回的是高精度纳秒值,但对监控「所有线程」毫无帮助。
常见错误现象:
- 在主线程里循环调用
clock_gettime想“枚举线程”——实际每次都是主线程自己的时间 - 误以为传入 pthread_t 就能指定目标线程——该函数不接受线程标识符参数
所以别在这儿绕弯,老实用 /proc。
计算占比时要注意 jiffies 到秒的换算与采样窗口
/proc/[tid]/stat 中的 utime/stime 是以系统 jiffies 为单位(通常是 100 Hz 或 250 Hz),需除以 sysconf(_SC_CLK_TCK) 才得秒数。但更重要的是:这些值是**累计值**,不是瞬时占用率。
要得到“CPU 时间占比”,你得做两次采样(比如间隔 1 秒),再用差值计算:
- 第一次读所有线程的
utime+stime,记为prev_total和各线程prev_t - 等 1 秒后第二次读,得
curr_total和curr_t - 线程占比 ≈
(curr_t - prev_t) / (curr_total - prev_total)(分母为零需防护) - 若只做单次快照,只能看历史累计占比,对实时监控意义有限
Windows 上没有等价的轻量级方案,EnumThreads + GetThreadTimes 开销大且不准
Windows 没有类似 /proc 的无锁、零拷贝接口。必须用 EnumThreads 枚举 TID,再对每个 TID 调用 GetThreadTimes。问题在于:
- 每次
GetThreadTimes是一次内核调用,线程数多时延迟明显(几十毫秒级) - 两次调用间线程可能已退出或新建,导致数据不一致
- 返回的 FILETIME 是 100ns 单位,但 Windows 线程调度器本身存在统计滞后,短时间窗口下误差常超 ±5%
所以 Windows 下真要监控,建议改用 ETW(Event Tracing for Windows)配合 Thread/ThreadCreate 和 Thread/CPUTime 事件流——但这已超出“简单获取列表”的范畴,属于系统级埋点了。
真正容易被忽略的是:Linux 下 /proc/[tid]/stat 的字段顺序依赖内核版本(2.6.x 和 4.x 差 2 列),务必用 man 5 proc 核对你正在跑的系统,并用 fscanf 的 %*s 跳过不确定字段,而不是硬写偏移索引。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











