QThread, с резьбой, Rly? - PullRequest
       3

QThread, с резьбой, Rly?

2 голосов
/ 12 октября 2010

В течение некоторого времени я неохотно наблюдаю за массовым сливом времени / процессорного времени, который работает за пользовательским интерфейсом с хорошим откликом.К сожалению, я не могу заставить его работать, и «я думаю», проблема в том, что слот обрабатывается не в рабочем QThread, а в потоке GUI.Тем не менее, идентификаторы ThreadID отличаются, как и ожидалось.

Я уже прочитал это http://doc.trolltech.com/4.6/threads-qobject.html и использовал поиск googel и SO, но ничего, что действительно помогло мне.Вероятно, это что-то упрямое, я просто не вижу.

Ниже приведен мой сокращенный код (Примечание: png с именем "dummy1024x1024.png" требуется в той же папке, что и двоичный файл):

main.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() << "";
}

Спасибо за любую помощь / совет / ответ

1 Ответ

5 голосов
/ 12 октября 2010

Правильное использование QThread является распространенной проблемой среди пользователей Qt. Это сообщение в блоге в Qt Labs хорошо объясняет это.

Короче говоря, вы должны не подкласс QThread, чтобы содержать код, который вы хотите запустить в этом потоке. Вам следует заключить код в подкласс QObject, создать его экземпляр и использовать QObject::moveToThread для перемещения вашего объекта в контекст QThread, чтобы обработка происходила в контексте этого QThread. Затем вы можете иметь слоты в своем подклассе QObject, которые можно безопасно подключать к другому потоку, но они будут работать в ожидаемом контексте.

Некоторые могут возразить, что подкласс QThread должен подойти, если вы можете легко вписать то, что вы хотите делать внутри метода run(), и вам не нужно много (или вообще) внешнего взаимодействия, но даже в этом простом случае я бы выберите отдельный класс для лучшей инкапсуляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...