Qt Thread

Some concepts of Qt Thread are subtle enough to confuse most newbies. You may have read articles about “the right way” and “the wrong way” to use Qt thread, and you may have known the programming pattern to use Qt thread. But if you do not understand the concepts thoroughly, you will definitely make your program crash and do not know where the bug is, sooner or later.

We begins with the QThread first. To execute a piece of code in a new thread, you should put the code in the re-implemented run() of QTread as follows:

class Thread:public QThread
{
  void run()
  {
    qDebug()<<"http://myprogrammingnotes.com";
  }
};

Thread t;

But do not call run() directly, as that will execute the code in the calling thread. You should call t.start(). Then run() will be automatically called, this time, in the new thread! And when the new thread starts, it will emit the start signal(in the new thread too), although I do not know the exact position the signal is emitted(we say a signal is emitted which means calling “emit somesignal()” somewhere). When run() returns, the new thread is finished, t.isFinished() will return true, and “finished” signal is emitted from the new thread although I still do not know the exact position the signal is emitted.

Now we take a further look into the “correct way” to use Qt thread.

class Worker:public QObject
{
  Q_OBJECT
  public slots:
  void dosomething()
  {
    qDebug()<<"http://myprogrammingnotes.com";
  }
};

QThread t;
Worker w;
w.moveToThread(&t);
connect(&t,SIGNAL(start()),&w,SLOT(dosomething()));
t.start();

We’ve known that when a thread starts, it will emit the “start” signal from that thread, and this time, a slot is w.dosomething() is connected to the signal. Because w has been moved to the thread t, “emit start()” will call w.dosomething() directly as the signal emitting thread is the same as the thread the object having that slot is living in. If w had not been moved to t, w would be living in the main thread which is different than the thread emitting the “start” signal, then  “emit start()” would queue the signal in the message queue of the main thread and w.dosomething() would be called(dispatched) sometime later from the main thread.

But what happens when dosomething() returns? Is the new thread finished? The answer is No. The “start” signal is emitted before run() and when dosomething() returns, run() begins which enters an event loop(this is the default implementation of QThread::run()). The new thread is still in the running state. You can call t.isRunning() to check the thread state. So how to make the new thread finished? You can emit a signal at the end of dosomething() and connect it to the thread’s quit() slot, i.e.,

class Worker:public QObject
{
  Q_OBJECT
public slots:
  void dosomething()
  {
    qDebug()<<"http://myprogrammingnotes.com";
    emit finished();
  }

signals:
  void finished();

};

QThread t;
Worker w;
w.moveToThread(&t);
connect(&t,SIGNAL(start()),&w,SLOT(dosomething()));
connect(&w,SIGNAL(finished()),&t,SLOT(quit()));
t.start();

Note that the “finished” signal is emitted from the new thread and t belongs to(or, is living in) the main thread(as it is created in the main thread.), so “emit finished();” and t.quit() are executed asynchronously, which means when dosomething returns, t.quit() may not be called yet. But very soon, t.quit() is called from the main thread while the new thread is now in the event loop. After t.quit() is called, the new thread exits from the event loop and finishes.

Posted in

Comments are closed, but trackbacks and pingbacks are open.