linux用/proc/uptime最轻量可靠,windows需gettickcount64或wmi;读取时只取首浮点数转整型秒数,日志用专用线程+无锁队列,windows下gettickcount64优先但注意溢出与语义差异。

Linux 下直接读 /proc/uptime 是最轻量、最可靠的方式,无需调用系统命令或依赖第三方库;Windows 则必须走 WMI 或 GetTickCount64(),但精度和语义与 Linux 不同——别指望跨平台一套代码通吃。
读取 /proc/uptime 的正确姿势(Linux)
/proc/uptime 是内核暴露的只读伪文件,第一字段是系统自启动以来的总秒数(含小数),精度为 jiffies,实际可稳定到 0.01 秒级。直接 fopen + fscanf 就够用,不用 popen("uptime") 解析字符串——那会引入 shell 启动开销和格式脆弱性。
实操建议:
- 用
std::ifstream或 C 风格FILE*打开/proc/uptime,失败时直接返回错误(该文件在容器中可能不可见,需检查 errno == ENOENT) - 只读第一个浮点数:
float uptime_sec; fscanf(fp, "%f", &uptime_sec);,忽略第二字段(空闲时间,基本用不到) - 转换为整型秒数存日志更稳妥,避免浮点打印误差;若需毫秒级,乘 1000 后转
long long - 别每秒都 fopen/fclose——可缓存文件描述符,或用
read()配合open(O_RDONLY)复用 fd
写入运行日志的线程安全与性能陷阱
日志不是 printf,高频写入(如每 5 秒记一次)容易因磁盘 I/O 或锁竞争拖慢主逻辑。尤其多线程程序里,std::ofstream 默认非线程安全,fprintf 也不保证原子性。
实操建议:
- 用单个专用日志线程 + 无锁队列(如
boost::lockfree::queue或简易 ring buffer)收日志消息,主线程只 push 字符串 - 日志行格式建议:
[2024-06-12 14:23:05] UPTIME: 86422s—— 时间戳用strftime生成,别依赖std::chrono::system_clock::now()再格式化,后者在某些 libc 实现里有锁 - 打开日志文件时加
O_APPEND(C)或std::ios::app(C++),避免多进程写冲突;定期按大小轮转,不依赖外部 logrotate
Windows 下的等效实现与关键差异
Windows 没有 /proc/uptime,GetTickCount64() 返回的是自系统启动以来的毫秒数,但它会在约 49.7 天后溢出重置(虽然函数名带 64,但底层仍可能受旧驱动影响);更稳的是 WMI 查询 Win32_OperatingSystem.LastBootUpTime,但要链接 comsuppw.lib,初始化 COM,延迟高且可能失败。
实操建议:
- 优先用
GetTickCount64():它快、轻量、无需 COM,只要接受“可能重启后归零”这个事实(对运行日志而言,连续性比绝对值重要) - 若需绝对时间,WMI 方案中务必检查
LastBootUpTime字段是否为空,且需将YYYYMMDDHHMMSS.mmmmmm+UUU格式手动解析为 FILETIME,再转为秒数 - 跨平台代码里,用
#ifdef _WIN32分支,不要试图封装成统一接口——Linux 的 uptime 是单调递增的,Windows 的GetTickCount64可能被系统调速(如节能模式)轻微拉伸,二者语义不等价
真正麻烦的从来不是读 uptime,而是日志滚动时没清空缓冲、多进程同时写一个文件导致内容错乱、或者把 /proc/uptime 当普通文件 mmap 导致 SIGBUS——这些细节不踩一遍,很难信。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











