简体   繁体   中英

Is mutex required in Qt, if different threads are invoking same signal of another different thread?

Let class A is having only one object named as objectA and it's being on a separate thread (say "TCP"):

connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot()));    

Note : I assume that Qt::AutoConnection will take care of whether it's QueuedConnection or DirectConnection . I am OK with any type, which makes it safer.

Now if B (say "Processor") & C (say "Utility") are different threads, which are invoking MySignal() with their own convenience.
In the MySlot() , some data of objectA is getting written.

Question :
Do I need mutex-locking to protect data of A a; ?
OR
The MySignal() will be queued automatically and hence the MySlot() will get sequentially invoked?

Use case : Currently I am having a TCP thread which send/receive data to/from server. At times, 2 threads may send the data at same time. It's likely to run 2 threads in perfect parallel now a days due to multi-processor architecture.

Assume those threads have been created on the main thread and since connect by default uses Qt::AutoConnection and docs say:

(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.

By the time a thread emits a signal, since sender (the code running in QThread::run() ) and receiver (the thread who has created the QThread object itself) are different threads, Qt::QueuedConnection is used. That is:

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.

So all MySlot will be sequentially executed on the main thread.


Update

You've somewhat changed your question! In general, The following connection means: MySignal could be emitted in any threads (ie the thread in which you've called emit MySignal() ), but MySlot is only called in the thread which objectA belongs to (ie thread affinity). If those threads are the same, the slot is executed synchronously.

connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot())); 

If the object the slot is executed on is in a different thread than the object that does the emit , then the call is not sequential. The emit will not block. Thus if you access data that the emitting object might be writing to after the emit , you need to either synchronize that access with a mutex, or use a blocking connection (which means you're forcing sequential execution, meaning emit will block until the slot has returned.)

So, if the emit happens on a different thread, and you want it to block, use a blocking connection. If you don't want the emit to block, use a mutex to protect the data. If the emit happens on the same thread, it's going to be a blocking connection anyway.

However, if the emit happens in several threads, then you always need a mutex.

Do I need mutex-locking to protect data of A a;?

In case you are accessing a 's data outside of the thread in which a 's event loop lives, yes you do need a lock.

There's something suspect in your design.

Normally, signals are protected , and emitted only from code running in that object's thread. A more conventional design would have objects B and C emit their own signals, and you would connect those signals to the slots of objectA .

Whilst what you have might work , it will be hard to reason about, and it's probably a good time to review your design before it becomes too tangled to understand what happens in which thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM