linux下进程启动时间需读/proc/[pid]/stat第22字段(start_time,单位为clk_tck分之一秒)并结合/proc/stat的btime换算;windows下须用getprocesstimes()获取filetime后转为unix时间戳。

Linux 下读取 /proc/[pid]/stat 的 start_time 字段
Linux 内核在 /proc/[pid]/stat 中第 22 个字段(空格分隔)记录了进程启动时的内核启动后毫秒数(unsigned long 类型),不是 Unix 时间戳,需结合系统启动时间换算。
实操要点:
- 用
getpid()获取当前 pid,拼出路径如/proc/self/stat(推荐用self避免竞态) - 逐字段解析需跳过括号内的
comm字段(第 2 字段),实际应读取第 22 个以空格分隔的数值(索引从 1 开始计) - 读取
/proc/stat中的btime行获取系统启动的 Unix 秒数(注意:不是uptime,btime是 boot time) -
start_time单位是CLK_TCK分之一秒(通常为100),即毫秒;需除以sysconf(_SC_CLK_TCK)转为秒再加btime
示例关键逻辑:
FILE* f = fopen("/proc/self/stat", "r");
unsigned long start_time;
fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %lu", &start_time);
fclose(f);
<p>long clk_tck = sysconf(_SC_CLK_TCK); // 通常是 100
double proc_start_sec = (double)start_time / clk_tck;</p><p>// 读 /proc/stat 获取 btime
f = fopen("/proc/stat", "r");
unsigned long btime = 0;
char line[256];
while (fgets(line, sizeof(line), f)) {
if (sscanf(line, "btime %lu", &btime) == 1) break;
}
fclose(f);</p><p>time_t exact_ts = (time_t)(btime + proc_start_sec); // 精确到秒,小数部分可保留用于微秒级对齐
</p>
Windows 下调用 GetProcessTimes() 并转为本地时间
Windows 不直接暴露进程启动的绝对时间戳,但 GetProcessTimes() 返回的 lpCreationTime 是 FILETIME(100 纳秒精度,自 1601-01-01 UTC),必须手动转为 time_t 或 std::chrono::system_clock::time_point。
常见错误:
- 直接把
FILETIME.dwLowDateTime当作秒或毫秒用 —— 它是 64 位整数,需合并高低 32 位 - 忽略时区:FILETIME 是 UTC,
time_t也是 UTC,但用localtime()转换前别误以为它含本地时区偏移 - 未检查
GetProcessTimes()返回值,对受限进程(如沙箱、服务)可能失败并返回 0
实操建议:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 用
GetCurrentProcess()获取句柄,传给GetProcessTimes() - 用
ULARGE_INTEGER联合体安全合并FILETIME的高低位 - 减去 Windows 纪元偏移(116444736000000000LL 微秒 = 1601 到 1970 的秒数 × 10⁷)再除 10⁷ 得
time_t
片段示意:
FILETIME ftCreate, ftExit, ftKernel, ftUser;
if (GetProcessTimes(GetCurrentProcess(), &ftCreate, &ftExit, &ftKernel, &ftUser)) {
ULARGE_INTEGER ui;
ui.LowPart = ftCreate.dwLowDateTime;
ui.HighPart = ftCreate.dwHighDateTime;
uint64_t utc_100ns = ui.QuadPart;
time_t ts = (time_t)((utc_100ns - 116444736000000000LL) / 10000000LL);
}
跨平台封装要注意的精度与权限差异
同一份代码在 Linux 和 Windows 上拿到的时间源不同:Linux 依赖 /proc(仅 Linux)、Windows 依赖 Win32 API(仅 Windows),不存在标准 C++ 库函数能直接获取该信息。
关键权衡点:
- Linux 下
/proc/[pid]/stat的start_time来自jiffies,受HZ影响(现代内核多为 250 或 1000),理论精度在毫秒级;而GetProcessTimes()在 Windows 是微秒级(实际常为 15.6ms 间隔,取决于系统定时器分辨率) - 容器环境(如 Docker)中,
/proc/self/stat的btime是宿主机启动时间,但进程start_time是容器内核视图下的值 —— 若容器启动晚于宿主机,结果仍正确;但若用 cgroup v1 + ns 混合,需确认是否挂载完整/proc - 非特权进程在某些加固系统(SELinux enforcing、Android /proc 隐藏)可能读不到
/proc/self/stat,应有 fallback(如退到clock_gettime(CLOCK_MONOTONIC)记录启动瞬间,但非“系统级精确时间戳”)
不要依赖 time(0) 或程序入口处打点
很多开发者在 main() 第一行调用 time(0),误以为这就是“进程启动时间”。这完全错误 —— 从内核 execve() 完成、映射完动态库、运行 C 运行时初始化(如 __libc_start_main)、再到进入 main,中间可能有几毫秒到几十毫秒延迟,尤其在高负载或启用 ASLR/PTI 的系统上更明显。
真正可靠的来源只有:
- Linux:
/proc/[pid]/stat的start_time+/proc/stat的btime - Windows:
GetProcessTimes()的lpCreationTime - macOS:无直接等价接口;需用
sysctl(KERN_PROCARGS2)结合clock_gettime(UNSPEC)估算,误差更大
如果你的应用需要亚毫秒级对齐(比如 trace 工具、性能审计),务必绕过用户态打点,直取内核/系统 API 提供的原始时间源。任何中间环节都可能引入不可控延迟。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










