使用第二个线程快速更新 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 窗口的大小或移动 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;
}
'
图形用户界面更新:
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();
}
}
QImage
构造函数为图像数据获取uchar *data
不会创建数据的副本,这意味着它们需要uchar *
缓冲区至少与 QImage 实例一样长。
此外,QImage
是隐式共享的,这意味着复制QImage
也不会复制图像数据,但仍会访问原始缓冲区。
这很好,因为复制图像并通过信号传递速度很快。但这也意味着,来自kinect->getRgb()
调用的图像数据必须一直存在,直到信号事件通过事件队列传递到MainWindow::rgbImageReady
,直到使用完数据。这也意味着,如果Kinect
类更改了已传递给rgbImageReady
的现有缓冲区,而您从带有QPixmap::fromImage(image)
的图像创建像素图,则会弄得一团糟。如果Kinect
类在完成上一个缓冲区之前删除了现有缓冲区(例如,因为它分配了更大的缓冲区,因为窗口大小已更改),则rgbImageReady
将出现访问冲突。
通过考虑@E4Z9暗示 QImage 不拥有其数据的所有权,很明显,在第二个线程中销毁 QImage 数据是不成熟的。 因此,将QImage
的深度拷贝传递到信号中可以解决问题。
emit OnRgbImage(imgIn.copy());
因此,这是一个不成熟的对象破坏问题,通过不相关的窗口大小调整和移动而暴露出来。
- 在C++中获取应用程序窗口的大小
- Wxwidgets - 如何添加调整大小事件处理程序以使"X"绘图随窗口调整大小?
- 如何以编程方式更改基于对话框的窗口的大小和位置?
- 如何在Qt中修复MDI子窗口的大小
- win32 自动调整父窗口的大小以适合其内容
- 如何调整地铁窗口的大小
- 调整 SDL2 窗口的大小
- Buit矩形(我自己的类型),不会随窗口调整大小
- 获取确切的窗口区域大小 - 创建窗口窗口大小不正确
- 插件如何调整其窗口的大小
- 在 C 语言中将窗口控制台大小调整为全屏
- 调整Qml窗口的大小
- 如何有效地调整DirectX窗口的大小
- 设置MFC应用程序中窗口的大小
- 如何在VTK中自动调整渲染窗口的大小
- 调整我简单的OpenGL/GLUT窗口的大小会产生奇怪的线条
- 设置OpenGL中窗口的大小
- 如何修复我的Qt窗口的大小
- 当嵌入一个应用程序到Qt应用程序,如何获得mouseMoveEvent和嵌入窗口的大小
- 如何更改窗口的大小DepthBasics