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
Related
I have two functions which has to be executed after specific interval of time. So I create two threads and each function is executed in separate threads. One of the function "checkForEvent()" has a Event which is waiting for an event to happen.
When the "checkForEvent()" function is waiting for an event the other function "checkServer()" is not being executed even though it is run in a separate thread.
dongleThread = new QThread(this);
checkDongle = new QTimer();
checkDongle->setInterval(DONGLE_CHECK_TIMER);
checkDongle->moveToThread(dongleThread);
connect(checkDongle, SIGNAL(timeout()), this, SLOT(checkForEvent()));
connect(dongleThread, SIGNAL(started()), checkDongle, SLOT(start()));
dongleThread->start();
serverThread = new QThread(this);
checkServer = new QTimer();
checkServer->setInterval(SERVER_CHECK_TIMER);
checkServer->moveToThread(serverThread);
connect(checkServer, SIGNAL(timeout()), this, SLOT(checkServer()));
connect(serverThread, SIGNAL(started()), checkServer, SLOT(start()));
serverThread->start();
checkForEvent() //This function is waiting for an Event
checkServer()
How can I execute both the functions in separate threads ?
Thank you!!
Your connect call uses the default connection type: Qt::AutoConnection. Here is what this means:
Qt::AutoConnection: 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.
Here your QTimer and this are in a different thread. It means Qt::QueuedConnection will be used.
Qt::QueuedConnection: 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 your two slots are called in the thread of this. If one is blocking, the other one will never run.
One way of fixing the problem is having a worker object moved to its own thread. The worker object would call checkForEvent and emit a signal after the wait is over. This signal can be connected to checkServer in this. With this, you need only one thread. You can look at the documentation of QThread for more information about worker objects.
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.
I have applications with 2 threads. In first (main) thread I want to generate some message and send it to second thread. Is there method to blocked thread for wait incoming message (like a queue in embended OS(FreeRTOS, TNKernel etc))?
while (true) {
waitQueue(TIMEOUT_INFINITY);
}
in waitQueue(TIMEOUT_INFINITY); current thread becomes blocked, when in main thread generates some message waitQueue releases thread.
The natural way for doing this in Qt is calling QThread::exec() in the thread (which is what the default implementation for QThread::run() do).
after that to execute a QObject instance (worker object)'s slots in that thread, you can set the instance's affinity to the new thread using QObject::moveToThread(), then when a signal connected to some slot in that instance is emitted, the slot will be invoked in the new thread.
Instantiating a QThread provides a parallel event loop, allowing QObject slots to be invoked in a secondary thread. Subclassing a QThread allows the application to initialize the new thread before starting its event loop, or to run parallel code without an event loop.
see QThread class, QObject class, Threads and QObject, along with Qt event loops.
Hope this helps. . .
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.
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.