Linux需解析/proc/[pid]/stat第22字段(start_time)结合clock_gettime(CLOCK_BOOTTIME)反推进程启动时间;Windows可直接用GetProcessTimes()获取创建时间。

Linux 下用 clock_gettime(CLOCK_BOOTTIME) 反推进程启动时间
Linux 没有直接暴露进程启动绝对时间的系统调用,但可以通过读取 /proc/[pid]/stat 中的第 22 个字段(start_time,单位是 jiffies),再结合系统启动时间反推。关键在于:这个 start_time 是相对于系统启动时刻的偏移,不是 Unix 时间戳。
实操建议:
- 先调用
clock_gettime(CLOCK_BOOTTIME, &ts)获取当前系统启动后经过的纳秒数(比CLOCK_MONOTONIC更可靠,能跨 suspend 计时) - 读取
/proc/self/stat,按空格分割后取第 22 字段(注意:字段索引从 1 开始,且括号内内容需跳过——实际解析时推荐用std::stringstream配合ignore跳过括号) - 查
/proc/sys/kernel/osrelease或运行getconf CLK_TCK确认sysconf(_SC_CLK_TCK)值(通常是 100),把start_time转成秒级偏移 - 用
boot_time_ns = current_boottime_ns - (start_time * (1'000'000'000LL / sysconf(_SC_CLK_TCK)))得到进程启动时刻的CLOCK_BOOTTIME纳秒值,再转为time_t需配合clock_gettime(CLOCK_REALTIME, &rt)和clock_gettime(CLOCK_BOOTTIME, &bt)算出二者差值做校准
Windows 下用 GetProcessTimes() + GetSystemTimeAsFileTime()
Windows 提供了更直接的路径:GetProcessTimes() 返回的 lpCreationTime 就是进程创建的 UTC 时间(FILETIME 格式),可直接转为 Unix 时间戳或 std::chrono::system_clock::time_point。
注意点:
立即学习“C++免费学习笔记(深入)”;
-
GetProcessTimes(GetCurrentProcess(), &ftCreate, ...)第一个参数必须传有效的进程句柄,GetCurrentProcess()安全可用 - 返回的
FILETIME是 100 纳秒为单位、自 1601-01-01 起的计数,转换时别漏掉乘 100;常见错误是直接 reinterpret_cast 导致高位截断 - 若需
std::time_t,推荐走ULARGE_INTEGERunion 解包再减去 116444736000000000LL(即 1601 到 1970 年的 100ns 数),再除 10'000'000 - 该时间精度取决于系统时钟源,通常为 10–15ms,在虚拟机中可能更低
跨平台封装时为什么不能只依赖 std::chrono::system_clock::now()
有人试图用进程启动时记下 std::chrono::system_clock::now(),后续再读——这在单线程短生命周期程序里看似可行,但一旦涉及 fork、守护进程重载、或被调试器延迟 attach,初始快照就失效了。更严重的是:C++ 标准不保证 system_clock 的起始点与 Unix epoch 对齐(尽管主流实现都对齐),且无法应对系统时间被 NTP 或用户手动回拨的情况。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
所以真实场景下必须依赖 OS 提供的进程元数据接口,而不是“自己记”。
实操建议:
- Linux 必须解析
/proc/self/stat,不要尝试读/proc/self/comm或/proc/self/status——它们不包含启动时间 - Windows 别用
QueryPerformanceCounter配合启动时打点,它不提供绝对时间语义 - macOS 没有等价接口,得用
sysctl(KERN_PROCARGS2)+task_info()组合估算,误差可能达秒级
容易被忽略的权限与竞态问题
在容器或 sandbox 环境中,/proc/[pid]/stat 可能因 hidepid=2 被隐藏,导致读取失败并返回空或权限错误;而 Windows 上若进程以低完整性级别运行,GetProcessTimes() 可能返回 ERROR_ACCESS_DENIED(尤其在受保护进程如 CSRSS 附近)。
应对方式:
- Linux:检查
open("/proc/self/stat", O_RDONLY)是否成功,失败时 fallback 到std::chrono::steady_clock::now()并记录 warning - Windows:调用前用
OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId())测试权限,避免直接调GetProcessTimes报错 - 所有平台都应避免在信号处理函数中调用这些 API——
/proc文件读取和GetProcessTimes都非 async-signal-safe
最麻烦的其实是 macOS 和某些嵌入式 Linux(无 procfs),这时候没有真正意义上的“绝对启动时间”,只能接受用首次进入 main 的时间作为近似——而且得确保编译器没把初始化逻辑优化到 main 外。

















