【问题标题】:Why message loop doesn't block the GUI in windows app but does in Qt?为什么消息循环不会阻止 Windows 应用程序中的 GUI,但在 Qt 中会阻止?
【发布时间】:2013-04-13 11:39:32
【问题描述】:

我正在开发一个使用 Qt 的程序,我的一些代码基于 Windows 示例。我遇到的问题,我不太明白的问题是,相同的代码将如何阻止我的 Qt GUI,而它在 Windows 应用程序中完全可以正常工作。

这是一个例子。我有一个程序,它从相机获取一些数据,对其进行一些处理,然后将其显示在屏幕上。在 Windows 示例中有这样的内容:

// Create an event with these self-explanatory parameters
// This event signals when the next frame is ready to process
HANDLE frameEvent  = CreateEvent(nullptr, TRUE, FALSE, nullptr)

// Now run a while loop which magically doesn't block
HANDLE hEvents[1];

while (WM_QUIT != msg.message)
{
  hEvents[0] = frameEvent;

  DWORD dwEvent = MsgWaitForMultipleObjects(1, hEvents, FALSE, INFINITE, QS_ALLINPUT);

  // If we have our event run some processing
  if (WAIT_OBJECT_0 == dwEvent)
  {
    update();
  }
  // Else handle input or whatever
}

更新函数如下所示:

if (WAIT_OBJECT_0 = WaitForSingleObject(frameEvent, 0)
{
  getTheFrame();
  processTheFrame();
  drawTheFrame();
}

如果我尝试在 Qt 中以相同的方式实现它,一切都会冻结,while 循环将永远运行。我的解决方案是在单独的线程(QThread)中运行循环并在新帧准备好时发出信号,如下所示:

void Worker::run()
{
    running_ = true;

    while (running_)
    {
        if (WaitForSingleObject(frameEvent, 0) == WAIT_OBJECT_0)
        {
            emit signalFrame();
        }

        // This is necessary or it will still freeze!
        usleep(15);
    }
}

然后将信号连接到与 windows 示例中的 Update() 方法执行类似工作的插槽。

现在,这可以正常工作,但只要在下一帧可用之前处理单个帧即可。

随着我的处理变得更复杂并且比相机帧速率更慢,程序停止响应。 windows 示例中完全相同的代码仍然可以正常工作,帧率只是下降,但所有内容都已绘制并且 GUI 保持响应。

有人可以解释发生了什么吗?可能的解决方案是什么?

【问题讨论】:

  • 您实际上替换了 Qt 消息循环,消息现在由 MWFMO 发送。我不知道 Qt 的消息循环是什么样的,但它肯定是非标准的。因此,事故并非不可能。不要发出信号,而是使用 PostMessage,这样帧检索代码仍然在主线程上运行。并使用一个事件来通知线程在检索到帧后恢复循环。
  • 帧检索代码确实在主线程中运行。工作线程定期检查偶数,并在准备好检索新帧时发出信号。我不确定 Qt 的消息循环是否真的被替换了。问题在于相机每秒产生 30 帧,但我只能处理 10 帧。所以在我处理完一帧之前,已经有几帧可用了。暂停循环似乎是一个简单的解决方案(它在 Windows 上是如何工作的?在处理发生时帧是否刚刚丢弃?)。我设法通过使用使其工作
  • QThread::blockSignals()。所以它现在类似于 `onNewFrameReady() { worker.blockSignals(true);做处理(); worker.blockSignals(false); }。我猜使用信号暂停然后恢复循环会产生相同的效果。如果您愿意对此发表评论作为答案,我会接受它作为解决方案。

标签: c++ multithreading qt winapi loops


【解决方案1】:

Win32 版本调用MsgWaitForMultipleObjects。顾名思义,它等待指定对象发出窗口消息(因为它是用QS_ALLINPUT 调用的,任何窗口消息)。大概代码之后也会分派窗口消息。

您的版本调用WaitForSingleObject。顾名思义,它等待指定的对象。它不会解除对窗口消息的阻止。

【讨论】:

  • 你误解了这个问题。在他无法启动 MWFMO 之后,他在 thread 中使用了 WFSO。这是对 WFSO 的正确使用。
  • 是的,这不是真正的问题。我可能可以用 MWFMO 替换线程中的 WFSO,但问题仍然存在。
  • @HansPassant 但问题并没有解释为什么她使用 WFSO 而不是 MWFMO。评论“现在运行一个神奇地不会阻塞的while循环”向我暗示她不明白为什么在她的版本中需要另一个线程。并且声明“如果我尝试在 Qt 中以相同的方式实现它,一切都会冻结,while 循环将永远运行。”似乎是错误的,因为她没有“以同样的方式”实现它。
  • @Marian 为什么是“可能”?您实际上没有尝试过使用 MWFMO 吗?如果是这样,为什么不呢?
  • @Marian 好的,那么你应该在问题中提到这一点。 (抱歉,我通常将“玛丽安”与罗宾汉的“女仆玛丽安”联系起来。)
猜你喜欢
  • 1970-01-01
  • 2011-04-03
  • 2013-10-23
  • 2016-06-19
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
  • 2012-07-12
相关资源
最近更新 更多