QThread 阻塞主应用程序
Posted
技术标签:
【中文标题】QThread 阻塞主应用程序【英文标题】:QThread blocking main application 【发布时间】:2010-07-09 14:47:45 【问题描述】:我有一个简单的表单 UI,它有一个按钮槽,启动一个线程:
void MainWindow::LoadImage()
aThread->run();
run() 方法如下所示:
void CameraThread::run()
qDebug("Staring Thread");
while(1)
qDebug("ping");
QThread::sleep(1);
当我单击调用 LoadImage() 的按钮时,UI 变得无响应。我定期将“ping”消息视为调试输出,但 UI 挂起,不响应任何内容。 为什么我的线程没有单独运行? CameraThread 派生为公共 QThread 我正在使用 gcc 版本 4.4.3 (Ubuntu 4.4.3-4ubuntu5) 以及来自 Ubuntu 10.04(x86) 存储库的 QT 库和 QT Creator。
【问题讨论】:
【参考方案1】:简答:通过调用aThread->start();
而不是run()
启动您的线程,并确保您线程的run() 方法受到保护(不公开)。
说明
Calling start()
is the correct way 启动线程,因为它提供优先级调度并在自己的线程上下文中实际执行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();
另请阅读有关此主题的Qt blog。
【讨论】:
QT 文档通过子类化解释了 QThread 的使用。为什么这是个坏主意? @Atilla - 如果您阅读 Casey 回答中的 QT 博客链接,您会发现它的标题为“您做错了……”。这是关于为什么 Qt 关于子类化 QThread 的文档不是执行线程的正确方法的讨论。此外,如果我正确阅读了该博客条目,那么它是由编写原始 Qt 文档的人编写的。 是的,没错。基本上,Qt 文档具有误导性,因此导致许多人做一些不合时宜的事情(例如 Qthread 构造函数中的 movetoThread(this)),这会导致问题发生。希望文档能尽快更新。 @photo_tom,@Casey,谢谢你们的澄清。就我而言,我的单独线程没有任何插槽,应该在自定义循环中运行(不断轮询硬件),并且只需要偶尔通知主应用程序。所以就我而言,我相信子类化是正确的方法。 我知道这是一个长期死的问题,但我不同意将 A QThread 对象子类化为正确的方法......仍然创建你的 QObject 和threadInstance.moveToThread(myObjInstance);
但只有一个插槽调用时将永远循环(或直到某些条件变量从另一个 sig/slot 连接更改)。这有一个额外的好处,即可能使用相同的确切线程来做更多的事情,而不仅仅是一个对象工作(你可以在一个单独的线程中使用尽可能多的对象)只要你在你的 cont 循环中执行processEvents
,一切都会好的。【参考方案2】:
你必须调用 thread->start() 不运行...运行是线程的入口点。线程以 start 开始。你直接调用run,这就是你阻止你的gui的原因。检查 QThread 的文档。 virtual void QThread::run() 受到保护(并非没有原因)
【讨论】:
【参考方案3】:我认为问题可能是您没有在构造函数中调用 QtCore.QThread._init__(self)。我遇到过同样的问题。另外我认为你不应该重写 start 函数,只需重写 run() 函数。这解决了我遇到的同样问题。即使没有任何 sleep() 延迟,窗口也应该是响应式的。
【讨论】:
不,我的问题是调用 run() 而不是 start()。我已经覆盖了 run()。以上是关于QThread 阻塞主应用程序的主要内容,如果未能解决你的问题,请参考以下文章
g_main_loop_run 阻塞 Qthread 并且不允许停止视频