《C++编程原理与实践》第三版:timer_wait回调结果异常问题
PPP图形库timer_wait阻塞版与回调版行为差异分析及解决
为什么两种实现结果不同?
问题根源在于timer_wait的Qt实现使用了共享的单个QTimer对象:
- 阻塞版的
timer_wait是串行执行逻辑:先阻塞2秒修改c1颜色,再阻塞4秒修改c2颜色,两次等待是先后顺序,总时长6秒。 - 回调版中,连续调用两次
timer_wait时,每次调用都会执行user_timer.start(milliseconds)。而QTimer的start方法会重置当前正在运行的定时器——第一次设置的2秒定时器被第二次的start(4000)直接覆盖,导致两个回调都被安排在程序启动后的4秒时触发,最终出现4秒时两个圆形同时变色的异常。
结合给出的timer_wait实现代码来看:每次调用都会给同一个user_timer绑定新的回调,但user_timer.start()会终止之前的计时并重新开始新时长的计数,因此第一个2秒的定时器根本没机会触发就被覆盖了。
如何用回调方式实现预期效果?
有两种可行方案:
方案1:链式回调(无需修改库代码)
利用回调嵌套,在第一个回调执行完成后再启动第二个定时器,完全复刻阻塞版的串行逻辑:
// 替换原有的两个timer_wait调用 w.timer_wait(2000, [&]{ c1.set_fill_color(Color::red); // 第一个颜色修改完成后,启动4秒的定时器 w.timer_wait(4000, [&]{ c2.set_fill_color(Color::blue); }); });
这种方式下,第二个定时器的4秒计时从第一个颜色修改完成后开始,和阻塞版的行为完全一致。
方案2:修改库的timer_wait实现(使用独立定时器)
如果希望支持多个并行的定时器,可以修改WindowPrivate::timer_wait的实现,每次创建独立的QTimer对象,避免互相干扰:
void WindowPrivate::timer_wait(int milliseconds, std::function<void()> cb) { if (!accept_waits) return; // 每次创建新的QTimer,而非共享同一个user_timer QTimer* timer = new QTimer(); QObject::connect(timer, &QTimer::timeout, [timer, func = std::move(cb)] { func(); timer->deleteLater(); // 回调执行完毕后自动销毁定时器 }); timer->start(milliseconds); }
修改后,调用时需要调整第二个定时器的时长为6000毫秒(2秒+4秒),才能和阻塞版的时序一致:
w.timer_wait(2000, [&]{c1.set_fill_color(Color::red);}); w.timer_wait(6000, [&]{c2.set_fill_color(Color::blue);});
内容的提问来源于stack exchange,提问作者freeze
相关产品推荐
相关产品推荐

