std::chrono::steady_clock 是唯一靠谱的选择,因其单调递增且不受系统时间调整影响;system_clock 可能跳变,high_resolution_clock 在 Windows MSVC 下仅为 system_clock 别名、分辨率仅毫秒级;微秒精度需 steady_clock 配合显式转换,并注意平台实际分辨率(如 Windows 为 100 纳秒)、避免 duration_cast 截断误差及多线程竞争问题。

为什么 std::chrono::steady_clock 是唯一靠谱的选择
因为只有 std::chrono::steady_clock 保证单调递增且不受系统时间调整影响,std::chrono::system_clock 可能跳变,std::chrono::high_resolution_clock 在某些平台(如 Windows MSVC)只是 system_clock 的别名,实际分辨率可能只有毫秒级。微秒精度必须靠 steady_clock + 显式转换,不能依赖“高分辨率”字面意思。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 始终用
std::chrono::steady_clock::now()获取时间点,不要用high_resolution_clock - 用
std::chrono::microseconds作为目标时长单位,避免中间用nanoseconds再截断——部分平台nanoseconds构造会向下取整丢精度 - 检查实际分辨率:
std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den,Linux 通常为 1/1000000000(纳秒),Windows(QueryPerformanceCounter)通常为 1/10000000(100 纳秒),这意味着在 Windows 上你最多只能稳定达到 100 纳秒(即 0.1 微秒)分辨率,请求 1 微秒是可行的,但 0.5 微秒就不可靠
如何避免 std::chrono::duration_cast 引发的精度丢失
duration_cast 默认向零截断,比如把 1.9 微秒转成 microseconds 得到 1,不是四舍五入。这对计时器起点/终点误差累积很敏感,尤其做多次短间隔测量时。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 起点和终点都用
time_point存储,差值先转成nanoseconds,再用浮点除法算微秒:auto us = std::chrono::duration_cast<:chrono::nanoseconds>(end - start).count() / 1000.0;</:chrono::nanoseconds> - 如果只要整数微秒且允许向下取整(例如超时判断),用
duration_cast<:chrono::microseconds></:chrono::microseconds>没问题;但做性能统计时,优先保留小数或用nanoseconds原始值 - 别写
duration_cast<microseconds>(duration_cast<nanoseconds>(...))</nanoseconds></microseconds>—— 双重 cast 可能触发两次截断,直接一步到位
实现一个线程安全、可重置的微秒计时器类
多数场景不需要原子操作,但多线程读写同一计时器实例时,start() 和 elapsed_micros() 必须保证不出现数据竞争。C++11 起 std::chrono::time_point 是 trivially copyable,但读写共享变量仍需同步。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 最简方案:用
std::atomic<bool></bool>标记是否已启动,配合std::atomic<time_point></time_point>存起点(注意:time_point本身不可原子,需用int64_t存纳秒计数,或用std::atomic_flag+ mutex 封装) - 更实用的做法:放弃完全无锁,用
mutable std::mutex mtx_保护内部start_time_和is_running_,毕竟微秒级计时本身开销远小于 mutex 争用 - 示例关键片段:
class MicroTimer {
mutable std::mutex mtx_;
std::chrono::steady_clock::time_point start_time_;
bool is_running_ = false;
public:
void start() {
std::lock_guard<std::mutex> lk(mtx_);
start_time_ = std::chrono::steady_clock::now();
is_running_ = true;
}
double elapsed_micros() const {
std::lock_guard<std::mutex> lk(mtx_);
if (!is_running_) return 0.0;
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_).count() / 1000.0;
}
};
Windows 下实测达不到标称微秒精度?检查 QueryPerformanceCounter 配置
MSVC 和 MinGW 的 steady_clock 底层多基于 QueryPerformanceCounter(QPC),但某些旧 BIOS 或电源管理策略会让 QPC 返回值抖动,表现为连续调用 now() 得到相同值,或相邻值差小于 100 纳秒。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 运行前调用
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)并禁用 CPU 节能(如设置电源计划为“高性能”) - 用
QueryPerformanceFrequency(&freq)检查实际频率,若低于 2.5 MHz(即周期 > 400 纳秒),说明硬件或驱动不支持亚微秒级计时 - 避免在虚拟机中测试——多数 hypervisor 对 QPC 支持不完整,返回值常被模拟为毫秒级
- Linux 用户不用操心这个:glibc 下
steady_clock绑定CLOCK_MONOTONIC,现代内核默认支持纳秒级,clock_getres(CLOCK_MONOTONIC, &ts)可查实际分辨率
真正难的不是写对语法,而是确认你的硬件+OS+运行时环境是否真能支撑微秒级区分——很多“精确计时”失败,卡在 BIOS 设置或容器 cgroup 限制上,而不是代码本身。


















