How does Qt::DirectConnection act when used in multi-threaded environment?

1k views Asked by At

Though Qt::QueuedConnection or Qt::AutoConnection (in certain cases) are preferred in a multithreaded environment, I am asking this question for my understanding purpose.

  1. If signal MySignal() is emitted in thread A & slot MySlot() belongs to object of thread B. Both are connected via Qt::DirectConnection, how does the execution happen? i.e. If thread A sends a signal to thread B, while thread B is executing in middle of some function foo(). Will the slot MySlot() be called just after the foo() finishes or will it be called in parallel to foo()?

  2. Are there any scenario when Qt::DirectConnection is desirable over others in a multithreaded app?

2

There are 2 answers

0
Johannes Schaub - litb On

Are there any scenario when DirectConnection is desirable over others in a multithreaded app?

Yes, if your thread B is only executing in a single function and has no event loop, then DirectConnection is the only choice you have. Using AutoConnection or QueuedConnection will not work because the corresponding slot call event will not be processed in B or anywhere else.

Another reason for DirectConnection might be if your parameters are not serializable/deserializable using the Qt meta object system. If the conditions for Qt::DirectConnection are satisfied (the slot is thread-safe), you can use it instead (be wary about consequences - see following text).

Another thing you have to take into account is signal distribution across multiple slots. If you use DirectConnection and the slot needs to wait on a mutex, other slots that were connected after that said slot will not be activated until the slot has returned. Using QueuedConnection in this case will provide for a non-blocking signal distribution. Then, the thread B will block (in its qt-internal event handler for the slot-call event), instead of thread A in its "emit" statement.

Another thing you have to take into account is slot invocation order. If you issue multiple emit statements one after another, and slots of the same object are called using QueuedConnection, they are called in this order, because what's behind it are ordinary slot-call events. If some of these slots are DirectConnection, then they are called synchronously in the emitting thread, with no order guarantee relative to the other queued slot invocations!

Edit: I think there's also an interesting case with QObject::deleteLater. I recommend connecting to it using Qt::DirectConnection. This function is thread-safe and will send a delete-later event to the object's target thread. What's more, the function also handles the case where the object's thread has no running event loop (in which case the object is deleted when its thread exits). If you were to use Qt::QueuedConnection and there's no event loop in the target thread, you would have created a memory leak.

0
G.M. On

If thread A sends a signal to thread B, while thread B is executing in middle of some function foo(). Will the slot MySlot() be called just after the foo() finishes or will it be called in parallel to foo()?

Unfortunately (and as you suspect) Qt::DirectConnection is precisely that and B::MySlot() will be invoked on thread A concurrently with whatever is already happening on thread B -- foo() in this case. So, without any other form of synchronization the use of Qt::DirectConnection is generally a bad idea when the sender and receiver may be on different threads.

If you really do require the concept of a synchronous cross-thread signal/slot call then you might want to look at Qt::BlockingQueuedConnection