PDA

View Full Version : Trying to resolve sub-classing QThread - or not



astodolski
5th December 2012, 14:24
I have done a search regarding the issue of sub-classing QThread or not. There are what looks almost like a theological debate as to the merits of one versus the other. What I am not being able to find is what are the pitfalls of using an object as a sub-class of QThread. I see benefits of sub-classing such as the availability of isRunning, isFinished, sleep, msleep etc. Without using a subclass, those functions are not available. So other than the statement that it essentially is "no longer necessary", is there a more functional reason?

amleto
5th December 2012, 14:55
Don't know why you think a benefit of subclassing is 'isRunning, isFinished, sleep, msleep are still available'. They are of course still available on the associated QThread!

The benefit of not sub-classing is that people dont get confused about what threads the signals/slots are (executed) in.

Kwakkie
5th December 2012, 14:57
Do you need those functions in your subclass? The isRunning and isFinished functions are more for the object controlling the thread, not for the thread itself. I haven't encountered a reason to subclass from QThread honestly. As I see it:

Subclass QThread if you want different thread functionality
Do not subclass QThread to create a thread

So subclass to "expand" the thread control, not to create a thread!

astodolski
6th December 2012, 15:21
Do you need those functions in your subclass? The isRunning and isFinished functions are more for the object controlling the thread, not for the thread itself.

I need to determine from a main thread in the UI that a worker thread has completed

wysota
6th December 2012, 15:52
I need to determine from a main thread in the UI that a worker thread has completed

Connect to the QThread::finished() signal.

tuli
7th December 2012, 23:07
this has been bugging me for some time, too.
How would i create a thread without sub-classing, reimplementing run() and calling it to start the thread?

amleto
7th December 2012, 23:39
How? Like this.


QThread* thread = new QThread;
thread->start();

colour me confused.

wysota
8th December 2012, 00:12
Create an instance of QThread, create an instance of QObject subclass that does something practical, start the thread, move the object to the thread using QObject::moveToThread() and start the practical functionality of the object by posting an event to it or calling its slot (via a signal or QMetaObject::invokeMethod()).

Kwakkie
10th December 2012, 10:19
Check the updated documentation: http://qt-project.org/doc/qt-4.8/QThread.html . Basically:


class Worker : public QObject
{
Q_OBJECT

public slots:
void doWork() {
...
}
};

void MyObject::putWorkerInAThread()
{
Worker *worker = new Worker;
QThread *workerThread = new QThread(this);

connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
worker->moveToThread(workerThread);

// Starts an event loop, and emits workerThread->started()
workerThread->start();
}

You can also connect the thread finished() signal to its own deleteLater slot.


I need to determine from a main thread in the UI that a worker thread has completed

You don't need to subclass for that. Either use the signal or check the isRunning from the main thread.

astodolski
11th December 2012, 01:27
How? Like this.


QThread* thread = new QThread;
thread->start();

colour me confused.

I am just trying to seek consensus of what is one way of using QThread as a sub-class or the other more preferred method.

wysota
11th December 2012, 09:59
There is no need to subclass QThread unless you really want to reimplement run().

astodolski
13th December 2012, 19:25
You don't need to subclass for that. Either use the signal or check the isRunning from the main thread.

Which signal?

If checking isRunning, then it will always return true if calling from the man thread. I need to check the status of the worker object moved to the other thread.

My code's constuctor in FlashWizard.cpp:



FlashWizard::FlashWizard(QWidget *parent) : QWizard(parent), ui(new Ui::FlashWizard)
{
ui->setupUi(this);

ui->pbReading->reset();
ui->pbWriting->reset();

ui->lblReadingStatus->setText("");
ui->lblReadingStatus->setText("");
ui->lblProgStatus->setText("");

connect(ui->introPage, SIGNAL(p1_updateLabelOne(const QString&)), this, SLOT(updateLabel(const QString&)));
connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(pageCleanUp(int)));

worker = new Worker;
workerThread = new QThread;

worker->moveToThread(workerThread);

connect(workerThread, SIGNAL(started()), worker, SLOT(start()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), ui->programPage, SLOT(setDone()));
connect(worker, SIGNAL(updateProgress(int)), this, SLOT(updateWritingProgressBar(int)));
connect(worker, SIGNAL(finished()), ui->programPage, SLOT(setDone()));
connect(workerThread, SIGNAL(finished()), worker, SLOT(stop()), Qt::QueuedConnection);
}


..and the worker.h



#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QTimer>
#include <QThread>

class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);

signals:
void finished();
void updateProgress(int);

public slots:
void start();
void stop();
void doWork();

private:
QTimer* m_workerTimer;
};

class MThread : public QThread
{
Q_OBJECT
public:
MThread(QObject *parent) : QThread(parent) {}

static void sleep(unsigned long secs)
{
QThread::sleep(secs);
}

static void msleep(unsigned long msecs)
{
QThread::msleep(msecs);
}
};

#endif // WORKER_H



Code



#include "worker.h"
#include <QThread>
#include <QDebug>

Worker::Worker(QObject *parent) : QObject(parent)
{
m_workerTimer = new QTimer(this);
}

void Worker::start()
{
connect(m_workerTimer, SIGNAL(timeout()), this, SLOT(doWork()));
qDebug() << "Object constructor: " << thread();
m_workerTimer->start(100);
}

void Worker::stop()
{
m_workerTimer->stop();
emit finished();
}

void Worker::doWork()
{
for (int i = 0; i < 1000000; i++)
{
if (i % 10000 == 0)
{
emit updateProgress(i / 10000);
qDebug() << (i / 10000);
static_cast<MThread*>(QThread::currentThread())->msleep(10);
}
}

emit updateProgress(100);
emit finished();
}

amleto
13th December 2012, 19:35
Look, if you want to check workerThread->isFinished, then it isn't very clever to be deleting the workerThread when it is finished, is it?

If you remove this


connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));

Then you can query workerThread->isFinished at any time you like.