【问题标题】:Queue several QTimers calls to slots将多个 QTimers 调用排队到插槽
【发布时间】:2014-04-26 16:43:23
【问题描述】:

我正在使用一个库,我需要在其中调用一个触发器函数,该函数开始一些处理(启动一个执行该工作的线程)并立即返回。然后当处理完成时会发出一个信号。

这需要根据不同的参数定期进行。由于在处理过程中不能对触发函数进行其他调用,因此我需要以某种方式将它们排队。我考虑过使用 QEventLoop(“循环”),但到目前为止没有运气。

请看这段代码:

test::test()
    {
    connect(&timer,   SIGNAL(timeout()), this, SLOT(timerSlot()));
    connect(&timer2,  SIGNAL(timeout()), this, SLOT(timer2Slot()));
    connect(&library, SIGNAL(processingFinished()), &loop, SLOT(quit()));

    timer.setInterval(2000);
    timer.start();

    timer2.setInterval(4000);
    timer2.start();
    }

void test::timerSlot()
    {
    loop.exec();
    startProcessing(some_parameters);
    }

void test::timer2Slot()
    {
    loop.exec();
    startProcessing(some_other_parameters);
    }

问题是在处理过程中调用 loop.exec() 时,我会收到消息:

QEventLoop::exec: instance xxxxxx has already called exec()

什么是做我想做的事情的正确方法?

提前致谢。

【问题讨论】:

  • 如果您想在处理参数时阻止定时器槽执行,您可以让定时器槽断开信号槽连接,并在处理完成后重新连接。但是,这不会“排队”处理期间发生的其他计时器事件。您能解释一下通过排队计时器事件来实现的目标吗?您是否希望所有排队的计时器事件在处理完成后立即执行?
  • 您好@deGoot,感谢您的回答!这是一个服务器-客户端模型。我需要定期轮询客户端以更新服务器上的信息。每 x 秒应该发生不同类型的轮询。我对排队所​​有未决的民意调查不感兴趣,但至少如果两个同时发生或在前一个民意调查正在进行时,我想在第一次完成后执行最后一个。关于您的建议,我认为这可能会对轮询周期产生重大影响,因为计时器将每 x 秒调用一次 slot 以及中间的所有“暂停”。
  • 在这种情况下,您可以只使用成员bool m_is Processing 变量并将计时器代码包装在if(!m_isProcessing) 中。您还可以有一个成员变量来指示在您处理时是否有另一个计时器关闭。并在处理完成后重置 m_isProcessing 并启动其他计时器的操作。
  • 谢谢@deGoot!你的解决方案是一个非常简单的解决方案,如此简单以至于我没有想到,在考虑复杂的替代方案之前我无法弄清楚。它解决了我的问题。如果您想发布答案,我很乐意将其设置为已接受。
  • 很高兴我的建议对您有用。我知道当您认为自己正在处理一个复杂的问题时,错过一个简单的解决方案是什么感觉。

标签: c++ qt qt-signals qtimer qeventloop


【解决方案1】:

一个简单的解决方案是引入一个成员变量,例如bool m_isProcessing,只有在m_isProcess == false时才开始处理,然后在开始处理时将其设置为true,并在处理完成时将其重置为false .由于test QObject 的槽在 GUI/主线程上执行,因此您无需担心计时器槽与处理完成时将执行的槽之间的同步。

如果你想跟踪处理过程中发生的事件,你可以使用相同的方法:在test类中引入一个成员变量来跟踪你需要的信息。

【讨论】:

    【解决方案2】:

    您似乎在寻找Qt::QueuedConnection

    Qt::QueuedConnection 2 当控制返回接收者线程的事件循环时调用槽。该槽在接收者的线程中执行。

    因此,你可以这样写:

    connect(&timer, SIGNAL(timeout()), SLOT(timerSlot()), Qt::QueuedConnection);
    connect(&timer2, SIGNAL(timeout()), SLOT(timer2Slot()), Qt::QueuedConnection);
    

    有关详细信息,您可以查看著名的 mandelbrot 示例,尽管它使用的是工作线程:

    Mandelbrot Example

    【讨论】:

    • 你好@LaszloPapp 谢谢你的回答。似乎尽管我使用 Qt::QueuedConnection loop.exec() 在 loop:quit() 之前多次调用了连接。
    • @Fracu:完全删除你的循环。
    • 定时器调用的槽只是触发库处理。他们立即完成。所以队列需要走得更远。只有在上一个处理完成后才允许下一个插槽调用(在我的示例中,当库发出一个退出循环的信号时发生这种情况)。它是一个异步处理。我相信图书馆内部正在启动线程。
    • AI 只会删除循环...仅使用应用程序事件循环。
    • 不,它没有工作,因为插槽正在调用“startProcessing()”,并且这个函数只是启动一个执行该工作的线程,在线程启动后它立即返回到主事件循环并执行对插槽的后续调用(我们不希望这样)。只有当线程完成其工作时(几秒钟后),它才会发出一个信号,表明它在我的示例中(最终)连接到 loop::quit()。
    猜你喜欢
    • 2018-09-20
    • 2020-12-26
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多