std::chrono+std::thread休眠适合毫秒级轻量定时任务,但受调度影响存在抖动;std::jthread+stop_token可安全终止;Windows用CreateWaitableTimerA、Linux用timerfd_create实现高精度,但需注意系统限制与偏差补偿。

std::chrono + std::thread 循环休眠适合轻量级定时任务
精度在毫秒级、对时序抖动不敏感的场景(比如心跳上报、状态轮询),用 std::this_thread::sleep_for 配合 std::chrono 最直接。它不依赖系统底层定时器,可移植性好,但本质是“忙等+休眠”,实际间隔受线程调度影响。
- 别用
std::this_thread::sleep_until做长周期定时——如果系统时间被手动调整,可能跳过一次触发 - 每次休眠前要重新计算下一次目标时间点,避免累积误差;示例中常见错误是写成固定步长
sleep_for(100ms),跑久了会漂移 - Windows 上
sleep_for(1ms)实际可能延迟 15ms,Linux 默认调度周期也常为 10ms;真要压到 1ms 以下,得调高线程优先级或改用clock_nanosleep
std::jthread + stop_token 可安全终止定时循环
C++20 的 std::jthread 自带协作式中断能力,比裸 std::thread + 原子标志位更可靠。尤其当你需要在程序退出或配置变更时立刻停掉定时器,它能避免竞态和资源泄漏。
- 必须在循环内定期检查
stop_token::stop_requested(),否则request_stop()不生效 - 不要在
stop_callback里做耗时操作(如锁全局资源、发网络请求),它运行在调用request_stop()的线程上下文中 - 示例代码中容易漏掉
join()或detach()——std::jthread析构时自动join(),但若你提前 move 出去,就得自己管
Windows 下用 CreateWaitableTimerA 实现 sub-ms 精度
需要微秒级响应(比如音频同步、硬件采样触发),Windows 原生 API 比标准库更靠谱。CreateWaitableTimerA 配合 SetWaitableTimer 能做到理论 100ns 分辨率,实际受 DPC 延迟和电源策略限制。
- 必须用
TIMECAPS查询系统支持的最小精度,timeGetDevCaps返回的wPeriodMin才是真实下限(常为 1ms) - 设置
dwPeriod > 0启用周期模式,但首次触发仍需手动SetWaitableTimer;漏掉这一步会导致只触发一次 - 回调函数不能是普通成员函数——得用静态函数或 lambda +
std::bind绑定 this,且必须确保对象生命周期长于定时器
Linux 下 timerfd_create 是最干净的 POSIX 方案
timerfd_create 把定时器封装成文件描述符,可直接塞进 epoll/kqueue,避免额外线程和唤醒开销。适合嵌入事件驱动框架(如 libuv、asio),也方便做多定时器统一管理。
立即学习“C++免费学习笔记(深入)”;
- 创建后必须用
timerfd_settime启动,否则读timerfd会永远阻塞;it_value设为 0 表示“不启动”,不是“立即触发” - 读取返回的是
uint64_t类型的超时次数,不是时间戳——多次未读会累积,容易误判为“卡顿” - 记得设
TFD_CLOEXEC标志,否则 fork 后子进程会继承该 fd,导致定时器意外触发
高精度不等于高稳定性。哪怕用了 timerfd 或 CreateWaitableTimer,如果线程被抢占、CPU 频率动态缩放、或系统启用了节能模式,实测抖动仍可能翻倍。真正关键的定时逻辑,得配合硬件时间戳(如 RDTSC)做偏差补偿,而不是只靠 API 声称的精度。











