Yes, that should work as long as you don’t delete the MultiAsyncUpdater concurrently with calling callOnMessageThread.
Also, for a small speed increase you probably want to move callback into the vector: queue.push_back (std::move (callback));
I’m going to talk about this next week…
In general though I’ve seen a lot of bugs arise from passing std::function by reference. If you’re going to make a copy anyway you might as well make the copy when passing the argument then move the parameter. Then, it’s up to the caller to move the argument if they don’t need it anymore. I’ve not looked in to it fully but I’m also hoping that one day compilers will be able to spot xvalues and automatically move them into arguments if they are values not references.
this is an old topic, but I stumbled into a similar situation. And I want to use the approach with the “SafePointer” inside a lambda. Thanks for suggesting.
You wrote, that one has to safeguard the creation of the SafePointer. Can you elaborate on that? When/why is that necessary? In case the function is not re-entrant?
Um, bit difficult to remember the context from 3 years ago…
I think in general though, you can only create SafePointers on the message thread as that’s the only time you know a Component won’t be being deleted from underneath you…
Thanks for explaining… I see…
When I call MessageManager::getInstance()->callAsync((), I am of course not on the message thread. So, I must create the SafePointer at some earlier point in time, I assume, when on the message thread?
Wondering if that’s really safe? Even if I create the SafePointer at an earlier time, the class could just be about to get destructed, while pushing the Async lambda on the message thread. Then I might copy an already destructed SafePointer to the lambda. Hmmm…
I am still a little new to this
How should I use AsyncUpdater to make it safer than MessageManager::getInstance()->callAsync ?
Both result in async execution on the message thread. And as far as I can see, both rely internally on MessageManager::MessageBase.
Doesn’t that make them equivalent?
Well it really depends on what you want to do. They’re different tools for different jobs. AsyncUpdater coalesces updates and is a simple signal notification, there’s no payload. If all you want to do is find out that another thread has finished its job, then this is the simplest tool.
MessageManager::callAsync is for dispatching specific messages (via std::function) to be called back from the message thread. If you call it multiple times, multiple messages will be dispatched and therefore delivered. These are useful for one-hit notifications.
However, as they’re asynchronous and you need to make sure anything the callback references is still valid when the callback happens. This often means capturing SafePointers (which internally are weak-pointers).
If you’re calling MessageManager::callAsync from a background thread, you also need to pay attention to data races as you would do in any other multi-threaded code. This usually means making sure objects can’t get deleted out from underneath you.