繁体   English   中英

具有第二个线程的快速更新GUI窗口会因调整窗口大小或移动窗口而崩溃

[英]Fast updating GUI window with a second thread crashes by resizing or moving the window

我有一个图像获取线程,该线程将在使用Visual Studio 2015编译的64位Qt 5.6.0应用程序中的每个抓取中更新GUI。除非用户不调整大小或移动GUI窗口,否则该应用程序将正常运行。 但是,如果窗口被移动或调整大小,它将随机崩溃。 代码摘要如下。

根据调试信息,由于QImage::convertToFormat_helper的访问冲突而导致崩溃,有人知道为什么会发生这种情况以及如何解决?

初始化:

auto thread = new KinectThread();
connect(thread,SIGNAL(OnRgbImage(QImage)),this,SLOT(rgbImageReady(QImage)));
thread->start();

`

工作者线程:

void KinectThread::run()
{
    kinect = new Kinect();

    while(true)
    {
        auto img = kinect->getRgb();
        QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
        emit OnRgbImage(imgIn);
        QThread::msleep(20);
    }

    delete kinect;
}

`

GUI更新:

void MainWindow::rgbImageReady(QImage image)
{
    if (!image.isNull())
    {
        QGraphicsView* view = ui->graphicsView;
        auto width = image.width();
        auto height = image.height();
        m_pScene->setSceneRect(0, 0, width, height);
        auto pixmap = QPixmap::fromImage(image);
        m_pixmapItem->setPixmap(pixmap);
        view->show();
    }
}

使用uchar *data作为图像数据的QImage构造函数不会创建数据的副本,这意味着它们要求uchar *缓冲区的生存时间至少与QImage实例一样长。

此外, QImage隐式共享的 ,这意味着复制QImage也不会复制图像数据,但仍会访问原始缓冲区。

这样可以很好地复制图像并将其通过信号传递。 但这也意味着从kinect->getRgb()调用来的图像数据必须一直存在,直到信号事件已通过事件队列传递到MainWindow::rgbImageReady并完成使用数据为止。 这也意味着,如果Kinect类更改了已传递给rgbImageReady的现有缓冲区,而您使用QPixmap::fromImage(image)从图像创建像素图时,则会陷入混乱。 如果Kinect类在rgbImageReady完成之前的缓冲区之前删除了现有缓冲区(例如,由于窗口大小改变而分配了较大的缓冲区),则会遇到访问冲突。

通过考虑@ E4Z9关于QImage不拥有其数据所有权的暗示,很明显,在第二个线程中对QImage数据的破坏还不成熟。 因此,将QImage深层副本传递到信号中可以解决此问题。

emit OnRgbImage(imgIn.copy());

因此,这是一个不成熟的对象破坏问题,暴露于无关的大小调整和窗口移动中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM