Is there a safer alternative than using delay when we want to ensure it is safe to run some code?

This is a query for general programming methods, but the specific context is that I am using the Common UI widget stack. I have a function to clear the stack, and a function to push new widgets to the stack.

There is a case where I clear the stack, and then shortly after push a new widget to the stack. But the code runs so quickly that it these functions step on eachother, so even though the Push function happens later in execution, the Clear function overrides it.

If I just put a tiny delay like this:
image

that solves the issue.

But is this safe? Because what is a persons computer is running slower? Is this delay a measure of time independent from frame rate? Is there a better method I might use to know for certain it is safe to call the Push function?

I don’t think an event dispatch would do here because there may be many different widgets that can call the clear stack function. I guess you might have to setup a queue to be completely safe? So when some widget request to the clear the stack, that goes to a queue, and then if some other class request to push a widget to stack, that also goes to the queue. Then the queue just fires off in order, which would ensure two request don’t go on top of each other.

That’s a lot of work to setup though - would you consider it worth the effort compared to just using a delay in the rare trouble cases?

It’s not safe, generally speaking.

Because things can happen very differently on someone else’s computer, it’s best to do one of two things:

  1. Wait for a sign that things are ready.

I had a lot of problems with level streaming and BPs initializing. I figured out in the end, that waiting for the player start to appear was enough. So I had a loop waiting until I could find that actor.

  1. Use a callback.

Register with an event dispatcher, so that when something is ready, an event gets called for you. The other object will either run the dispatcher, or tell the thing you registered with the run the dispatcher, when ready.

The queue idea sounds good too :slight_smile:

4 Likes

Could you share more the push and clear are setup?

Imo either clear is being called after or the problem is somewhere else.

2 Likes

Sure.

The Push and Clear functions live in a component that is attached to the HUD class (the one unreal gives you that is associated with the player controller). Reason for component is just organization.

Here is the Push Widget to Stack function:

the Push Widget node is the main thing - the other things are just ensuring prerequisite things are setup. I’ll show that just in case it matters, though I don’t think it does:

So this is the collapsed node prior to Push Widget:

And the Clear Stack function:

It is probably doing more than is truly needed, but basically it removes widgets from the stack, and then also removes the entire widget (that contains the stack). Probably it is only necessary to remove the widget, though I set this up a long time ago and perhaps there was some reason I was doing both.

So what happens step by step in this case is:

  • Widget is pushed to stack

  • button press reports to the game mode via interface that event has ended, then calls Escape which clears the stack:

  • Over in the Game mode, that interface goes through a couple nodes before calling Push to Stack:

  • Going through a switch and running some checks… then all the branches end up calling TO AAR, and first thing that does is to call the Push Widget To Stack function

So, looking at all this, it seems like there is some possibility for overlap, though it is surprising because quite a few things happen between time that Clear stack is called compared to the next Push to Stack.

Adding that delay seems to solve the problem, hence leading me to believe it’s an issue of the Clear stack getting called after the Push.

Also, the output log seems to confirm that:

The highlighted portion is reporting that a widget is pushed to stack (this is from the TO AAR function).
Then, the stack is cleared (only place stack has been called to Clear was from the previous widget. And using the delay does cause things to work appropriately, so I think that rules out possibility that somewhere else the Clear stack was inadvertantly called)

1 Like

Also, if I breakpoint at the time the Escape is called and advance frame by frame, it goes through all the steps of getting back to that component and clearing the stack before getting to the interface stuff. Though perhaps these must be running at the same time, then?

One more note:

The highlighted line is where the dialog widget is pushed to stack. But the Clear Stack (yellow warning at bottom) is not called until after all of that interface stuff happens and the next widget had been pushed to stack (the UI_AAR)

So I think that means that these things must be running parallel, and for some reason the interface to game mode series of events runs faster.

Well, whatever the reason, I guess this indicates that something like a queue or callback is required for maximum safety… in this case, I think the queue is more work to setup, however it would be self-managing compared to using callbacks I think.

hold up. I think I am being really stupid.

the interface stuff all fires first because I am calling it first.

Dunno why this escaped me. So it makes sense that the clear stack happens after the interface stuff - nothing crazy going on at all.

I’ll award the solution to @pezzot1 since they’ve indicated it was probably a simple mistake and made me look closer into it.

2 Likes