簡體   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