linux通过/proc/self/stat第22字段(jiffies)结合/proc/stat的btime和sysconf(_sc_clk_tck)计算进程启动时间戳;windows用getprocesstimes获取filetime并转为unix时间戳;跨平台需容错处理且不可用steady_clock替代。

Linux下读取/proc/self/stat获取启动时间戳
Linux内核在 /proc/self/stat 文件第22个字段(从1开始计数)提供进程启动时刻,单位是“系统启动后经过的时钟滴答数(jiffies)”,不是秒或纳秒。你需要结合系统启动时间换算成绝对时间戳。
常见错误是直接把该字段当秒处理,或者忽略 sysconf(_SC_CLK_TCK) 获取实际的 jiffy 频率(通常是 100,但可能被配置为其他值)。
- 用
std::ifstream读取/proc/self/stat,按空格分割字段,提取第22个(注意:字段可能含空格,实际应按括号配对解析;稳妥做法是用std::regex或手动跳过前21个空格分隔符) - 调用
sysconf(_SC_CLK_TCK)获取CLK_TCK,别硬编码为 100 - 读取
/proc/stat中btime行获取系统启动时间(单位秒),这是自 Unix 纪元起的秒数 - 计算:
process_start_timestamp = btime + (jiffies / CLK_TCK),再乘以 1e9 转为纳秒(若需std::chrono::nanoseconds)
Windows下用GetProcessTimes获取创建时间
GetProcessTimes 返回的 lpCreationTime 是 FILETIME 结构,表示自 1601-01-01 起的 100 纳秒间隔数,精度足够高(100ns),但不是 Unix 时间戳。多数 C++ 项目需要转成 std::chrono::system_clock::time_point。
容易踩的坑是直接 reinterpret_cast 或忽略 FILETIME 的低/高位 DWORD 顺序,或忘记转换时区(FILETIME 是 UTC,无需调整)。
- 调用
GetProcessTimes(GetCurrentProcess(), &ftCreate, ..., ...) - 用
ULARGE_INTEGER联合体把ftCreate两个 DWORD 合成 64 位整数 - 减去 Windows Epoch 到 Unix Epoch 的差值(116444736000000000LL),再除以 10(转为纳秒)
- 构造
std::chrono::nanoseconds,然后转成system_clock::time_point
C++跨平台封装建议:避免依赖Boost或第三方
没有标准库函数能直接跨平台获取进程启动时间,std::chrono::system_clock::now() 只能拿到当前时间。硬写宏判断平台会增加维护成本,但比引入 Boost.DateTime 更轻量。
关键点在于:Linux 版本必须容忍 /proc 不可用(容器中可能被挂载为只读或无 procfs),Windows 版本要检查 GetProcessTimes 返回值是否为非零。
- 定义统一返回类型:
std::optional<:chrono::system_clock::time_point></:chrono::system_clock::time_point> - Linux 分支里加
access("/proc/self/stat", R_OK)检查可读性,失败则 fallback 到当前时间(或抛异常) - Windows 分支里用
GetLastError()判断GetProcessTimes失败原因,比如权限不足(少见但可能) - 不要试图用
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)—— 这是 CPU 时间,不是墙上时间
精度与可观测性差异:为什么不能用std::chrono::steady_clock
std::chrono::steady_clock 是单调递增的,适合测量间隔,但它不对应任何绝对时间源。你无法把它“对齐”到 Unix 时间戳——没有标准方法把 steady_clock 的 time_point 转成 system_clock 的 time_point。
所以即使你记录了进程启动时的 steady_clock::now(),也无法对外暴露一个可比较、可序列化的绝对时间戳(比如日志打点、分布式 trace ID 关联)。
- 唯一可靠方案是启动时立刻调用
std::chrono::system_clock::now()并缓存,但存在几微秒延迟(函数调用开销 + 系统调用延迟) - Linux
/proc/self/stat和 WindowsGetProcessTimes都由内核在进程创建时写入,理论上更接近真实起点 - 如果应用对精度要求极高(system_clock::now(),并确保编译器不优化掉该调用(加
volatile或内存屏障不必要,但可加asm volatile("" ::: "memory")防重排)
btime 值可能被 cgroup v2 或某些容器运行时篡改,Windows 上某些沙盒环境会限制 GetProcessTimes 权限——这些边界情况比精度问题更常导致失败。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











