C++ QThread阻塞主应用程序
我有一个简单的表单UI,它有一个按钮槽,启动一个线程:C++ QThread阻塞主应用程序,c++,qt,multithreading,qthread,C++,Qt,Multithreading,Qthread,我有一个简单的表单UI,它有一个按钮槽,启动一个线程: void MainWindow::LoadImage() { aThread->run(); } run()方法如下所示: void CameraThread::run() { qDebug("Staring Thread"); while(1) { qDebug("ping"); QThread::sleep(1); } } 当我单击调用LoadImage(
void MainWindow::LoadImage()
{
aThread->run();
}
run()方法如下所示:
void CameraThread::run()
{
qDebug("Staring Thread");
while(1)
{
qDebug("ping");
QThread::sleep(1);
}
}
当我单击调用LoadImage()的按钮时,UI将变得无响应。我周期性地将“ping”消息视为调试输出,但UI挂起,没有任何响应。
为什么我的线程没有单独运行?派生为公共QThread的CameraThread
我正在使用gcc版本4.4.3(Ubuntu 4.4.3-4ubuntu5)和来自Ubuntu 10.04(x86)存储库的QT库和QT创建者。您必须调用线程->开始(),而不是运行。。。run是线程的入口点。线程以start开始。您可以直接调用run,这就是为什么要阻止gui。检查QThread的文档。virtual void QThread::run()受保护(并非没有原因)简短回答:通过调用
aThread->Start()启动线程代码>非运行()
,并确保线程的run()方法受保护(非公共)
解释
启动线程,因为它提供优先级调度,并在自己的线程上下文中实际执行run()
方法
看起来您将在这个线程中加载图像,所以在您遇到许多人在使用QThread时遇到的陷阱之前,我将提供一些提示
QThread本身不是一个线程。它只是一个围绕线程的包装器,这让我们想到
在CameraThread
类中定义的信号/插槽不一定在线程的上下文中运行,请记住,只有run()方法和从中调用的方法在单独的线程中运行
依我看,在大多数情况下,将QThread子类化是而不是的方向。使用下面的代码,您可以做得更简单,并且它将为您节省许多麻烦
class ImageLoader : public QObject {
Q_OBJECT
public slots:
void doWork()
{
// do work
}
};
void MainWindow::MainWindow(/*params*/)
{
ImageLoader loader;
QThread thread;
loader.moveToThread( &thread );
connect( this, SIGNAL( loadImage() ), &loader ,SLOT( doWork() ) );
thread.start();
// other initialization
}
void MainWindow::LoadImage()
{
emit loadImage();
}
另外,请阅读与此主题相关的。我认为问题可能是您没有在构造函数中调用QtCore.QThread.\u init\uuuuself。我也有同样的问题。另外,我认为不应该重写start函数,而应该重写run()函数。这解决了我遇到的同样问题。即使没有任何sleep()延迟,窗口也应该响应。QT文档通过子类化解释了QThread的用法。为什么这是个坏主意?@Atilla-如果你阅读Casey回答中的QT博客链接,你会发现它的标题是“你做错了…”。这是关于为什么Qt关于子类化QThread的文档不是执行线程的正确方法的讨论。另外,如果我正确阅读了博客条目,那么它是由编写原始Qt文档的人写的。是的,这是正确的。基本上,Qt文档是误导性的,因此导致许多人做了一些令人讨厌的事情(比如Qthread构造函数中的movetoThread(这一点)),这会导致后续问题。希望文档很快就会更新。@photo_tom,@Casey,谢谢你们两位的澄清。在我的例子中,我的独立线程没有任何插槽,应该在自定义循环(连续轮询硬件)中运行,并且只需要偶尔通知主应用程序。所以在我的例子中,我相信子类化是正确的方法。我知道这是一个长期的死问题,但我不同意将QThread对象子类化为正确的方法。。。仍然创建QObject和threadInstance.moveToThread(myObjInstance)代码>但是只要有一个插槽,当被调用时它将永远循环(或者直到某个条件变量从另一个sig/插槽连接被更改)。这还有一个额外的好处,就是可能使用同一个线程来做更多的事情,而不仅仅是一个对象工作(你可以在一个单独的线程中创建更多的对象),只要你在cont循环中执行processEvents
,一切都会很好。不,我的问题是调用run()而不是start()。我已经重写了run()。