Is it safe to emit a signal on an object from another thread (if the slot is connected as QueuedConnection
)? I couldn't find a specific piece of documentation that would mention this, the most relevant quote I found is this:
QObject is reentrant. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket and QProcess, are also reentrant, making it possible to use these classes from multiple threads simultaneously. Note that these classes are designed to be created and used from within a single thread; creating an object in one thread and calling its functions from another thread is not guaranteed to work.
This suggest that it might not be OK, does this also apply to signals? There is a QMutexLocker
inside QMetaObject::activate
, so it looks to me that it might be thread safe...?
#include <QCoreApplication>
#include <QTimer>
#include <thread>
#include <iostream>
struct Foo : public QObject
{
Q_OBJECT
public:
Foo(QObject* parent) : QObject(parent) {}
public slots:
void run()
{
connect(this, &Foo::signal, this, [] { std::cout << "activated"; }, Qt::QueuedConnection);
std::thread t([this] { emit signal(); });
if (t.joinable()) t.join();
}
signals:
void signal() const;
};
#include "main.moc"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Foo* b = new Foo(&a);
QTimer::singleShot(0, b, &Foo::run);
return a.exec();
}
Signals2 are thread safe and can be used in multithreaded applications. For example, objects of type boost::signals2::signal and boost::signals2::connection can be accessed from different threads.
The common ways of signalling are through WaitHandle and Monitor , that can coordinate between threads by notifying (signal) them when to go ahead and when to halt. All the EventWaitHandle mentioned below are basically WaitHandle objects that can signal and wait for signals.
The purpose of thread signaling is to enable threads to send signals to each other. Additionally, thread signaling enables threads to wait for signals from other threads. For instance, a thread B might wait for a signal from thread A indicating that data is ready to be processed.
Event loop means that your code is continuously running, think about it as being refreshed every time, so changes will be seen and made continuously based off your cases you have. You can think of it as an event driven program, just continuously waiting for events and will do something.
Qt is based on queues of events. Each Qt thread has its own queue and associated event loop around it. So when you have a situation where 2 different objects are living it 2 different threads and one is connected to another through the signals/slots mechanism (either by Auto or Queued connection) the following happens during the emission: the code inside the signal creates an event and posts it to the queue of the object-receiver. The receiver's event loop is running through the queue, finds the event posted and executes an appropriate slot.
The queue is guaranteed to be thread safe so it is absolutely safe to emit signals across threads. The quote in your questions talks about the situation where you make a direct call on the object living in T1
from T2
.
There is a great article about threads, qobjects, signals, slots and how everything relates to each other: Threads Events QObjects. I recommend to read it if you want to understand it deeper.
Regarding the code in question. You have a queued connection and it means that it doesn't matter if the sender and receiver live in one thread or different ones. It doesn't matter if the sender and receiver are 2 objects or the same. The said routine will be the same. If you created an Auto connection then it would have a Direct call but you didn't. And a relevant quote from the documentation:
On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.
yes it's the prefered way because qt GUI prevents change a thread directly from another thread so you should emit a signal from the thread one and connect it (receive it) in the thread tow and depends on signal type execute some of your thread code if you tried to execute code directly you will get this error
QObject::setParent: Cannot set parent, new parent is in a different thread
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