[Qt-interest] Example of "moveToThread (this)" idiom -- legal?
Clinton Stimpson
clinton at elemtech.com
Sun Jan 2 04:40:39 CET 2011
For me, it is simply that QThread isn't documented as thread-safe or
reentrant. So, if a QThread moves itself off the original parent
thread, I don't see how the original parent thread can call
QThread::wait(), QThread::isFinished(), etc... without calling functions
that aren't thread-safe.
Clint
On 01/01/2011 07:38 PM, K. Frank wrote:
> 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
> _______________________________________________
> Qt-interest mailing list
> Qt-interest at qt.nokia.com
> http://lists.qt.nokia.com/mailman/listinfo/qt-interest
More information about the Qt-interest-old
mailing list