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 并且不允许停止视频

QT串口编程 - 阻塞主机示例(Blocking Master)

当主线程显然未阻塞时,QProgressDialog 冻结

等待QThread时UI会阻塞/如何正确使用QThread

我不确定为啥我的 QThread 模式会阻塞

如何停止运行阻塞 Forever 循环的 QThread?