简体   繁体   中英

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

I have an image acquisition thread that is updating GUI per each grab in a 64-bit Qt 5.6.0 application compiled with Visual Studio 2015. Unless user does not resize or move the GUI window, the application is working fine. But if the window is moved or resized, it randomly crashes. Code summary is following.

According to debugging information, the crash happens because of access violation in QImage::convertToFormat_helper Anybody knows why this is happening and how it can be fixed?

Initialization: `

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

`

Worker thread: `

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 Update:

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();
    }
}

The QImage constructors taking uchar *data for the image data do not create a copy of the data, meaning that they require the uchar * buffer to live at least as long as the QImage instance.

Additionally, QImage is implicitly shared , meaning that copying a QImage does not copy the image data either, but still accesses the original buffer.

That is good in the way that copying the image and passing it through the signal is fast. But it also means that the image data from the kinect->getRgb() call must live until the signal event has been passed through the event queue to MainWindow::rgbImageReady and until this has finished using the data. It also means that if the Kinect class changes the existing buffer that has been passed to rgbImageReady , while you create a pixmap from the image with QPixmap::fromImage(image) , you'll get a mess. And you'll get an access violation if the Kinect class deletes the existing buffer (for example because it allocates a larger buffer because the window size changed) before rgbImageReady finished with the previous buffer.

By considering @E4Z9's hint that QImage does not take ownership of its data, it was then obvious that destruction of the QImage data was immature in the second thread. Thus, passing deep copy of the QImage into the signal fixed the problem.

emit OnRgbImage(imgIn.copy());

So it was a problem of immature object destruction which was exposed with unrelated resizing and moving of window.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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