[Qt-interest] Example of "moveToThread (this)" idiom -- legal?
K. Frank
kfrank29.c at gmail.com
Sun Jan 2 03:38:45 CET 2011
Hello List!
According to my understanding of the Qt threading model,
I believe that our so-called "moveToThread (this)" idiom is
technically legal. I'd like to get some feedback on whether
this is correct.
This is a follow-up to a number of questions about threading
that come up from time to time, most recently this:
http://lists.qt.nokia.com/pipermail/qt-interest/2010-December/030053.html
To help make things concrete, I''ve put together a minimal
example (see below).
The basic question is whether it is legal to derive a worker
class from QThread, and include the business logic and any
necessary signals and slots in the QThread-derived class
(I want to set aside the separate question of whether such an
approach is good design,and focus on whether it is technically
correct.)
In the following example, I derive a worker-thread class from
QThread, and include in it signals and slots, and (trivial)
business logic. I use a call to QThread::sleep() to emulate
an expensive computation or blocking call.
The basic point is that in order for the worker thread's slots
to be actually executed by the worker thread's thread of
execution (rather than by the main gui thread), the worker
thread must be "moved" to itself. In the example, this is
done in the worker thread's constructor:
class SquareThread : public QThread {
Q_OBJECT
public:
SquareThread() { moveToThread (this); }
// ...
};
This is what I've called the "moveToThread (this)" idiom.
As far as I can tell the example works just fine, the "work"
gets handed off to the worker thread for execution, and the
gui remains responsive while the worker thread is busy.
Any thought or insight would be greatly appreciated.
(I do agree that there are some design trade-offs using this
approach, primarily the loss of the "separation of concerns"
that is one of the goals of object-oriented design.
If you look at Hughes's "You’re doing it wrong…" article,
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
I believe that this design issue underlies Hughes's main
complaint, although he doesn't say so in so many words.
Hughes also does not state outright that there is anything
technically wrong with the "moveToThread (this)" approach.
My question is not whether this idiom is object-orientedly
impure, but rather whether it is technically correct and works
as desired and expected. For me it seems to.)
The example consists of two files: thread_example.h and
thread_example.cpp.
I build it by placing the two files in a clean directory, and
running:
qmake -project
qmake
mingw32-make
(I am using 32-bit mingw g++ 4.4.1 and Qt 4.6 on 64-bit windows 7.)
// thread_example.h
// illustrate "moveToThread (this)" idiom
#include <QtGui>
class SquareThread : public QThread {
Q_OBJECT
public:
SquareThread() { moveToThread (this); }
signals:
void send_result (int result);
public slots:
void receive_value (int value) {
sleep (3);
emit send_result (value * value);
}
};
class SquareDialog : public QDialog {
Q_OBJECT
public:
SquareDialog (QWidget *parent = 0) : QDialog (parent) {
value_box = new QSpinBox (this);
value_box->move (40, 20);
calc_button = new QPushButton ("calculate square", this);
calc_button->setGeometry (110, 20, 90, 20);
QLabel *value_label = new QLabel ("value:", this);
value_label->move (40, 50);
QLabel *result_label = new QLabel ("result:", this);
result_label->move (110, 50);
value_edit = new QLineEdit (this);
value_edit->setGeometry (40, 70, 40, 20);
value_edit->setReadOnly (true);
result_edit = new QLineEdit (this);
result_edit->setGeometry (110, 70, 40, 20);
result_edit->setReadOnly (true);
resize(240, 110);
SquareThread *square_thread = new SquareThread;
connect (calc_button, SIGNAL(clicked()), this, SLOT(calc_square()));
connect (this, SIGNAL(send_value (int)), square_thread,
SLOT(receive_value (int)));
connect (square_thread, SIGNAL(send_result (int)), this,
SLOT(receive_result (int)));
square_thread->start();
}
signals:
void send_value (int value);
public slots:
void calc_square() {
int v = value_box->value();
value_edit->setText (QString::number (v));
calc_button->setEnabled (false);
calc_button->setText ("thinking...");
result_edit->setText ("- ??? -");
emit send_value (v);
}
void receive_result (int result) {
result_edit->setText (QString::number (result));;
calc_button->setText ("calculate square");
calc_button->setEnabled (true);
}
private:
QSpinBox *value_box;
QPushButton *calc_button;
QLineEdit *value_edit;
QLineEdit *result_edit;
};
// thread_example.cpp
// illustrate "moveToThread (this)" idiom
#include <QtGui>
#include "thread_example.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
SquareDialog main_window;
main_window.show();
return a.exec();
}
Thanks for your thoughts, and Happy Hacking!
K. Frank
More information about the Qt-interest-old
mailing list