I would like to confirm what I believe is a straightforward aspect of worker threads in Qt.
Suppose I create a QThread whose purpose is to manage time-consuming work in its corresponding thread. Furthermore, suppose I allow this thread's corresponding event loop to run by calling start()
on the QThread. The work itself is performed by a member function (slot) that is signaled by the QThread's started()
signal.
That is (copying from https://stackoverflow.com/a/11039216/368896):
class Task : public QObject
{
Q_OBJECT
public:
Task();
~Task();
public slots:
void doWork()
{
//very time-consuming code is executed here before the next line is reached...
emit workFinished(); // Calls workFinished() signal (after a long time)
}
signals:
void workFinished();
};
// ... in the main thread:
QThread *thread = new QThread( );
Task *task = new Task();
task->moveToThread(thread);
connect( thread, SIGNAL(started()), task, SLOT(doWork()) );
connect( task, SIGNAL(workFinished()), thread, SLOT(quit()) );
//automatically delete thread and task object when work is done:
connect( thread, SIGNAL(finished()), task, SLOT(deleteLater()) );
connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
thread->start();
My question is the following. I understand that the worker thread's event loop will receive a trigger from the finished()
signal in order to call the deleteLater()
slot on the task
instance. Also, this event loop will be running quite shortly after the doWork()
function returns, and therefore it will be ready and available to process the trigger from the finished()
signal that was just added to the worker thread's event queue by the call to finished()
at the end of the doWork()
function.
I would like to confirm that during the entire course of the time-consuming operation being executed inside doWork()
(before finished()
is emitted and before the doWork()
function exits), that the event loop inside the worker thread is blocked on the slot function doWork()
and therefore the worker thread will NOT be responsive to any slots triggered on any objects owned by the event loop's thread during the entire course of execution of the time-consuming doWork()
function. (And that therefore, any such slots will only be executed after doWork()
exits, once the worker thread's event loop is active again, and before the trigger from the finished()
signal is handled.)
I suspect that this is the case, but I want to confirm.
Thanks!
Qt's event loop starts the moment the underlying application's exec() function gets called. Once started, the loop repeatedly checks for something to happen in the system, such as user-input through keyboard/mouse.
QThread is the thread "controller". Its event loop doesn't block just because your QObject executes an infinite loop.
QObject and all of its subclasses are not thread-safe. This includes the entire event delivery system. It is important to keep in mind that the event loop may be delivering events to your QObject subclass while you are accessing the object from another thread.
In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.
The event loop of the worker thread will be blocked, i.e. you won't be able to process any events (including those which are used for 'queued' connections between signals and slots, which is what you get when doing signal-slot connections across threads) unless you explicitely trigger a call to the event loop object yourself.
You can however still have slots executed in your worker thread triggered by signals which are emitted from the worker thread, because those are plain function calls and don't need a running event loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With