【问题标题】:QThread, threaded, rly?QThread,线程,rly?
【发布时间】:2010-10-12 12:32:42
【问题描述】:

有一段时间,我现在很烦在响应良好的 UI 后面运行大量时间/cputime 消耗操作。不幸的是,我似乎无法让它运行,“我认为”问题是插槽不是在 QThread 工作线程中处理的,而是在 GUI 线程中处理的。 ThreadID 与预期的不同。

我已经读过这个http://doc.trolltech.com/4.6/threads-qobject.html 并使用了 googel 和 SO 搜索,但没有什么真正帮助我。可能是我看不到的顽固。

以下是我的精简代码(注意:在二进制文件所在的文件夹中需要一个名为“dummy1024x1024.png”的 png):

ma​​in.cpp

#include <QtGui>
#include "dummy.h"

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    Dummy d(NULL);
    d.show();
    qDebug() << "App thread " <<  QThread::currentThreadId();
    return app.exec();
}

dummy.h

#ifndef DUMMY_H
#define DUMMY_H

#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>

#include "workerthread.h"

class Dummy : public QWidget
{
Q_OBJECT
public:
    explicit Dummy(QWidget *parent = 0);
    virtual ~Dummy();
private:
    QVBoxLayout* m_layout;
    QPushButton* m_dummy[3];
    QPushButton* m_shootcalc;
    WorkerThread* m_work;
signals:

public slots:

};

#endif // DUMMY_H

dummy.cpp

#include "dummy.h"

Dummy::Dummy(QWidget *parent) :
    QWidget(parent)
{
    m_work = new WorkerThread(this);
    m_work->start();

    m_shootcalc = new QPushButton("Calc!", this);
    connect(m_shootcalc, SIGNAL(clicked()), m_work, SLOT(expensiveCalc()), Qt::QueuedConnection);

    m_dummy[0] = new QPushButton("Dummy [0]", this);
    m_dummy[1] = new QPushButton("Dummy [1]", this);
    m_dummy[2] = new QPushButton("Dummy [2]", this);

    m_layout = new QVBoxLayout(this);
    m_layout->addWidget(m_shootcalc);
    m_layout->addWidget(m_dummy[0]);
    m_layout->addWidget(m_dummy[1]);
    m_layout->addWidget(m_dummy[2]);
    setLayout(m_layout);
}


Dummy::~Dummy()
{
    m_work->quit();
    m_work->wait();
    m_work->deleteLater();
    m_work = NULL;
}

workerthread.h

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H

#include <QThread>
#include <QPixmap>
#include <QDebug>

class WorkerThread : public QThread
{
Q_OBJECT
public:
    explicit WorkerThread(QObject *parent = 0);
protected:
    virtual void run();
signals:

public slots:
    void expensiveCalc();
};

#endif // WORKERTHREAD_H

workerthread.cpp

#include "workerthread.h"

WorkerThread::WorkerThread(QObject *parent) :
    QThread(parent)
{
}


void WorkerThread::run()
{
    qDebug() << "Thread start << " << QThread::currentThreadId();
    exec();
    qDebug() << "Thread stop << " << QThread::currentThreadId();
}

void WorkerThread::expensiveCalc()
{
    qDebug() << "start pixie loading.... " << QThread::currentThreadId();
    QPixmap* pixies[16384];
    for (int i=0; i<16384; ++i)
    {
        pixies[i] = new QPixmap("./dummy1024x1024.png");
        if (i>0)
            delete pixies[i-1];
        msleep(1);
    }
    delete pixies[16384-1];

    qDebug() << "loaded pixies " <<  QThread::currentThreadId();
    qDebug() << "";
    qDebug() << "";
    qDebug() << "";
    qDebug() << "";
}

感谢任何帮助/提示/回复

【问题讨论】:

  • 不久前在德国的“Linux Magazin”中有一篇关于这个问题的文章。并且在 github 上有一些代码可用于工作线程,这些代码可以与信号/插槽一起正常工作。见这里:github.com/picaschaf/Qt-Worker-Thread这可能就是你要找的。​​span>
  • 感谢您提供的信息,我通常阅读 LinuxMagazine,但似乎错过了。我根据 Qt 文档和示例告诉我的内容完成了上述代码。不幸的是,QThread 文档是 Qt 文档中最糟糕的部分之一。

标签: multithreading qt qt4


【解决方案1】:

正确使用QThread 是Qt 用户的常见问题。 Qt Labs 的 blog post 很好地解释了这一点。

简而言之,您应该子类化 QThread 以包含您想在该线程中运行的代码。您应该将代码包装在QObject 子类中,对其进行实例化并使用QObject::moveToThread 将您的对象移动到QThread 上下文中,以便在QThread 的上下文中进行处理。然后,您可以在 QObject 子类中拥有插槽,这些插槽可以安全地连接到另一个线程,但会在您期望的上下文中运行。

有些人可能会争辩说,如果您可以轻松地在 run() 方法中满足您想要做的事情并且不需要太多(或任何)外部交互,那么子类化 QThread 应该没问题,但即使在这种简单的情况下,我也会支持单独的类以更好地封装。

【讨论】:

  • 并描述实际问题:QThread qobject 本身就存在于主线程中,而不是在线程本身中表示(!)。阿诺德描述的分离应该更清楚。
  • 谢谢,是的,QThread 对象“存在”在主线程中,因此向它发出的信号在主事件循环中处理,这就是 OP 所看到的。
  • 不久前在德国的“Linux Magazin”中有一篇关于这个问题的文章。并且在 github 上有一些代码可用于工作线程,这些代码可以与信号/插槽一起正常工作。见这里:github.com/picaschaf/Qt-Worker-Thread这可能就是你要找的。​​span>
  • @ArnoldSpence 我相信你应该继承 QThread,而不是创建单独的 QObject 子类。如果您在派生的 QThread 类的构造函数中调用moveToThread(this),信号和槽将按预期工作(在槽的线程中执行)。这里有更详细的描述:engineer-dan.tumblr.com/post/36274332373/subclassing-qthread
  • @Daniel K. 我知道这种技术。当你这样做时,看起来一切正常,但在某些情况下你将难以摧毁它们。除此之外,这只是一个糟糕的面向对象设计,因为它违反了单一职责原则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多