I am having difficulty grasping what happens when for eg. two different signals are connected to two different slots and when one slot is not done, the other slots' signal is emitted (for both slots connected to their respective signals in a direct connection) where the application only has "one" thread.
This is from the QT official documentation:
Direct Connection: The slot is invoked immediately, when the signal is emitted. The slot is executed in the emitter's thread, which is not necessarily the receiver's thread.
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.
It says "immediately" for direct connection unlike the queued connection. Does that mean, if the second signal is emitted when the first slot is not done yet, the first slot will be interrupted and it will run concurrently with the second slot even though the application is a single threaded application? If so, why don't I see any warnings that one should use mutexes to lock variables that could be accessed by both slots.
Maybe I am misunderstanding the whole "Direct" and "Queued" connection thing.
I think you are misunderstanding not the queued and direct versions, but the whole signal/slot mechanism as a whole. The signal/slot system is a more elegant solution to the callback problem, when you synchronously or asynchronously need to know when another part of your application (this may be single or multi-threaded) is done doing its work.
Direct / Queued
Let´s get this out of the way before diving into the basics.
Now there is a way to force your code execution to jump into a slot in another thread, that is by invoking a method:
QMetaObject::invokeMethod( pointerToObject*, "functionName", Qt::QueuedConnection);
The Basics
So let´s go over the signal/slot mechanism quickly. There are three actors in the system : signals, slots and connect()
Signals are basically messages that say "Hey! I am finished". Slots are places in your code where post-processing happens, so once the signals are finished you can do something in the slot part of your code.
connect() is the way to organise what happens where and for what reason. The order of execution for signals/slots is the same as your code execution order. First come first serve, since you did mention single-threaded. In a multi-threaded environment that´s different. Honestly the order of execution shouldn´t matter, if you are trying to work with signals/slots and need a guaranteed order of execution you are designing your application wrong. Ideally you use the signal/slot mechanism in the same way that functional programming works, you pass messages along to the next instance to work on the data.
Enough ranting, let´s go down to some practical specifics:
signals:
void a();
void b();
slots:
void sa();
void sb();
Case 1
connect( a -> sa ); // Simplified Notation. Connect signal a to slot sa
connect( b -> sb );
:: emit a(); -> sa is executed
:: emit b(); -> sb is executed
Case 2
connect ( a -> sa );
connect ( a -> sb );
connect ( b -> sb );
:: emit a(); -> sa & sb are executed
:: emit b(); -> sb is executed
I think this should make it clear. If you have anymore questions let me know
Direct connection means that emitting the signal and calling the slot are shortcutted to a simple method call, making the emit
call jump directly into the slot. Queued connection puts the call into a queue, which is handled as soon as the Qt event loop is running again, or you force it by calling QCoreApplication::processEvents()
, in line with all other events that have been queued until then.
In a single threaded application (more exactly: when sender and receiver object live in the same thread), direct connection is the default except you state otherwise when calling QObject::connect()
. This implies that during execution of a slot or other code any emit
in this code calls the connected slot immediately - which can be what you intended, or sometimes not.
You didn't say what, if any, actual problems you have with your signals, but be aware of eternal loops, deadlocks and other locking/mutex issues; mutexes shouldn't be necessary at all in single threaded code. Keep the signal/slot call chains as simple as possible and avoid emit
within slots if ever possible.
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