I have a single-thread gui application and I do not choose a type of connection, so according to documentation the connection will be a direct one. According to documentation then: "The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread."
For my understanding, this obviously leads to the conclusion that if I disconnect such an auto-connection in a method, then there is a guarantee that there is no possibility that after completion of this method (in which I do the disconnection) I can get a slot (corresponding to the just-disconnected connection) still being called. The reason of that is, as far as I understand, the fact that no event queue is used for such an auto (here direct) connection.
Am I right? Or should I be careful and better keep a state-variable and double check this state and return from the slot if it's in a some (unclear to me) way still got called? I am especially worried for the situations where I have connections, in which signals are produced by Qt entities (e.g. signals QNetworkReply::finished(), etc.), rather than by me, as I do not control them fully.
I have found related questions, like this one, but I have not found the exact question, and so I have inconfidence and decided to ask.
If you use only direct connections then you can't "receive" any further signals after you disconnected from getting them. Direct connection is just a callback call, nothing more.
Related
From Qt documentation on Performance Considerations And Suggestions I got the following:
use asynchronous, event-driven programming wherever possible
I'm not sure what that means, so would like to ask. Does it mean I should use signal/slots whenever possible (because they are asynchronous?)?
Qt signals/slots are not necessarily asynchronous. From https://doc.qt.io/qt-5/threads-qobject.html:
Direct Connection: The slot is invoked immediately, when the signal is emitted. The slot is executed in the emitter's thread, which is not necessarily the receiver's thread.
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.
Blocking Queued Connection: The slot is invoked as for the Queued Connection, except the current thread blocks until the slot returns.
A signal subscribed to by a slot with a Direct Connection will be essentially a method call that you can "hook up" at runtime.
Also, yes, you should probably use "asynchronous, event-driven programming" "whenever possible" for a sane definition of "whenever possible".
Obviously, don't replace all method calls between your objects with signals and slots. And when you do use signals and slots, don't always make them asynchronous (Queued) - sometimes you will want the objects subscribed to your signals to finish their "reactions" to your signals before the emitting function proceeds.
In general, when you don't really care if the subscribers of your signals get their slots invoked immedtiatelly or later, just connect them up without specifying a connection type, and Qt will use Auto Connection, which will do the right thing (thread-wise). When you do care, just specify the type of connection you want.
If you feel confused by this at first, a reasonable thing to do might also be to make all connections Queued by default - you won't really notice any performance difference, and this might prevent you from accidentally writing code that depends on the slots executing "directly", when that was not your intent.
The suggestion in your link is mainly meant for any events that get generated on your main thread, most likely by UI elements - buttons, etc. The main idea is that you want to process any input events as quickly as possible, to keep the main thread free for accepting any later events and rendering your UI, and, if the events cause any significant work to be done, move that work to another thread, and have your main thread wait for a completion signal, so that your main thread remains "responsive". If you want your UI to immedtially react to any events, for example, by initiating a "loading spinner" or displaying a progress bar, you can, of course, do that directly. This, of course, also applies to any other threads that might need to remain responsive and handle other events while a larger calculation is happening in the background.
We are trying to write a portable shared library that makes use of some Qt classes for convenience (mainly QTimer and QTcpSocket); no GUI stuff, though. The according signal/slot connections appear to require some Qt event loop, so we "prime" a QCoreApplication as outlined in this answer. Accordingly, we set up a worker object that does the heavy lifting and move it to a QThread.
The problem we run into now is that the queued connections between the QThread's owner object (within the main thread) and the worker object within the QThread seem to never get handled on Linux systems, at least as long as the program that implements our library does not provide any further Qt event loop of its own in the main thread. This is not very helpful, since the data passed from the worker to the main thread should be passed further using some callback functions, which now never get called, though.
My question is thus: is there a way to get an event loop to work in the library main thread without locking it or the host program up (which seems to be the case when just putting a QCoreApplication::exec() or similar there)? Or will we have to set up a different inter-thread communication scheme (independent from Qt) in order to deal with these data transfers?
Since we do not know if the host software is going to run on a QApplication or not, ideally I'd also have a check for that before setting up a main thread event loop. Is a simple if(qApp != nullptr) enough for that?
P.S.: A few things I tried but which did not work for me, either:
Settings up a QEventLoop in a std::thread launched from the main thread (probably not working because still not in the main thread)
Setting up a QEventLoop in the main thread class and triggering its processEvents() function periodically using a QTimer (probably not working due to the missing event loop for the QTimer::timeout signal in the main function)
Starting the QCoreApplication in a std::thread (gives a run-time warning on Windows that QCoreApplication should be started in the main thread)
In Qt parlance, a callback is called Qt::DirectConnection. But of course those callbacks will run on your worker thread. But that’d be the case with any other library that uses callbacks, so Qt is not a problem here, and neither is your code: the basic idea has this property.
If the host application is not using an event loop (any event loop, not necessarily Qt’s), then there’s nothing you can do other than polling – see below.
If the host application runs an X11 event loop, then you need to ensure that your copy of Qt is using the same underlying event loop as the host application. Usually, this would be the glib’s event loop, and then it should work automagically. Otherwise, you’ll need to pass to the user the file descriptor of the synchronization primitive used by Qt’s event loop, and the user will need to integrate it into their event loop. You’ll face the same problem whether you use Qt or not: rolling your own communication method won’t fix it, since you still need a waitable primitive that will interoperate with whatever event loop the user is using.
The user can of course poll for callbacks whenever they feel like it: expose a mainPoll() method that forwards to QCoreApplication::processEvents().
Despite accepting another answer (which I deem more correct), I'd still like to mention a workaround that worked surprisingly well: We actually managed to get around the event loop/thread problems on most systems by connecting the worker thread signals with lambda functions in constructor of the class that sets up the worker.
Now, I doubt that this behaviour is properly thread-safe, and having relatively lengthy lambda functions declared in connect function calls is certainly not good style. But in case anyone else ends up struggling with this issue, this may be a short-term solution or (temporary) workaround.
I'm having trouble with Qt signals.
I don't understand how DirectConnection and QueuedConnection works?
I'd be thankful if someone will explain when to use which of these (sample code would be appreciated).
You won't see much of a difference unless you're working with objects having different thread affinities. Let's say you have QObjects A and B and they're both attached to different threads. A has a signal called somethingChanged() and B has a slot called handleChange().
If you use a direct connection
connect( A, SIGNAL(somethingChanged()), B, SLOT(handleChange()), Qt::DirectConnection );
the method handleChange() will actually run in the A's thread. Basically, it's as if emitting the signal calls the slot method "directly". If B::handleChange() isn't thread-safe, this can cause some (difficult to locate) bugs. At the very least, you're missing out on the benefits of the extra thread.
If you change the connection method to Qt::QueuedConnection (or, in this case, let Qt decide which method to use), things get more interesting. Assuming B's thread is running an event loop, emitting the signal will post an event to B's event loop. The event loop queues the event, and eventually invokes the slot method whenever control returns to it (it being the event loop). This makes it pretty easy to deal with communication between/among threads in Qt (again, assuming your threads are running their own local event loops). You don't have to worry about locks, etc. because the event loop serializes the slot invocations.
Note: If you don't know how to change a QObject's thread affinity, look into QObject::moveToThread. That should get you started.
Edit
I should clarify my opening sentence. It does make a difference if you specify a queued connection - even for two objects on the same thread. The event is still posted to the thread's event loop. So, the method call is still asynchronous, meaning it can be delayed in unpredictable ways (depending on any other events the loop may need to process). However, if you don't specify a connection method, the direct method is automatically used for connections between objects on the same thread (at least it is in Qt 4.8).
in addition to Jacob Robbins answer:
the statement "You won't see much of a difference unless you're working with objects having different thread affinities" is wrong;
emitting a signal to a direct connection within the same thread will execute the slot immediately, just like a simple function call.
emitting a signal to a queued connection within the same thread will enqueue the call into the threads event loop, thus the execution will always happen delayed.
QObject based class has a queued connection to itself
Jacob's answer is awesome. I'd just like to add a comparative example to Embedded Programming.
Coming from an embedded RTOS/ISR background, it was helpful to see the similarities in Qt's DirectConnection to Preemptive behavior of the ISRs and Qt's QueuedConnection to Queued Messages in an RTOS between tasks.
Side note: Coming from an Embedded background, it's difficult for me to not define the behavior in the programming. I never leave the argument as Auto, but that is just a personal opinion. I prefer everything to be explicitly written, and yes that gets difficult at times!
This question is more for my personal curiosity than anything important. I'm trying to keep all my code compatible with at least Windows and Mac. So far I've learned that I should base my code on POSIX and that's just great but...
Windows doesn't have a sigaction function so signal is used? According to:
What is the difference between sigaction and signal? there are some problems with signal.
The signal() function does not block other signals from arriving while the current handler is executing; sigaction() can block other signals until the current handler returns.
The signal() function resets the signal action back to SIG_DFL (default) for almost all signals. This means that the signal() handler must reinstall itself as its first action. It also opens up a window of vulnerability between the time when the signal is detected and the handler is reinstalled during which if a second instance of the signal arrives, the default behaviour (usually terminate, sometimes with prejudice - aka core dump) occurs.
If two SIGINT's come quickly then the application will terminate with default behavior. Is there any way to fix this behavior? What other implications do these two issues have on a process that, for instance wants to block SIGINT? Are there any other issues that I'm likely to run across while using signal? How do I fix them?
You really don't want to deal with signal()'s at all.
You want "events".
Ideally, you'll find a framework that's portable to all the main environments you wish to target - that would determine your choice of "event" implementation.
Here's an interesting thread that might help:
Game Objects Talking To Each Other
PS:
The main difference between signal() and sigaction() is that sigaction() is "signal()" on steroids - more options, allows SA_RESTART, etc. I'd discourage using either one unless you really, really need to.
If there are two slots in two different threads and these slots are connected to a signal in a third thread. Can it happen, that both slots get called at the same time by the signal or do they get called synchronized every time?
I ask because i want to send some callback data structure (encapsulated with QSharedPointer) and ask if locking mechanism inside is needed.
You don't need to lock the actual signal/slot calls if you're using a Qt::QueuedConnection to pass the information to your threads, as the QueuedConnection mechanism handles this in a thread-safe manner.
That being said, you still need to protect any shared memory your threads access, regardless of how they were called. The fact that a third thread emitted a single signal to cause both slots to be called will not change this.
Have a look here (official Qt documentation for Qt's signal/slot mechanism regarding threads).
Each slot is called inside its thread, therefore I am pretty sure anything can happen. You should install a lock mechanism.