如何在Qt GUI中使用线程

How to use threads in Qt GUI

本文关键字:线程 GUI Qt      更新时间:2023-10-16

我有一个应用程序,它可以连续从相机读取图像并将其显示给用户。用户可以调整不同的滑块,如曝光和阈值,以实时修改图像。之后,我还对这个图像进行了一系列计算,这有时会使GUI没有响应,所以我决定使用线程来分配工作负载。

然而,我无法使其正常工作,有时当滑块值更改或尝试保存图像(GUI中的保存按钮)时,我会出现分段错误和一堆"assertion`GLib GObject CRITICAL**:g_object_unref:assertion'g_IS_object(object)'failed"警告,GUI有时会停止更新图像或冻结,因此您无法移动滑块或按下任何按钮。

我尝试使用C++中的标准std::线程,并通过插槽将其连接到启动按钮。

QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(RunStartThread()));
void MainMenu::RunStartThread(){
std::thread t1;
t1= std::thread(&MainMenu::Start,this);
t1.detach();
}
void MainMenu::Start() {
run = true;    
window->mngr->ReadCalibration();
window->mngr->InitializeCameras();
while (run) {
window->mngr->CaptureImage();
window->mngr->ProcessImages();            
UpdateLabels();
}  
window->mngr->Stop();
}

当用户更改滑块值时,他们会更改我的管理器(上面的mngr)中captureImage和ProcessImages使用的变量。当要访问变量时,我尝试使用std::互斥锁/解锁,但它没有改变任何内容。我试着在网上找到如何做到这一点的例子,但还没有找到有连续while循环的东西。

当谈到线程时,我是个新手,所以只要告诉我我是否以错误的方式处理它。

首先,对于线程间通信,使用信号和插槽。默认情况下,Qt连接在线程之间进行良好的线程跳跃,从而避免复杂的同步。

其次,您有三种使用线程的方法:QThread、QRunnable、QtConcurrent::Run(我最喜欢,因为需要最少的代码量)。

如果是QThread,请不要将其子类化!这是常见的设计错误。

示例:

SomeClass::~SomeClass()
{
SignalStop();
future.result();
}
void SomeClass::RunStartThread(){
future = QtConcurrent::run(this, &SomeClass::DoOnThread);
}
void SomeClass::DoOnThread()
{
while (ShouldContinueToRun()) {
QImage im1 = CaptureImage();
emit ImageCaptured(im1);
QImage im2 = ProcessImages(im1);            
emit ImageProcessed(im2);
}
emit JobCompleted();
}

请注意,QObject::connect有最后一个参数,它定义了在涉及不同线程的情况下如何执行插槽调用。请参阅用于此参数的枚举文档
因此,默认情况下,Qt会检测是否需要跳线程。仔细阅读QObject::moveToThread也应该有助于理解这个问题(注意,如果对象有父线程,就不能将其移动到不同的线程)。