跨平台cpu使用率需抽象“时间快照”概念,windows用getsystemtimes(需se_increase_quota_name权限),linux读/proc/stat首行cpu行,采样间隔不低于500ms且首次仅初始化。

如何在 Windows 和 Linux 上统一获取 CPU 使用率
跨平台性能统计最难啃的骨头就是 CPU 使用率——Windows 用 GetSystemTimes,Linux 读 /proc/stat,两者数据格式和采样逻辑完全不同。不能简单封装两个 if 分支,得抽象出「时间快照」概念:每次调用 sample() 记录当前系统总空闲/非空闲时间戳,两次 sample 做差值再算百分比。
关键点在于采样间隔不能太短(/proc/stat 的 jiffies 精度不够,Windows 下 GetSystemTimes 返回的 FILETIME 也难分辨微小变化;也不能太长(>2s),否则无法反映瞬时负载。建议固定 500ms 间隔,首次调用 sample() 仅初始化,第二次起才返回有效率值。
- Windows 需启用
SE_INCREASE_QUOTA_NAME权限才能准确获取系统时间(尤其在服务进程里),否则GetSystemTimes可能返回 0 - Linux 下必须解析
/proc/stat第一行以cpu开头的行(注意末尾有空格),不是cpu0或cpu1 - 别用
clock_gettime(CLOCK_MONOTONIC)替代系统时间差——它测的是流逝时间,不是 CPU 时间分配
内存使用量为什么在不同系统上数值差异很大
Linux 的 /proc/meminfo 里 MemAvailable 是内核估算的可立即分配内存,而 Windows 的 GlobalMemoryStatusEx 返回 ullAvailPhys 是物理内存减去已锁定部分,二者语义不等价。强行对齐会导致误判“内存不足”。实际工程中应分场景处理:
- 监控告警:Linux 用
MemAvailable / MemTotal,Windows 用ullAvailPhys / ullTotalPhys,各自独立阈值(如 Linux 15%,Windows 10%) - 日志记录:必须打标来源系统,例如
{"os":"linux","mem_avail_mb":1248,"mem_total_mb":8192} - 避免使用
psutil类第三方库——它在 Windows 上依赖 WMI,启动慢且权限要求高;Linux 上可能因 cgroups v2 导致MemAvailable读错
如何让 C++ 类不依赖 Boost 或 Qt 实现跨平台文件系统统计
磁盘空间统计看似简单,但 statvfs(Linux/macOS)和 GetDiskFreeSpaceEx(Windows)返回字段单位不一致:statvfs 的 f_bsize 是 I/O 块大小,f_frsize 才是真正计算用的块大小;而 Windows 直接返回字节数。若直接把 f_bavail * f_bsize 当可用字节,在某些 XFS 文件系统上会严重高估。
统一做法是全部转为字节再计算,并缓存设备路径到 stat 结构的映射,避免重复 syscall:
// 示例:Linux 端核心计算
struct statvfs buf;
if (statvfs("/home", &buf) == 0) {
uint64_t total = static_cast<uint64_t>(buf.f_blocks) * buf.f_frsize;
uint64_t free = static_cast<uint64_t>(buf.f_bavail) * buf.f_frsize;
}
</uint64_t></uint64_t>
- Windows 路径需转为宽字符传给
GetDiskFreeSpaceExW,否则中文路径失败且不报错 - Linux 下若挂载点是 NFS 或 FUSE,
statvfs可能阻塞数秒,务必设超时(用alarm()或线程+join) - 不要尝试用
std::filesystem::space()(C++17)——GCC 11 前版本在 Windows 上返回全 0,MSVC 2019 对符号链接处理异常
为什么多线程采集时 CPU 和内存数据会相互污染
典型错误是把所有采样逻辑塞进一个单例对象,然后多线程并发调用 update_cpu() 和 update_memory()。问题在于:Linux 下读 /proc/stat 和 /proc/meminfo 是两个独立的 open-read-close,中间可能被其他进程写入 /proc,导致 CPU 快照和内存快照时间错位;Windows 下 GetSystemTimes 和 GlobalMemoryStatusEx 虽然快,但若没加锁,多个线程同时更新同一组成员变量(如 m_last_idle_time),会产生脏读。
- 必须按「一次完整采集周期」原子化:在一个线程里顺序调用所有指标采样函数,结果存入临时结构体,再整体 swap 到对外可见的数据区
- 禁止用
std::atomic保护单个字段——CPU 计算需要至少两个时间点,原子变量无法保证跨字段一致性 - 如果必须多线程(比如 UI 线程要读、采集线程要写),用
std::shared_mutex(C++17)或 pthread_rwlock_t,读多写少场景下性能损失可控
最易被忽略的是时间同步:即使你把所有采样塞进一个函数,Linux 下两次 read() 之间仍有毫秒级间隔,Windows 下 GetSystemTimes 和 QueryPerformanceCounter 也不同源。真要高精度关联指标,得接受 10–50ms 的固有误差,别试图用纳秒级时间戳对齐。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











