【问题标题】:QThread blocking main applicationQThread 阻塞主应用程序
【发布时间】: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。

【问题讨论】:

    标签: c++ qt multithreading qthread


    【解决方案1】:

    简答:通过调用aThread->start(); 而不是run() 启动您的线程,并确保您线程的run() 方法受到保护(不公开)。

    说明

    Calling start() is the correct way 启动线程,因为它提供优先级调度并在自己的线程上下文中实际执行run() 方法。

    看起来你要在这个线程中加载图像,所以我将在你遇到许多人在使用 QThread 时陷入的陷阱之前提供一些提示

    1. QThread 本身不是线程。它只是一个线程的包装器,这将我们带到..
    2. 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()。
      猜你喜欢
      • 2013-12-03
      • 2012-02-20
      • 1970-01-01
      • 2020-11-26
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多