Return to site

Qthread Slot Connection

broken image


Q) What is the entry point for qthread?

QtConcurrentprovides an easy interface for distributing work to all of the processor's cores. The threading code is completely hidden in the QtConcurrentframework, so you don't have to take care of the details. Its important to use a direct connection here // because moveToThread must be called in the GraphicsThread (finished is emitted in the GraphicsThread context) connect ( qThread, SIGNAL ( finished ( ) ), this, SLOT ( moveBack ( ) ), Qt:: DirectConnection ). An event posted using a QueuedConnection is a QMetaCallEvent. When processed, that event will call the slot the same way we call them for direct connections. All the information (slot to call, parameter values.) are stored inside the event. PyQt5 - Tutorial 009. Using QThread with MoveToThread. Based on one of the questions on the forum, I wrote an example on using QThread in PyQt5, as well as using the moveToThread method to move the class object of the inherited QObject to another thr.


The run() implementation is for a thread what the main() entry point is for the application.
Q) Different types of thread?
http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
http://ynonperek.com/course/qt/threads.html
First:
QThread MyThread;
this->moveToThread(&MyThread);
//'this' makes object of current class to run in thread
MyThread.start();
Second:
Subclass Qthread and override run()
Third:
QtConcurrent::run(this, &Camera::firstStartThreadProc);
OR
QFuture f1 = QtConcurrent::run(this, &CanDTC::readThreadProc);
USAGE-01
#include
class Thread : public QThread
{
private:
void run()
{
qDebug()<<'From worker thread: '< }
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug()<<'From main thread: '< Thread t;
QObject::connect(&t, SIGNAL(finished()), &a, SLOT(quit()));
t.start();
return a.exec();
Qthread Slot Connection

}
Q) What happens if Qthread subclas declartion is in cpp and anot in header file?
You need to have a line at the bottom of your source file: #include 'main.moc'
That's because the declaration of class Thread isn't in a header - it's in a .cpp file. So by default moc won't run on it. Adding the line does two things:
it signals to qmake and moc that moc has to process the .cpp file
it causes the stuff that moc generates to be pulled in by the compile step
So after adding that line you'll need to rerun qmake so it can update the makefiles to cause main.moc to be generated.
Q) What is the difference between QueuedConnection and normal connection in connect Qt?
// connect signal-slots for decoupling
QObject::connect (this, SIGNAL(setCurrentTaskSignal(int)), this,
SLOT(SetCurrentTaskSlot(int)), Qt::QueuedConnection);
Note that QueuedConnection doesn't mean that something is in different thread. QueuedConnection means only that when signal is emitted, corresponding slot won't be called directly. It will be queued on event loop, and will be processed when control will be given back to event loop
One uses a queued connection to ensure that the signal will be delivered from within the event loop, and not immediately from the emit site as happens with direct connection. Direct connection is conceptually a set of calls to function pointers on a list. Queued connection is conceptually an event sent to a clever receiver who can execute a function call based on the contents of the event.
Qt.QueuedConnection -> When emitted, the signal is queued until the event loop is able to deliver it to the slot.
Qt.BlockingQueuedConnection -> Same as QueuedConnection, except that the current thread blocks until the slot has been delivered. This connection type should only be used for receivers in a different thread. Note that misuse of this type can lead to dead locks in your application.
Direct signal-slot connection is nothing else but a chain of synchronous or direct C++ function calls.
A queued signal-slot connection is nothing else but an asynchronous function call
Q) When is Qthread begin executing?

Qthread Slot Connections

QThreads begin executing in run().
By default, run() starts the event loop by calling exec()..'.
Q) By whom and when is run() method called in Qthread?
The run() method is called automagically by Qt when the caller calls start() on your thread
Q) How qthread can be used?
To be able to use one of the QThreadPool threads, we have to subclass QRunnable and implement the run() method. After that, we have to create an instance of the QRunnable subclass and pass it to QThreadPool::start().
Qthread Slot Connection
//start->run->qthread.
Q)Wtat is the main difference between a process and a thread?
The main difference between a process and a thread is that each process is executed in a separate address space, whereas each thread uses the same address space of a process.
A process can have multiple threads.
Threads share the heap, but each thread of execution has its own call stack.
Q) Difference between QThread runnable and QtConcurrent?
QThread provides a low-level class that can be used for explicit creation of long-running threads.
Using QtConcurrent's functional map/filter/reduce algorithms, which apply functions in parallel to each item in a container, you can write a program that automatically takes advantage of the system's multiple cores by distributing the processing across the threads managed by the thread pool. Alternatively, you can use QRunnable as a base class for the Command pattern and schedule work with QtConcurrent::run(). In these cases, you do not need to create threads explicitly or manage them directly – you can simply describe the pieces of work as objects with the right interface.
QtConcurrent runs a pool of threads and it is a higher level API not well-suited to run a large number of blocking operations:
If you have CPU-bound work to do and want to distribute it across multiple cores, you can break up your work into QRunnables and make those thread-safe by following these recomendations.

Qthread Lock


Distribute the CPU-heavy calculations across multiple threads using QtConcurrent algorithms whenever possible, instead of writing your own QThread code.
Do not access the GUI (this includes any QWidget-derived class, QPixmap, and other graphics-card specific classes) from any thread other than the main thread. This includes read access like querying the text entered into a QlineEdit.
Q) Suppose your application needs to run a function in multiple threads the number of which is more than the number of CPU cores/threads.
One way is to use QtConcurrent and setting the maximum thread count :
MyClass *obj = new MyClass;
QThreadPool::globalInstance()->setMaxThreadCount(30);
for(int i=0;i<30;i++)
QtConcurrent::run(obj, &MyClass::someFunction);
Another way is to have multiple objects and move them to different threads using moveToThread :
for(int i=0;i<30;i++)
{
MyClass *obj = new MyClass;
QThread *th = new QThread();
obj->moveToThread(th);
connect(th, SIGNAL(started()), obj, SLOT(someFunction()) );
connect(obj, SIGNAL(workFinished()), th, SLOT(quit()) );
connect(th, SIGNAL(finished()), obj, SLOT(deleteLater()) );
connect(th, SIGNAL(finished()), th, SLOT(deleteLater()) );
th->start();
Slot
}

A short history

Slot

}
Q) What happens if Qthread subclas declartion is in cpp and anot in header file?
You need to have a line at the bottom of your source file: #include 'main.moc'
That's because the declaration of class Thread isn't in a header - it's in a .cpp file. So by default moc won't run on it. Adding the line does two things:
it signals to qmake and moc that moc has to process the .cpp file
it causes the stuff that moc generates to be pulled in by the compile step
So after adding that line you'll need to rerun qmake so it can update the makefiles to cause main.moc to be generated.
Q) What is the difference between QueuedConnection and normal connection in connect Qt?
// connect signal-slots for decoupling
QObject::connect (this, SIGNAL(setCurrentTaskSignal(int)), this,
SLOT(SetCurrentTaskSlot(int)), Qt::QueuedConnection);
Note that QueuedConnection doesn't mean that something is in different thread. QueuedConnection means only that when signal is emitted, corresponding slot won't be called directly. It will be queued on event loop, and will be processed when control will be given back to event loop
One uses a queued connection to ensure that the signal will be delivered from within the event loop, and not immediately from the emit site as happens with direct connection. Direct connection is conceptually a set of calls to function pointers on a list. Queued connection is conceptually an event sent to a clever receiver who can execute a function call based on the contents of the event.
Qt.QueuedConnection -> When emitted, the signal is queued until the event loop is able to deliver it to the slot.
Qt.BlockingQueuedConnection -> Same as QueuedConnection, except that the current thread blocks until the slot has been delivered. This connection type should only be used for receivers in a different thread. Note that misuse of this type can lead to dead locks in your application.
Direct signal-slot connection is nothing else but a chain of synchronous or direct C++ function calls.
A queued signal-slot connection is nothing else but an asynchronous function call
Q) When is Qthread begin executing?

Qthread Slot Connections

QThreads begin executing in run().
By default, run() starts the event loop by calling exec()..'.
Q) By whom and when is run() method called in Qthread?
The run() method is called automagically by Qt when the caller calls start() on your thread
Q) How qthread can be used?
To be able to use one of the QThreadPool threads, we have to subclass QRunnable and implement the run() method. After that, we have to create an instance of the QRunnable subclass and pass it to QThreadPool::start().
//start->run->qthread.
Q)Wtat is the main difference between a process and a thread?
The main difference between a process and a thread is that each process is executed in a separate address space, whereas each thread uses the same address space of a process.
A process can have multiple threads.
Threads share the heap, but each thread of execution has its own call stack.
Q) Difference between QThread runnable and QtConcurrent?
QThread provides a low-level class that can be used for explicit creation of long-running threads.
Using QtConcurrent's functional map/filter/reduce algorithms, which apply functions in parallel to each item in a container, you can write a program that automatically takes advantage of the system's multiple cores by distributing the processing across the threads managed by the thread pool. Alternatively, you can use QRunnable as a base class for the Command pattern and schedule work with QtConcurrent::run(). In these cases, you do not need to create threads explicitly or manage them directly – you can simply describe the pieces of work as objects with the right interface.
QtConcurrent runs a pool of threads and it is a higher level API not well-suited to run a large number of blocking operations:
If you have CPU-bound work to do and want to distribute it across multiple cores, you can break up your work into QRunnables and make those thread-safe by following these recomendations.

Qthread Lock


Distribute the CPU-heavy calculations across multiple threads using QtConcurrent algorithms whenever possible, instead of writing your own QThread code.
Do not access the GUI (this includes any QWidget-derived class, QPixmap, and other graphics-card specific classes) from any thread other than the main thread. This includes read access like querying the text entered into a QlineEdit.
Q) Suppose your application needs to run a function in multiple threads the number of which is more than the number of CPU cores/threads.
One way is to use QtConcurrent and setting the maximum thread count :
MyClass *obj = new MyClass;
QThreadPool::globalInstance()->setMaxThreadCount(30);
for(int i=0;i<30;i++)
QtConcurrent::run(obj, &MyClass::someFunction);
Another way is to have multiple objects and move them to different threads using moveToThread :
for(int i=0;i<30;i++)
{
MyClass *obj = new MyClass;
QThread *th = new QThread();
obj->moveToThread(th);
connect(th, SIGNAL(started()), obj, SLOT(someFunction()) );
connect(obj, SIGNAL(workFinished()), th, SLOT(quit()) );
connect(th, SIGNAL(finished()), obj, SLOT(deleteLater()) );
connect(th, SIGNAL(finished()), th, SLOT(deleteLater()) );
th->start();
}

A short history

Long long ago, subclass QThread and reimplement its run() function is the only recommended way of using QThread. This is rather intuitive and easy to used. But when SLOTS and Qt event loop are used in the worker thread, some users do it wrong. So Bradley T. Hughes, one of the Qt core developers, recommend that use worker objects by moving them to the thread using QObject::moveToThread . Unfortunately, some users went on a crusade against the former usage. So Olivier Goffart, one of the former Qt core developers, tell the subclass users: You were not doing so wrong. Finally, we can find both usages in the documentation of QThread.

QThread::run() is the thread entry point

From the Qt Documentation, we can see that

A QThread instance represents a thread and provides the means to start() a thread, which will then execute the reimplementation of QThread::run(). The run() implementation is for a thread what the main() entry point is for the application.

As QThread::run() is the thread entry point, it is rather intuitive to use the Usage 1.

Usage 1-0

To run some code in a new thread, subclass QThread and reimplement its run() function.

Qthread Slot

For example

The output more or less look like:

Usage 1-1

As QThread::run() is the thread entry point, so it easy to undersand that, all the codes that are not get called in the run() function directly won't be executed in the worker thread.

In the following example, the member variable m_stop will be accessed by both stop() and run(). Consider that the former will be executed in main thread while the latter is executed in worker thread, mutex or other facility is needed.

The output is more or less like

You can see that the Thread::stop() is executed in the main thread.

Usage 1-2 (Wrong Usage)

Though above examples are easy to understand, but it's not so intuitive when event system(or queued-connection) is introduced in worker thread.

For example, what should we do if we want to do something periodly in the worker thread?

  • Create a QTimer in the Thread::run()
  • Connect the timeout signal to the slot of Thread

At first glance, the code seems fine. When the thread starts executing, we setup a QTimer thats going to run in the current thread's event queue. We connect the onTimeout() to the timeout signal. Then we except it works in the worker thread?

But, the result of the example is

Oh, No!!! They get called in the main thread instead of the work thread.

Very interesting, isn't it? (We will discuss what happened behined this in next blog)

How to solve this problem

In order to make the this SLOT works in the worker thread, some one pass the Qt::DirectConnection to the connect() function,

and some other add following line to the thread constructor.

Both of them work as expected. But ..

The second usage is wrong,

Even though this seems to work, it's confusing, and not how QThread was designed to be used(all of the functions in QThread were written and intended to be called from the creating thread, not the thread that QThread starts)

In fact, according to above statements, the first workaround is wrong too. As onTimeout() which is a member of our Thread object, get called from the creating thread too.

Both of them are bad uasge?! what should we do?

Usage 1-3

As none of the member of QThread object are designed to be called from the worker thread. So we must create an independent worker object if we want to use SLOTS. Casino rama restaurants orillia.

Qthread Slots

The result of the application is

Problem solved now!

Though this works perfect, but you may have notice that, when event loop QThread::exec() is used in the worker thread, the code in the QThread::run() seems has nothing to do with QThread itself.

So can we move the object creation out of the QThread::run(), and at the same time, the slots of they will still be called by the QThread::run()?

Usage 2-0

If we only want to make use of QThread::exec(), which has been called by QThread::run() by default, there will be no need to subclass the QThread any more.

  • Create a Worker object
  • Do signal and slot connections
  • Move the Worker object to a sub-thread
  • Start thread

The result is:

As expected, the slot doesn't run in the main thread.

In this example, both of the QTimer and Worker are moved to the sub-thread. In fact, moving QTimer to sub-thread is not required.

Simply remove the line timer.moveToThread(&t); from above example will work as expected too.

The difference is that:

In last example,

  • The signal timeout() is emitted from sub-thread
  • As timer and worker live in the same thread, their connection type is direct connection.
  • The slot get called in the same thead in which signal get emitted.

While in this example,

  • The signal timeout() emitted from main thread,
  • As timer and worker live in different threads, their connection type is queued connection.
  • The slot get called in its living thread, which is the sub-thread.

Thanks to a mechanism called queued connections, it is safe to connect signals and slots across different threads. If all the across threads communication are done though queued connections, the usual multithreading precautions such as QMutex will no longer need to be taken.

In short

  • Subclass QThread and reimplement its run() function is intuitive and there are still many perfectly valid reasons to subclass QThread, but when event loop is used in worker thread, it's not easy to do it in the right way.
  • Use worker objects by moving them to the thread is easy to use when event loop exists, as it has hidden the details of event loop and queued connection.

Reference

  • http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
  • http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html
  • http://ilearnstuff.blogspot.com/2012/08/when-qthread-isnt-thread.html




broken image