You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:10:12