[英]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.