Does deleteLater() wait for all pending signals to be delivered? - c++

I was thinking about writing this code:
emit finished();
deleteLater();
But it made me wonder if finished() would always be delivered before the object is deleted. I'm pretty certain it will be delivered for Qt::DirectConnection, but I'm not sure about Qt::QueuedConnection, or if the slot is in another thread.

When you emit a signal, it is placed in the event queue of the thread of the receiving object for processing. Calling deleteLater also adds an event to the queue, so they will be performed sequentially if the receiving object and the object being deleted have the same thread affinity, regardless of the thread type.
If the sender and receiver have different thread affinity (running in different threads) then I would expect it is possible for deleteLater to be called before the emit is finished, if the receiver's event loop starts processing before the sender's event loop.
If you want to guarantee that finished is executed first, you can connect the sender and receiver with a blocking connection, which will halt the sender's thread until the message has been delivered.
connect(sender, SIGNAL(finished()), receiver, SLOT(handleFinished(), Qt::BlockingQueuedConnection);
Note that if using Qt::BlockingQueuedConnection and the sender and receiver have the same thread affinity, the application will be dead-locked.

Related

Determinate queued signals

Assume I have a Qt::QueuedConnection connection in which the signal is emitted in a different thread from the one the consumer slot is called. Now I want to close the application and in the handler destructor I would like to check either there are any remaining queued signal-slot calls (I am using this signal slot connection mechanism as a queue). Is it possible?

Is Qt's event loop thread safe or atomic? How is it synchronised when dealing with `QueuedConnection`?

Suppose 2 QThreads are running with following relation:
connect(&Object1OfThread1, &Object1::Signal,
&Object2OfThread2, &Object2::Slot, Qt::QueuedConnection);
So when an object from one thread raises a signal, the other thread's slot is invoked. As discussed in Qt signals (QueuedConnection and DirectConnection), due to Qt::QueuedConnection, the Signal() is posted/appended into the event loop of the Thread2. When it turn comes, the Slot() is invoked.
Question: Is the event loop itself thread-safe?
viz. what if Thread1 and Thread3 both post a signal simultaneously to Thread2's event loop.
The article mentioned in this comment, says that the event queue is protected by a mutex.
How Qt Signals and Slots Work - Part 3 - Queued and Inter Thread Connections
A QueuedConnection will post an event to the event loop to eventually be handled.
When posting an event (in QCoreApplication::postEvent), the event will be pushed in a per-thread queue (QThreadData::postEventList). The event queue is protected by a mutex, so there is no race conditions when threads push events to another thread's event queue.
Once the event has been added to the queue, and if the receiver is living in another thread, we notify the event dispatcher of that thread by calling QAbstractEventDispatcher::wakeUp. This will wake up the dispatcher if it was sleeping while waiting for more events. If the receiver is in the same thread, the event will be processed later, as the event loop iterates.
Qt event loop is thread safe but not atomic.
Thread safety
As long as Object2OfThread2 state is always modified by the thread associated with Thread2, there won't be any race conditions. At most one slot will be executed at any time.
Atomicity
The order of execution of slots is governed by :
usual thread preemption
The order in which the connections were made to this slot.
The other slots connected to the signal.
So I would not advise to assume a specific order of execution for a given slot.
what if Thread1 and Thread3 both post a signal simultaneously to Thread2's event loop
First, it is different signals : two threads cannot emit the same signal of the same object as this object resides in only one QObject
The signal connected first wins, assuming these signals are only connected to Object2OfThread2 even if they are "posted" simultaneously.
If for instance Thread1 signals are connected to other signals\slots, and those connections are made before Object2OfThread2, &Object2::Slot, they will be processed before being posted on Object2OfThread2 event loop. If the signals emitted simultaneously, Thread3 signal will be the first queued, so the first to execute.

Qt: Sending signal to dead/stopped thread

I've come across the problem, that I might be sending signals from one QThread to another, however I have no way of checking if the thread that is implementing the slot is running. How will the framework handle such a situation while using Qt::QueuedConnection ?
...
WorkerImp* pWorker = new WorkerImp();
QThread worker;
pWorker->moveToThread(&worker);
QObject::connect(&worker, QThread::finished, pWorker, &QObject::deleteLater, Qt::QueuedConnection);
bool connected = QObject::connect(this, &SlaveMaster::requireWork, pWorker, &WorkerImp::doWork, Qt::QueuedConnection);
assert(connected);
// at this point we have connected the signal, thread is not starded.
// however the object that we use to connect still exists and will after we exit the thread.
worker.start();
worker.exit();
worker.wait();
// note that when we exit the QThread we do not destroy the object - it can be start over
emit requireWork();
...
The signal is never handled. A queued connection across threads is posted as an event to the thread, handled by its event loop. If the thread is stopped (and thus its event loop), there is no one to pick up the event and deliver it:
From the Qt Docs Signals and Slots Across Threads:
Queued Connection: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
and Per-Thread Event Loop:
[...] If no event loop is running, events won't be delivered to the object.
Note that a blocking queued connection would dead-lock

What is difference between QTimer timeout slot calling a slot through direct connection or queued connection?

I'm asking in a case where there is a lot of qt events queued in event engine. Does QTimer emit timeout() signal through event and will with queuedConnection to a slot create another event?
The slots connected with Qt::DirectConnection will be called immediately when the QTimer::timeout signal is emitted by QTimer. If you use a queued connection, it will schedule an event to call the slot, which will be processed by the event loop. QTimer uses timerEvent to emit the timeout signal.
No it is not queued connection by default unless it is running in a different thread. Therefore it is DirectConnection.
I would say that, in general, if you want to guarantee a sequential order of events you are better of using Qt::QueuedConnection with things like timers even when in the same thread so that the event goes onto the queue and is not just acted upon immidiatley - since this behaviour is some-what more like an "interrupt".
However if you really want the timer timeout() to be acted on immediately then use Qt::DirectConnection - I feel that you need to be more careful with this connection type in general (with things like timers which can trigger in the middle of other normal code).
Edit
By "normal code" I mean...well, see comments below:
When a QTimer times out, every Signal-Slot connection, which joins signal of this QTimer with an slot, fires this slot exactly one time.

QT Is a slot launched in a separate thread

I have done some research on this topic . the thread at SO also caught my interest and I wanted to summarize my understanding and be corrected if I am going wrong on a certain path and also wanted to know how QueuedConnection would work.
Here is my understanding followed by the question.
Signals can be connected manually to slots primarily through two different ways first way is using direct connection and the second way is queued connection. In case of a direct connection if the slot method that is attached to the signal is in the same thread then the slot method is called sequentially (as if it was just another method) however incase the slot is in a different thread from where the signal is launched then QueuedConnection would launch it when it finds it appropriate. (Now In this case I am not sure if it would launch a new thread or how it would proceed on doing that)
Slots don't belong to any particular thread, as they are just plain functions. But objects do. If you connect a signal to a slot by QueuedConnection, the signal emission will create an event and send that into the event queue of the target. Qt will arrange that your slot will be called when internally processing that event.
As for all events, they are processed in the thread of the object's thread affinity. You can change that thread by calling moveToThread on the target object.
In multithread environement when sender and recievr object is in diffrent thread.
Qt::QueuedConnection
What is happening when emiting thread? it simply emits( internally
postevent, to reciever threads message queue) and resume emiter
thread( not blocking).
what is happening on reciever thread, after executing above
statement? The slot is invoked when control returns to the event loop
of the receiver's thread.
Qt::BlockingQueuedConnection
What is happening on emiting thread ? it emits( internally sendEvent,
to reciever message queue) and block emiter thread until receiver
slot returnes.(Blocking).
what happening on receiever thread ? The slot is invoked when control
returns to the event loop of the receiver's thread.
Roughly speaking, for QueuedConnection Qt will make a queue of received signals for the thread the slot belongs to, and will launch them one by one in order they are stored in the queue when the thread becomes available (it finishes whatever it was doing and returns to event loop).
No new thread will be launched - slot belongs to some thread, so execution will be performed in that thread.