【问题标题】:How to handle signal flood from another thread in Qt如何在 Qt 中处理来自另一个线程的信号泛滥
【发布时间】:2026-02-14 08:05:02
【问题描述】:

tl;dr:我有一个 QThread,只要有新数据可供处理,它就会向主线程发送一个信号。然后主线程获取、处理和显示数据。数据到达的频率更高,主线程能够对其进行处理,从而导致 GUI 冻结并最终导致堆栈溢出(耶!)。

详情

我的应用程序从相机获取帧以进行处理和显示。当新帧可用时,相机会通过 windows 事件进行通知。我有一个线程定期检查这些事件并在新帧可供抓取时通知主线程:

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

    while (running_)
    {
        if (WaitForSingleObject(nextColorFrameEvent, 0) == WAIT_OBJECT_0)        
            emit signalColorFrame();        

        usleep(15);
    }
}

signalColorFrame 连接到Camera 类中的插槽,该插槽从相机获取帧,进行一些处理并将其发送到MainWindow,后者将其绘制到屏幕上。

void Camera::onNewColorFrame()
{    
    getFrameFromCamera();
    processFrame();
    drawFrame();
}

现在,如果该方法在下一帧可用之前完成,则一切正常。随着处理变得越来越复杂,尽管Camera 类在处理前一帧之前接收到新信号。

我的解决方案是在处理时阻止来自工作线程的信号,并强制偶数循环在 QCoreApplication::processEvents() 之间运行:

void Camera::onNewColorFrame()
{   
    worker_->blockSignals(true)
    getFrameFromCamera();
    processFrame();
    drawFrame();
    QCoreApplication::processEvents(); // this is essential for the GUI to remain responsive
    worker_->blockSignals(false);
}

这看起来是一种好方法吗?有人可以提出更好的解决方案吗?

【问题讨论】:

  • 好的,我删除了关于此解决方案不可靠的部分,因为那是由于我的错误。它几乎可以按预期工作。

标签: c++ multithreading qt video-streaming kinect


【解决方案1】:

我认为在解决技术方面的问题之前,您应该考虑考虑应用程序的设计方面。有几种方法可以解决您的问题,但首先您应该决定如何处理您没有时间在主线程中处理的帧。您是要跳过它们还是保存以供以后处理,但是您应该意识到处理队列仍然必须有一定的大小限制,因此您无论如何都应该决定如何处理“超出范围”的数据。

我个人更喜欢在这种情况下制作一些中间容器来保存在某处接收到的数据,因此您的相机处理线程只需通知收集器接收到的数据,然后收集器决定它是否要存储或跳过数据。一旦有时间访问收集器,主循环就会以 fetchNext() 或 fetchAll() 形式访问,具体取决于您的需要并实现对象处理。

【讨论】:

  • 是的,我一直在考虑这个问题。他们目前的工作方式只是在处理完最后一个帧之前不接受新帧,然后获取当前可用的帧(所以是最新的帧)。这是针对实时数据的。我还将进行离线处理,其中类似于您建议的解决方案会更合适。
  • 这样我认为你根本不需要发出信号。为什么你应该通知它自己决定的东西然后它有可用的处理时间。因此,与其发出信号并传递将被丢弃的应用程序数据,不如将最新帧存储在您的 Camera 对象中并制作线程安全的方法,例如 getLatestFrame(),因此主线程一旦没有工作就会检查是相机有东西要处理...
  • 工作线程只发出新帧可用的信号,它不传递任何数据。数据在主线程中检索(这是 Caera 对象存在的)。我需要一个工作线程的原因是循环不断检查是否发生了事件,否则会阻塞 GUI。
  • 好吧,那么我会发布事件而不是发出信号。由于不同的原因,我认为在线程之间发送信号不是一个好主意。至少使用排队连接类型。 (但这实际上是事件的信号/槽机制包装器)
  • 我不知道如何处理 Qt 中的事件。如果我发布事件如何在没有消息循环的情况下处理它?