不能直接当定时器用,它只是时间工具;需自行实现循环、超时判断和回调调度,否则易出现精度偏差、线程不安全、UI崩溃、资源耗尽及悬垂引用等严重问题。
std::chrono + std::thread 能否直接做定时器?
不能直接当「定时器」用,它只是时间工具。你得自己搭循环、判断超时、调回调——容易漏掉精度控制和线程安全问题。
常见错误现象:
睡太久或太短,尤其在系统负载高时偏差可达几十毫秒;回调在子线程执行,但用户代码假设在主线程里改 UI 或访问
,结果崩得无声无息。
别用
+
做长周期定时(比如 5 分钟),系统休眠或调度延迟会让下次触发严重偏移
如果回调要访问共享数据,必须加锁,或改用
保护简单标志位
优先用
,不用
——后者可能被 NTP 调整,导致“时间倒流”误判超时
如何避免重复创建线程开销?
每次 setTimer 都 new 一个
,短周期高频定时(如 10ms)会迅速耗尽线程资源,甚至触发
。
正确做法是复用单个后台线程,靠队列驱动多个定时任务:
立即学习
“
C++免费学习笔记(深入)
”;
用
存待触发的定时器,按唤醒时间排序,顶部是最先要触发的
后台线程只做一件事:等最近那个定时器到期,pop 出来,调回调,再 loop
插入新定时器时用
唤醒等待中的线程,避免死等
示例关键逻辑:
std::function 捕获变量后生命周期怎么管?
这是最常踩的坑:回调里用了局部变量的引用或指针,定时器还没触发函数就返回了,回调一执行就 UB。
C知道
CSDN推出的一款AI技术问答工具
下载
典型错误写法:
安全做法只有两种:
值捕获全部依赖项:
(适合小对象、可拷贝)
用
包裹大对象,回调捕获该智能指针:
绝对不要捕获栈上容器的迭代器、
返回的指针——它们随局部变量销毁而失效
Windows 下 Sleep(1) 为什么不准?
不是 C++ 问题,是 Windows 内核默认时间粒度为 15.6ms。即使你
,实际可能睡 16ms,累积误差极大。
解决办法有限但有效:
调一次
(需
),提升系统计时精度到 1ms(注意:影响全局,退出前配对调
)
Linux/macOS 不需要这步,
或
默认支持 sub-ms 精度
若只需“大约”精度(如心跳包 30s ± 1s),干脆别纠结 1ms,用
更稳
复杂点在于:跨平台时,精度控制、线程唤醒机制、回调执行上下文都得隔离。轻量 ≠ 简单,真正可靠的定时器哪怕只有 200 行,也得把 clock、queue、lifecycle、cancel 逻辑全兜住。
std::this_thread::sleep_forstd::vectorwhile (true)sleep_forstd::atomicstd::chrono::steady_clocksystem_clockstd::threadstd::system_error: Resource temporarily unavailablestd::priority_queuestd::condition_variable::notify_one()
auto now = std::chrono::steady_clock::now();
auto when = now + std::chrono::milliseconds(100);
timer_queue.push({when, []{ /* callback */ }});
cv.notify_one(); // 唤醒空闲线程
void start_timer() {
int value = 42;
timer.set(1000, [&value]{ printf("%d\n", value); }); // 危险!
}
[value]{ printf("%d\n", value); }std::shared_ptr[ptr = shared_from_this()]{ ptr->do_work(); }std::string::c_str()sleep_for(1ms)timeBeginPeriod(1)#include timeEndPeriod(1)nanosleepclock_nanosleepsleep_for(30s)