linux下获取线程cpu时间应优先使用clock_gettime(clock_thread_cputime_id),它返回纳秒级总cpu时间(用户态+内核态),轻量且标准;拆分用户/内核时间需读取/proc/self/stat中第14、15字段并结合sysconf(_sc_clk_tck)换算。

Linux下用clock_gettime获取线程CPU时间
在Linux上,clock_gettime配合CLOCK_THREAD_CPUTIME_ID能直接拿到当前线程的总CPU时间(用户态+内核态之和),这是最轻量、最标准的方式。它不依赖glibc版本(2.17+即可),也不需要读取/proc伪文件。
注意:这个时钟返回的是该线程自调度开始以来消耗的CPU时间,不是挂钟时间,且只在该线程运行时才累加。
-
CLOCK_THREAD_CPUTIME_ID是POSIX标准定义的,但仅Linux内核支持;FreeBSD等系统不兼容 - 返回值单位是纳秒,需除以
1000000000.0转为秒 - 必须链接
-lrt(尤其在较老的编译环境中)
#include <time.h>
#include <iostream>
struct timespec ts;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) {
double total_sec = ts.tv_sec + ts.tv_nsec / 1000000000.0;
std::cout
<h3>拆分用户态与内核态时间要用<code>/proc/self/stat</code>
</h3>
<p>Linux内核不提供直接分离用户/内核时间的POSIX接口。<code>/proc/self/stat</code>是唯一可靠且开销可控的途径——它暴露了线程级的<code>utime</code>(用户态jiffies)和<code>stime</code>(内核态jiffies),通过系统<code>HZ</code>可换算成秒。</p>
<p>关键点:/proc/self/stat中第14字段是<code>utime</code>,第15字段是<code>stime</code>,单位是内核jiffies(非固定频率,需查<code>sysconf(_SC_CLK_TCK)</code>)。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>不能硬编码<code>HZ=100</code>——现代内核常为250或1000,必须调用<code>sysconf(_SC_CLK_TCK)</code>
</li>
<li>读取<code>/proc/self/stat</code>是线程安全的,但需注意字段位置可能因内核版本微调(建议用空格分割后按索引取,而非正则匹配)</li>
<li>该文件每次读取都触发轻量内核查询,频繁调用(如每毫秒)会有可观开销</li>
</ul>
<pre class="brush:php;toolbar:false;">#include <unistd.h>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
double get_utime_sec() {
long clk_tck = sysconf(_SC_CLK_TCK);
std::ifstream f("/proc/self/stat");
std::string line;
std::getline(f, line);
std::istringstream iss(line);
std::vector<:string> fields;
std::string field;
while (iss >> field) fields.push_back(field);
if (fields.size() >= 15) {
long utime = std::stol(fields[13]); // 14th field, 0-indexed
return static_cast<double>(utime) / clk_tck;
}
return 0.0;
}
</double></:string></sstream></string></vector></fstream></unistd.h>
Windows平台只能用GetThreadTimes,且无跨线程精确性保证
Windows没有线程级的用户/内核时间分离API,GetThreadTimes是唯一选择,但它返回的是“该线程句柄所代表线程”的时间,且文档明确指出:对已退出线程调用结果未定义,对其他线程调用可能返回过期或不一致值。
更麻烦的是:它返回的FILETIME需手动转为秒,且无法区分当前线程和其他线程——你得确保传入的是当前线程句柄(GetCurrentThread()),而非任意句柄。
-
GetThreadTimes要求线程处于活动状态;若线程刚结束,结果可能为空或错误 - 返回的
CreateTime、ExitTime在当前线程上调用时无意义,只应关注KernelTime和UserTime - FILETIME是100纳秒单位,转秒要除以
10000000.0
#ifdef _WIN32
#include <windows.h>
#include <iostream>
void print_thread_times() {
FILETIME creation, exit, kernel, user;
if (GetThreadTimes(GetCurrentThread(), &creation, &exit, &kernel, &user)) {
ULARGE_INTEGER u, k;
u.LowPart = user.dwLowDateTime; u.HighPart = user.dwHighDateTime;
k.LowPart = kernel.dwLowDateTime; k.HighPart = kernel.dwHighDateTime;
std::cout
<h3>别试图用<code>getrusage</code>替代——它只对进程有效</h3>
<p><code>getrusage(RUSAGE_SELF, ...)</code>返回的是整个进程的累计用户/内核时间,不是当前线程的。即使你在多线程程序里调用,它也包含所有线程的贡献,且无法剥离单个线程的占比。</p>
<p>常见误用场景:想监控某worker线程性能,却在该线程里调用<code>getrusage(RUSAGE_SELF)</code>——结果是整个进程的历史累加值,毫无参考价值。</p>
<ul>
<li>
<code>RUSAGE_THREAD</code>在glibc中存在但<em>未被内核真正支持</em>(始终返回ENOSYS或0),不要依赖</li>
<li>某些旧代码用<code>times(&tms)</code>,它同样只作用于进程,且精度低(tick级)、已被<code>clock_gettime</code>取代</li>
<li>如果真需要线程粒度的资源统计,Linux cgroup v2 + <code>cpu.stat</code>是更重但更准确的方案,但需root权限和额外配置</li>
</ul>
实际使用时,Linux上优先用<code>clock_gettime(CLOCK_THREAD_CPUTIME_ID)</code>拿总量,再配合<code>/proc/self/stat</code>拆分;Windows上只能接受<code>GetThreadTimes</code>的局限性。跨平台封装时,务必把“线程时间”和“进程时间”逻辑彻底隔离,否则很容易在高并发场景下得出误导性数据。</iostream></windows.h>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










