[Qt-interest] Example of "moveToThread (this)" idiom -- legal?
Mihail Naydenov
mlists at ymail.com
Sun Jan 2 12:01:54 CET 2011
Without going through the example, I just wanted to remind you
Qt itself uses moveToThred(this)
(see QFilesystemWatcher implementation)
So, I am sure by definition moveToThred(this) is not illegal.
If there are any dangers or gotchas they must be documented and
let the users decide what design approach is best suited for their needs.
thanks
MihailNaydenov
----- Original Message ----
> From: K. Frank <kfrank29.c at gmail.com>
> To: Qt-interest <qt-interest at qt.nokia.com>
> Sent: Sun, January 2, 2011 4:38:45 AM
> Subject: [Qt-interest] Example of "moveToThread (this)" idiom -- legal?
>
> 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