从非GUI线程使用QWidget :: update()

Ana*_*sia 4 qt thread-safety libvlc

有时我的应用程序在非GUI线程中执行的QWidget :: update()崩溃.

我正在开发一个应用程序,从远程主机接收视频帧并在QWidget上显示它们.

为此,我使用libVLC库给我一个解码图像.我在libVLC回调中接收图像,该图像在单独的libVLC线程中执行.在这个回调中,我正在尝试执行QWidget :: update()方法.有时应用程序崩溃,并且callstack在这个方法中的某个地方.这是我的回调代码:

//! Called when a video frame is ready to be displayed, according to the vlc clock. 
//! \c picture is the return value from lockCB().

void VideoWidget::displayCB(void* picture)
{
    QImage* image = reinterpret_cast<QImage*>(picture);

    onScreenPixmapMutex_.lock();
    onScreenPixmap_ = QImage(*image);
    onScreenPixmap_.detach();
    onScreenPixmapMutex_.unlock();

    delete image;

    update();
}
Run Code Online (Sandbox Code Playgroud)

我知道Qt中不允许主线程外的GUI操作.但根据文档QWidget :: update()只是在Qt返回主事件循环时调度一个paint事件进行处理,并且不会立即重新绘制.

问题是:QWidget :: update()是否适用"主线程外的GUI操作"规则?此操作是否属于"GUI操作"?

我使用Qt 4.7.3,在Windows 7和Linux上进行崩溃.

O.C*_*.C. 6

查看Mandelbrot示例.在该示例中,工作线程正在生成图像并将其传递给具有信号/槽机制的渲染小部件.使用相同的方法!

您可以直接连接窗口小部件的update()插槽,而不是实现示例中给出的新updatePixmap()插槽.

从您的代码中我可以看到您有一个互斥锁来提供并发访问.因此,直接使用更新槽应该很容易.

两种方法仍然使用信号/插槽机制,因为在Qt中不允许主线程外部的GUI操作.

  • 谢谢.现在我从非GUI线程发出一个信号,并将它连接到所需小部件的QWidget :: update()插槽.崩溃不会重现. (2认同)

Cal*_*itt 5

问题是:是否适用于QWidget :: update()的规则"不允许在主线程之外的GUI操作"?此操作是否属于"GUI操作"?

是.更新属于GUI操作.根据文档,所有QWidget和派生类只能由主线程使用.这是通用的,并且特定的函数可以声明它们是线程安全的,但是在这种情况下update()没有,因此从其他线程调用是不安全的.

信号/插槽机制有效,因为Qt将(除非另有说明)使用事件来允许一个线程中的插槽被另一个线程中的信号触发.如果您使用信号/插槽并告诉Qt不要进行特殊的线程处理,则会再次出现崩溃.