Qt Signals and Slots overhead for embedded linux - qt

I'm just curious how much overhead I might incur in a program that... abuses signals and slots ridiculously. Our app has almost everything connected via signals and slots. We've replaced calling functions with signals and slots for general data flow so we're passing data along a crazy chain.
I've already shown some concern on the design on this to see how easy it will be to debug/follow later but I'm curious about the performance we'll see. We have a small app now, but I imagine we'll see some issues as the program grows out of control.
Just to give a small idea of how much we are abusing signals, we are emiting a signal to call a logging function

Related

Is it possible to re-paint/update content in a Qt GUI application although the main thread is blocked?

There is a lot of discussion (e.g. here) going on about spinning or moving busy indicators in a GUI but I could not find a single one that clearly states that it is impossible to re-paint/update any content in a GUI application while the main thread is blocked.
This question is actually a general one and is not necessarily directly related to Qt GUI applications.
When the main thread of a GUI is performing a blocking operation no events are processed and no content can be re-painted. There are two "recommended" approaches:
Using worker threads
Splitting the work in chunks and updating the UI "just not that often"
The problem is that there are operations that simply cannot be moved to worker threads or any other asynchronous mechanism. The best example is the serialization and de-serialization of the UI itself. In both scenarios the user must not click happily in the UI and change settings while the settings, properties, etc. are taken from the widgets (during the saving) or applied to the widgets (during the loading). This is true for the threading approach as well as the splitting into chunks.
Edit: Another example is the application of stylesheets to a complete GUI. Imagine that a user wants so select a "dark" scheme. All of the widgets need to be updated and the currently visible ones needs to be re-painted. During this step the event loop cannot run. A similar discussion can be found here.
In my case I'm working on an embedded device so there is another approach:
Directly overwriting a specific region of the framebuffer
This approach feels very ugly and comes with a lot of problematic scenarios and surly involves lots of debugging.
The last but sad approach:
Do not use any moving/updating content at all and just show something static such as "...in progress..."
Well, this is just sad...
Do you agree on these observations? Does anyone know of a different approach or concept in general un-related to Qt?
The problem is that there are operations that simply cannot be moved to worker threads or any other asynchronous mechanism.
I can't agree. These operations should be split into blocking and non-blocking operations. Everything that blocks should be handled asynchronously, or, if no non-blocking APIs are available, handed off to a worker thread.
The best example is the serialization and de-serialization of the UI itself.
I find it a particularly poor example mainly because I've yet to run into a need for blocking the GUI, and serialization doesn't call for it.
In both scenarios the user must not click happily in the UI and change settings while the settings, properties, etc. are saved or loaded.
Construction and destruction of the widgets should be very quick, if that's what you mean by "deserializing" the UI. Recall that the blocking I/O and long parsing has been done in another thread. Almost all Qt widgets certainly are quick to set up, and those that are not are a necessary evil that you have no choice but to live with. If you have your own widgets that do blocking operations like disk or registry access in their constructors or event handlers (plenty of such "code" exists), fix them.
If you're merely talking about setting widget values, this again is super-quick and can be done all in one batch. You will probably need a viewmodel to asynchronously interface between the view (widgets, QML view, or a QAbstractItemView) and the data source.
Disk I/O and parsing/output of the on-disk representation belongs in a separate worker. Once you create an internal representation, it can be passed to the gui thread to build the widget tree or populate the interface.
You should implement thread-safe models using QAbstractItemModel or a similar interface, and populate them in a worker thread, and let the GUI thread react to the updates in real time.
If you wish to indicate to the user that a part of the interface is not usable yet, e.g. while a model gets populated, you could do so via an overlay, making sure that you temporarily disable the focus on the widgets that are under the overlay. This is not hard and I'd find it amusing if your entire question could be reduced to "how do I make a part of the UI inaccessible while it's being modified".
The key thing missing is that the UI should handle asynchronously reacting to a model changing its state. For all I care, it could take an hour to load the data needed to fully populate the model. It doesn't mean that your application should be unresponsive. Simply make the parts of the UI that can't be interacted with inaccessible for interaction. Ensure that other parts of the application that need the configuration data are similarly either inaccessible or in a partially usable state that will asynchronously revert to full state once the configuration becomes available.

Why should nesting of QEventLoops be avoided?

In his Qt event loop, networking and I/O API talk, Thiago Macieira mentions that nesting of QEventLoop's should be avoided:
QEventLoop is for nesting event Loops... Avoid it if you can because it creates a number of problems: things might reenter, new activations of sockets or timers that you were not expecting.
Can anybody expand on what he is referring to? I maintain a lot of code that uses modal dialogs which internally nest a new event loop when exec() is called so I'm very interested in knowing what kind of problems this may lead to.
A nested event loop costs you 1-2kb of stack. It takes up 5% of the L1 data cache on typical 32kb L1 cache CPUs, give-or-take.
It has the capacity to reenter any code already on the call stack. There are no guarantees that any of that code was designed to be reentrant. I'm talking about your code, not Qt's code. It can reenter code that has started this event loop, and unless you explicitly control this recursion, there are no guarantees that you won't eventually run out of stack space.
In current Qt, there are two places where, due to a long standing API bugs or platform inadequacies, you have to use nested exec: QDrag and platform file dialogs (on some platforms). You simply don't need to use it anywhere else. You do not need a nested event loop for non-platform modal dialogs.
Reentering the event loop is usually caused by writing pseudo-synchronous code where one laments the supposed lack of yield() (co_yield and co_await has landed in C++ now!), hides one's head in the sand and uses exec() instead. Such code typically ends up being barely palatable spaghetti and is unnecessary.
For modern C++, using the C++20 coroutines is worthwhile; there are some Qt-based experiments around, easy to build on.
There are Qt-native implementations of stackful coroutines: Skycoder42/QtCoroutings - a recent project, and the older ckamm/qt-coroutine. I'm not sure how fresh the latter code is. It looks that it all worked at some point.
Writing asynchronous code cleanly without coroutines is usually accomplished through state machines, see this answer for an example, and QP framework for an implementation different from QStateMachine.
Personal anecdote: I couldn't wait for C++ coroutines to become production-ready, and I now write asynchronous communication code in golang, and statically link that into a Qt application. Works great, the garbage collector is unnoticeable, and the code is way easier to read and write than C++ with coroutines. I had a lot of code written using C++ coroutines TS, but moved it all to golang and I don't regret it.
A nested event loop will lead to ordering inversion. (at least on qt4)
Lets say you have the following sequence of things happening
enqueued in outer loop: 1,2,3
processing 1 => spawn inner loop
enqueue 4 in inner loop
processing 4
exit inner loop
processing 2
So you see the processing order was: 1,4,2,3.
I speak from experience and this usually resulted in a crash in my code.

How to keep track of signals and slots in Qt?

This question is not directly about programming, but I hope that it still fits here: When programming with Qt I have the problem that after some times my subclasses are getting extremely large which leads to a lot of signals and slots in each class I have to connect later. Therefore I was wondering if there is a simple possibility to keep track of all the signals and slots, for example to tell me if I forgot to connect a signal, or to show me all connections of one signal if it is connected more than once. Is there a tool or a function in Qt for that, or should I rather stay with pen & paper for keeping track of them?
Conan is a C++ library that provides run-time introspection of object
hierarchies, object inheritance, signal/slot connections, and signal
emissions.
GammaRay is another advanced analyser which can show signals/slots.

Dynamic connecting/disconnecting signals and slots

My program has two states and it can switch between them for some reasons. In these states the program needs to receive different signals, which means it has to connect and disconnect certain signals during the run.
How bad is such approach?
It's a fine approach, I've used it before without issues. Depending on what you're actually doing a QSignalMapper might be of use for you.

Replacing WaitForMultipleObjects in Qt

I am not familar with WINAPI, and I am looking for a way to replace WaitForMultipleObjects used in one example I'm porting to Qt by anything using Qt only. Is it possible?
EDIT: (Providing more information as requested in comments)
A 3rd party API provides an array of events:
HANDLE m_hEv[MAX_EV];
In an endles-loop of a thread, the program waits for the events like this:
WaitForMultipleObjects(m_EvMax, m_hEv, FALSE ,INFINITE )
The HANDLE type seems to be void*.
So I wonder, if any Qt class could observe m_hEv for changes and unlock thread execution.
There is no simple way of porting WaitForMultipleObjects outside WinAPI. WinAPI has an "advantage" of that all lockable resources (sockets, files, processes) provide the same generic non-typesafe HANDLE, which is your void*. Unlike other platforms which have different ways of locking and signalling per the type of resource, the event handling in WinAPI is largely independent of the resources. Then a generic function like WaitForMultipleObjects can exist, which doesn't need to care who produced the HANDLEs. So you'll have to understand what the code is trying to do and mimic it differently per scenario.
The biggest difference is in WaitForMultipleObjects third parameter, which is FALSE in your case. Which means that the it will exit waiting as soon as any single event of the waiting array will happen. That is the easier scenario and can be replaced with a QWaitCondition.
Instead of m_hEv, you will pass a QWaitCondition* into the code which signals the event (most probably via WinAPI SetEvent(m_hEv[x]))
Instead of WaitForMultipleObjects, do QWaitCondition::wait().
Instead of SetEvent(), do QWaitCondition::wakeOne().
Would the third parameter be TRUE, then the WinAPI code waits until ALL m_hEv events are signalled. The established name for such functionality is a synchronization barrier and it can be simulated with QEventCondition too, but does not come out of the Qt box. I never needed to do any myself, but SO has some ideas how to do it:
Qt synchronization barrier?
WaitForMultipleObjects is a kind of generic function that works with many things: threads, processes, mutexes, etc. Qt is an OOP library where every class exposes the operations it supports. So the equivalent operation in Qt depends on what class you're using. For example, with threads, use QThread::wait. With mutexes, use QMutex::lock.

Resources