Direct connection and event loop [duplicate] - qt

This question already has answers here:
Qt signals (QueuedConnection and DirectConnection)
(3 answers)
Closed 8 years ago.
I have read the doc of Qt and have the following question:
if I have:
class_A::on_button_click(){
...do some things...//no signal emit this part
emit signal_A();
}
class_B::on_signal_received(){
...do some things...//no signal emit this part
}
...
connect(class_A_object,SIGNAL(signal_A()),class_B_object,on_signal_received);
All the things here are in the main thread,
now when I click the button and trigger the first function,
the program will be executed from the first line of
class_A::on_button_click()
until the last line of
class_B::on_signal_received()
and during the process nothing else in the main thread will get the chance to be executed, is this correct?( "...do some things..." part don't emit any signals)
In other words, when is the moment that the control return to the event loop?
After finishing
class_A::on_button_click()
or
class_B::on_signal_received()
?

When your signal and slot are in the same thread (as mentioned by user3183610) your signal will be direct connection (the default for same-thread). This effectively runs similarly to a function call. The signal is not queued, but instead the slot that the signal is connected to executes immediately - so you can think of it as a direct function call to the slot.
You can, however, change this behavior by using the Qt::QueuedConnection optional parameter at the end of your connect call:
connect(class_A_object,SIGNAL(signal_A()),class_B_object,on_signal_received, Qt::QueuedConnection);
This will force the use of the queue, your signal will be queued in the event loop and then other pending signals will be executed in order (this is often more desirable then DirectConnection because you can more easily guarantee the order of events). I tend towards to use of queued connections for this reason (though I believe direct is very slightly more efficient).
So for your code there is no return to the event loop until after on_button_click(). During on_button_click() you emit the diret signal signal_x() and immediately on_signal_received() is called (by-passing the event loop), when this finishes it returns back to on_button_click() - just like a function call would :)

Related

Cancel QThread in PyQt5

I have a GUI in PyQt5, which starts a QThread that reads from a serial port. The thread does quit, when it read all the data, but I want to be able to stop it when I click on a stop button. How do I do that? Here is the basic code:
# ...
class Worker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(list)
def __init__(self):
QObject.__init__(self)
self._Reader = Reader()
self._Reader.progress = self.progress
self._Reader.finished = self.finished
def run(self):
self._Reader.read()
class Ui(QtWidgets.QMainWindow):
# ...
def startClicked(self):
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.workerFinished)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.reportProgress)
self.thread.start()
def stopClicked(self):
# How do I stop the thread?
pass
when managing threads you can do, as states in the doc here: https://doc.qt.io/qt-5/qthread.html
You can stop the thread by calling exit() or quit().
https://doc.qt.io/qt-5/qthread.html#exit
exit:
Tells the thread's event loop to exit with a return code.
After calling this function, the thread leaves the event loop and returns from the call to QEventLoop::exec(). The QEventLoop::exec() function returns returnCode.
By convention, a returnCode of 0 means success, any non-zero value indicates an error.
https://doc.qt.io/qt-5/qthread.html#quit
quit:
Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0).
This function does nothing if the thread does not have an event loop.
I assume that you read data in some data processing loop. If this assumption is wrong, then the following is not valid, of course.
You cannot call secondary thread's quit() directly from the main thread and expect that the secondary thread will process it immediately and quit the thread. The reason is that the thread is busy reading the data in the data processing loop. So you need to break the data processing loop in the secondary thread to make the event loop idle.
(Btw. do not confuse the data processing loop with the event loop. Data processing loop is the one which you have written yourself to read data from the port. The event loop is the loop created by Qt automatically after you called QThread::start() and which is processing events, signals and slots in the secondary thread. This event loop is blocked while your data processing loop is running.)
In order to break the data processing loop, you need to do two things:
call QThread::requestInterruption() from the main thread as response to some "Abort" button having been pressed (do not worry about thread safety, requesting interruption is thread safe/atomic)
within the loop in the secondary thread you need to periodically check QThread::isInterruptionRequested(), and if this returns true, then break the loop and emit worker's finished() signal
Once you broke from the data processing loop in the secondary thread, the event loop in the secondary thread becomes available for processing signals sent from the main thread.
I can see in your code that worker's finished() signal is connected to QThread::quit(). So emitting finished() from the secondary thread (after you broke from the data processing loop) will call thread's quit() which will be processed by the secondary thread's event loop (which is now idle) and it will quit the event loop and subsequently the thread and if you have connected everything correctly it will delete the worker and the thread. (though I have not checked this part of your code)

How Qt Handle Events and Signal in Same EventLoop

I couldn't understand how qt handle events (e.g timer event, socket event etc.) and signals in same event loop.As I understand,timer and socket events are handled via select system call(in Unix like OS).
How an event loop handle signals while sleeping because of select system call.
In Qt, signals are used to call slots. When you emit a signal, there are, roughly speaking, only 2 options for calling the corresponding slot:
Direct slot call. This can be thought of as replacing a line with a signal emitting by a line with just a slot call. An event loop is not used to process this signal itself.
Delayed slot call. In this case, the signal will be converted to an event, and the event will be posted to the receiver event loop (the event enqueues in the event loop of the thread the receiver object is living in). From now on, for the processing receiver event loop, it makes no difference whether it was a signal or an event. The event will be picked up by the event loop and will cause the slot invocation sometime later.
From Qt doc: https://doc.qt.io/qt-5/signalsandslots.html#signals
When a signal is emitted, the slots connected to it are usually
executed immediately, just like a normal function call. When this
happens, the signals and slots mechanism is totally independent of any
GUI event loop. Execution of the code following the emit statement
will occur once all slots have returned. The situation is slightly
different when using queued connections; in such a case, the code
following the emit keyword will continue immediately, and the slots
will be executed later.
As for understanding an event loop, an event loop is just a loop which process one event from an event queue on each iteration.
In short, this can be represented as follows:
QQueue<QEvent> eventQueue; // Events (and pending slot calls as well) are added to this queue
...
// How an event loop works (schematically):
while(event = eventQueue.dequeue())
{
do_what_the_event_wants_or_ignore_it(event);
}
Read also https://wiki.qt.io/Threads_Events_QObjects

Qt synchronous method

I'm a pure Qt beginner and currently want to understand its basic concepts and how to use them in the right way. My question might appear as somehow "ragged" and I want to apologize for that in advance. This having said, the question is:
I want to implement a method, which "blocks" until the handling is finished (for what reason ever...). In order to do the internals, I have to use an asynchronous class, emmiting a signal when it has finished its job in the background. I want to use that in a blocking way:
QEventLoop myLoop;
workerClass x;
QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));
/* x is asnchrounous and will emit "finished" when ist job is done */
x.doTheJob();
myLoop.exec();
Will that work? According to some other postings around - it should. But what is going on exactly?
When a new instance of QEventLoop is just created, does it automatically mean, that signals emitted from myLoop are automatically handled within that new handler? Moreover, the loop starts some while after having started the job. What happens, when it emits already "finished", before myLopp is started?
I have been told by a collegue, that I could use
QEventLoop myLoop;
workerClass x;
QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));
/* doTheJob is a slot now */
QMetaObject::invokeMethod(x, "doTheJob", Qt::QueuedConnection);
myLoop.exec();
I understand, that in this case doTheJob is called from the event loop. But from which event loop? invokeMethod() is not told to invoke the method in a particular event loop (myLoop), so why should the event posted to myLoop instead into the "outer" loop? In fact, myLoop is not even running at that time...
I hope I was able to transport my question to be understandable by experts.
Many Thanks,
Michael
The key is QObject::connect:
QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));
This function says when finished() is emitted, myLoop.quit() should be called just after the event occurs. So in your example,
<--------thread A--------> | <--------thread B-------->
QEventLoop myLoop;
workerClass x;
x.doTheJob(); starts thread B
sleep in exec() workerClass::JobA();
sleeping..... workerClass::JobB();
sleeping..... workerClass::JobC();
sleeping..... workerClass::JobD();
sleeping..... workerClass::finished();
sleeping.....
wake up by quit();
myLoop.quit must be called after thread A is sleeping, otherwise thread A may sleep forever because quit may be called before sleeping. You have to find a way to specify this. But how? Take a look at QObject::connect, the last argument is
Qt::ConnectionType type = Qt::AutoConnection
And about Qt::AutoConnection,
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
The signal is emitted in thread B and the receiver myLoop is in thread A, that means you are using 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.
The slot myLoop.quit is invoked when control returns to the event loop, myLoop.exec. In other words, quit is invoked only when exec is running. This is exactly what we want and everything works fine. Therefore, your first example always runs correctly because the signal and slot are connecting together using Qt::QueuedConnection (from default value Qt::AutoConnection).
Your second example works fine because QObject::connect is the same, too.
If you change it to Qt::DirectConnection, the story is different. quit is called in thread B, it is possible that quit is called before exec and thread A is going to sleep forever. So in this scenario you should never use Qt::DirectConnection.
The story is about QObject::connect and threads. QMetaObject::invokeMethod is not related to this, it simply calls a function when the thread executes an exec function.
on your first part of the question: yes that will work.
There's actually a class for it in Qxt.
in order to understand how that works, you need to understand how event handling in general works, and this particular hack, while being a bad idea in generall, is a great way to learn it.
let's imaging a simplified call stack with just one mainloop:
6 myslot()
5 magic
4 someEvent.emit
3 eventloop.exec
2 qapplication.exec
1 main
as long as you don't return from myslot(), the "magic" cannot call any other slots that are connected to the same signal, and no other signal can be processed.
Now, with the nested eventloop "signalwaiter" hack:
10 myslot2()
9 magic
8 someEvent2.emit
7 eventloop.exec
6 myslot()
5 magic
4 someEvent.emit
3 eventloop.exec
2 qapplication.exec
1 main
we still cannot continue processing the event that we're blocking, but we can process new events, such as that signal you're connecting to quit.
This is not re-entrant, and generally a very bad idea. You may well end up with very hard to debug code, because you might be calling slots from a stack you don't expect.
The way to avoid the fire-before-exec problem, is to connect your signal to a slot that sets a flag. if the flag is set before exec, just don't exec.
However, for the sake of explanation, lets's see how your method works (it does work):
when you use Qt::QueuedConnection, a signal emission is not a stacked call anymore. It looks more like this:
5 eventloop.putQueue
4 someSignal.emit
3 eventloop.exec
2 qapplication.exec
1 main
then emit returns
3 eventloop.exec
2 qapplication.exec
1 main
and eventloop puts your slot on the stack
5 myslot()
4 eventloop.pop
3 eventloop.exec
2 qapplication.exec
1 main
So at the time your slot is called, your signal has already been removed from the stack and all local variables are gone.
this is vastly different than DirectConnection, and important to understand for other stuff like QObject::deleteLater()
To answer the question which eventloop executes your queue: the one on top of the stack.

When to use deleteLater

Assuming I have the following snippet, is it safe to call deleteLater in qto's destructor for other QT objects it might administer?
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyQTObject qto;
qto.show();
return a.exec();
}
Because I've analyzed similar code like this with a leak detector and all the objects for which deleteLater was called, weren't deallocated correctly unless I replaced the call with a normal delete.
If I've understood this correctly, deleteLater only registers a deletion event in the QT message queue. Can this be the problem that qto's destructor is called at the end of main's scope whereas the QT message loop already ends with the return from a.exec? Thus the deletion event will never be processed, in fact not even pushed into a message queue since there is none?
This post is rather aged, but I would like to add the answer I would have liked to come across when I was asking this myself.
deleteLater() can be very useful in combination with asynchronous operations. It especially shines, I think, with the more recent possibility to connect signals to lambda functions.
Suppose you have some longComputation() that you want to execute asynchronously (not in the sense of multithreading, in the sense of scheduling execution in the event loop). You can do like this:
void MyClass::deferLongComputation()
{
QTimer* timer = new QTimer();
connect(timer,
&QTimer::timeout,
[this, timer](){this->longComputiation(); timer->deleteLater();});
timer->setSingleShot(true);
timer->start();
}
where deleteLater() takes care of safely disposing of the QTimer once its duty has been carried out and avoid the memory leak that one would have otherwise.
The same pattern can be used in multithreading with QFutureWatcher.
As I understand it, deleteLater is most often used when you require an object to be deleted from within the call to a slot. If delete is used in this case and the object is referenced when returning from the slot, a reference to uninitialised memory occurs.
Therefore, deleteLater requests that object to be deleted by placing a message on the event loop, which is processed at some point, on returning from the slot and it is safe to be deleted.
I expect that using deleteLater in the destructor means there's a likely chance that the object goes out of scope, calls deleteLater on its managed objects, but quits before the event loop has a chance to delete the objects, as exiting from QApplication::exec() will terminate the event loop.
The question is old, but I'll leave this for the future generation)
The reply which was marked as an answer is correct but oddly formulated.
Actually your question contains a right answer:
message loop already ends with the return from a.exec? Thus the
deletion event will never be processed, in fact not even pushed into a
message queue since there is none.
This is exactly what is happening. Everything deleteLater() does is just posting a deletion event into the outter event loop. When event gets proccessed - object gets deleted. But if there are not outter event loop and no event loop is encountered later in the execution flow - event will never get posted, thus object is never deleted.
If you call deleteLater() in the object's destructor and put an object on the stack - deleteLater() is called when the object goes out of scope. In your example "going out of scope" is happening when closing brace of main() function is encountered. However, by that time, a.exec() (which represents the main event loop of Qt App) has already returned --> no event loop any more --> deleteLater() was called, but it's nowhere to post a deletion event --> objects were supposed to be "deletedLater" never get deleted...
Regarding the part "when to use deleteLater()":
Kuba Ober answered:
Generally speaking, there is a narrow set of circumstances where
deleteLater should be used. Most likely you simply shouldn't be using
it...
Don't listen to it, it is absolutely incorrect as the whole answer. What you should do and what should not you better decide after reading this article. Although, it is mainly about Qt threads, the article also tells about ascynchronous programming (and, as Emerald Weapon mentioned, it is exactly what deleteLater() was created for).
Also, smart pointers and QObject parent ownership have nothing to do with scheduling for the deletion with deleteLater(). These both techniques are actually using a simple delete operation under the hood. And as the article shows and as Emerald Weapon's answer demonstrated: delete does not solve the problems deleteLater() does. So if you need to delete object you use delete, if you need to schedule it for the deletion you use deleteLater().
BTW, if you want to use smart pointer with deleteLater() you can specify the deleter:
// Shared Pointer
QSharedPointer<MyObject> obj =
QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);
// Scoped Pointer
QScopedPointer<MyObject, QScopedPointerDeleteLater> customPointer(new MyObject);
And at last, It is an NOT an error to use deleteLater() in the destructor of QObject, for non-child objects.
You are correct that the deleteLater() command is only executed by an event loop.
From the Qt documentation for QObject:
Schedules this object for deletion.
The object will be deleted when control returns to the event
loop. If the event loop is not running when this function is
called (e.g. deleteLater() is called on an object before
QCoreApplication::exec()), the object will be deleted once the
event loop is started. If deleteLater() is called after the main event loop
has stopped, the object will not be deleted.
Since Qt 4.8, if deleteLater() is called on an object that lives in a
thread with no running event loop, the object will be destroyed when the
thread finishes.
Note that entering and leaving a new event loop (e.g., by opening a modal
dialog) will \e not perform the deferred deletion; for the object to be
deleted, the control must return to the event loop from which
deleteLater() was called.
Note: It is safe to call this function more than once; when the
first deferred deletion event is delivered, any pending events for the
object are removed from the event queue.
If you want all child QObjects to be deleted when qto is deleted, make sure they are created with qto as a the parent.
Generally speaking, there is a narrow set of circumstances where deleteLater should be used. Most likely you simply shouldn't be using it.
It is an error to use it in the destructor of QObject, for non-child objects. As you've found QObjects may well be destructed without an event loop present. There are no deleteLater calls in object destructors the qtbase Qt module, for example.
One has to be careful here: for example, ~QTcpServer() invokes close() invoking d->socketEngine->deleteLater(), but the socket engine is already a child of the server and will be deleted by ~QObject() anyway.
For all I know, MyQTObject should be doing one of the following:
using a smart pointer like QScopedPointer or std::unique_ptr,
have the objects as regular (non-pointer) members,
use raw pointers and have the objects be children of it.

Qt Direct Connection

I have created Qt tree control( and its nodes ) in different thread than the main thread. In the main thread I want to show context menu for the clicked node, so I am connectiong the actions in the menu with appropriate slots in the main thread. The connect function returns true , but slot is never executed. If I explicitly say in connect function that this is Qt :: DirectConnection then everything works fine. Why is this ?
I I create my tree in main thread, everything also works fine , without having to say that this is Qt::DirectConnection .
See the documentation here.
The default connection type, Qt::AutoConnection, is the same as Qt::DirectConnection if the signal is sent from the same thread as the receiver slot, otherwise the behaviour is the same as Qt::QueuedConnection.
In the case where you create the widget in the main thread, you basically get the same behaviour as when you explicitly specify Qt::DirectConnection.
The behaviour of Qt::QueuedConnection is to call the slot when that threads event loop regains control.
To solve your problem, make sure you have an event loop in every thread which may be receiving signals, unless you manually specify Qt::DirectConnection (which, I assume, will mean the slot is called from the same thread as the signals emitter - basically the equivelent of a normal function call).

Resources