On 2 Feb 2023, at 20:27, Stefan Seefeld <ste...@seefeld.name> wrote:


I haven't got any response to my question, but as the answer may really help us 
simplify our code I'm sending it again.
Thanks for any help !

On Tue, Nov 22, 2022 at 9:02 AM Stefan Seefeld 
<ste...@seefeld.name<mailto:ste...@seefeld.name>> wrote:
we are using Qt State Machines in a number of places in our applications to 
manage object states for certain types of objects. Occasionally I would like to 
use and manipulate such objects in a non-event-driven context, i.e. without a 
running event loop.
Short of a StateMachine function that allows me to wait for outstanding 
transitions to be completed, I wrote a little helper function that instantiates 
a `QEventLoop`, then calls `processEvents(QEventLoop::ExcludeUserInputEvents)` 
to drain the event queue and thus make sure that all in-flight transitions have 
been completed.
While this appears to be working fine, I'm not sure this is the best way (or at 
the very least, a particularly elegant way) to achieve what I want.

Is the above a "correct" way to get what I want ? Is there a better way ?


On 4 Feb 2023, at 20:11, Stefan Seefeld <ste...@seefeld.name> wrote:

Hi Roland,

thanks for your feedback !
I partially agree with your analysis. In particular, I'm not entirely sure why 
the entire application logic needs to gravitate around a single event loop. For 
user-input events this of course makes sense, as they are naturally ordered and 
so conceptually we don't need concurrency to model the related control-flow. 
(We do need asynchrony, though !)

My main puzzlement stems from the fact that the event loop is used in places 
where I don't expect it, such as in the handling of state machines. Of course, 
state changes may well be triggered by user input (or some other events), but 
they don't have to, so it seems questionable why the entire state machine 
architecture has to be founded on the event loop as well. It could be 
independent, with some mix-in classes that allow state machines to interact 
with the event loop, without forcing such a dependency on everyone.

But to get back to the smaller scope of my original question, users don't even 
have to access the main event loop via the `QApplication::processEvents()` 
function; they can just create their own local `QEventLoop` instance and use 
that. (Of course, under the hood that has to interact with the main event loop, 
which is why this only works in the presence of a global `QApplication` 
instance, but that interaction is luckily already hidden from the user.)

My question is: Is it OK to use my own local `QEventLoop` to drain events to 
render state-change requests synchronous. And furthermore, if the answer is 
"yes", is there a reason why such a facility isn't already offered by the Qt 
API itself ?

I'd really like to hear what Qt developers have to say about this, and, as you 
suggest, about the broader question of how to scale Qt applications to modern 
many-core platforms. How would users write modern C++-2x applications while 
using `co_await` ? There already are adapters for the Python equivalent, using 
`QEventLoop` instances to manage events and dispatch control flow to multiple 
threads (e.g. https://github.com/CabbageDevelopment/qasync). It seems to me 
what I'm asking for is something similar, if not much simpler).


Hi Stefan,

Where do you see the advantages of synchronously waiting for a state to be 
reached, when instead you can connect to the respective state’s entered() 
signal? The former might make your code look more linear of course, with less 
complexities due to object lifetimes etc.

When the QtState Machine framework was added it was done so in the context of a 
UI framework, so a core design choice was to drive the state machine 
asynchronously so that the UI doesn’t freeze. And since then, we had no 
compelling reason to modify that architecture. It seems to work well enough in 
the context of a UI framework, where state transitions are triggered by events. 
Or maybe people have silently migrated to alternative state machine frameworks.

QStateMachine could live in it’s own thread which can run its own event loop. 
States emit signals, so objects interesting in state enter/exit notifications 
can connect to those signals even if they live in threads other than the state 
machine. And a QSignalTransition could operate on a sender living in a 
different thread as well (QEventTransition can’t support that though). So 
asynchronicity could be achieved that way as well, but it doesn’t solve your 
problem of stopping your code until a state has been reached. The design of Qt 
State Machine is that you put that code into a callable connected to the 
respective signals.

That is a general question. We probably don’t want more waitFor… style APIs in 
Qt. If we would add such APIs, they might very well be implemented by a local 
QEventLoop that runs until the signal you are waiting for gets emitted. So your 
solution is reasonable. Why is it not in Qt? Because nobody asked for it, 
needed it, or contributed a solution so far. And perhaps it’s ok to leave that 
solution to the client, as not every waitFor… use case might want to e.g. 

Co-routines might at some point become the standard tool also for Qt 
application developers to solve that kind of problem. What that could look like 
continues to be a subject of research. Ville has commented on that in the past 
[1] and has recently played with Qt and sender/receiver (i.e. P2300), which got 
even Eric Niebler excited [2].


[1] https://lists.qt-project.org/pipermail/development/2021-March/041110.html
[2] https://twitter.com/ericniebler/status/1616180736914264066

Interest mailing list

Reply via email to