Closest JUCE equivalent to dispatch_async

I’m just migrating my app to C++ and I want to use JUCE as a cross-platform framework for it.
My app is currently Objective-C and uses a lot of dispatch_async blocks to dispatch some lambdas either to a background or to the main thread.

What’s the easiest way to get a similar behavior with JUCE?

I had a look at a couple of threading classes but they all seemed a bit heavyweight so I just wanted to make sure to make the right decision before migrating everything over to JUCE.

ThreadPool has addJob (std::function< ThreadPoolJob::JobStatus()> job) and addJob (std::function< void()> job), so those can be used with C++11 lambdas.

For executing work on the GUI thread, there is MessageManager::callAsync(FunctionType functionToCall), which also accepts lambdas. edit : Note that you have to be very careful with what kind of a task you pass into this. If the task uses a pointer or reference to something that could be destroyed before the message queue gets to calling the task, the nasty consequences should be pretty obvious.

Note that the behaviors of these may not be like what libdispatch offers, so you will need to experiment how they work for you. Also if you are going to be Mac-only, you can use the libdispatch C API from C++ code. (It is a bit tricky if you want to run stuff like lambdas with captures, but it is possible to do.)

This is a particularly good function for shooting yourself in the foot.

You want to explain that a bit more?

I think it’s more fun as a cliff-hanger?

1 Like

More seriously: the problem is that a thread puts a function in the queue using callAsync. And that has something to a pointer that gets deleted before the callback happens. (Maybe the user closes a window which deletes a component).

This isn’t something that can happen with, say, an AsyncUpdater type solution.

So the safe solution is something like callAsync with a WeakReference but it rapidly becomes a bit verbose and easy to get wrong.

Well, that should be pretty obvious stuff, if somewhat paranoid. Is there some way that condition can realistically be triggered by end user action? I guess if the message queue is completely stuck with messages so that it takes for the callAsync task a long time to get to the call, I guess the user might have managed to close a window in the mean time…But then the question would become, why is the message queue so full?

1 Like

This sounds like you’re looking for some statistically acceptable crash rate? :slight_smile:

Let’s suppose that you’ve got some event calling callAsync once a second to update some display component. Then if your existing UI loop is taking I dunno 5 ms to execute some updates on the message thread I guess you’d get a problem crash with 1 in every 200 clicks on a close button on that display?

I’ve not tested it so my logic might be shitty here:)

I am not sure if that’s a realistic scenario, if such a periodic thing is desired, then one would surely use a timer appropriately…

Well if it it’s only a one off event I think it’s worse than it seems because the very action of closing the application or a window is likely to cause a delay in the event loop as loads of stuff is cleared up on the message thread providing a whooping huge window for some thing to go wrong…

But I think the fundamental point is that you want some kind of assurance that anything referred to from a lambda passed into callAsync will still be around when the lambda is executed in the future. Otherwise it might crash occasionally (for some value of occasionally).

I edited my original reply to the original poster to mention about the danger involved. Since he mentioned he has been using Objective-C and now switching to C++, the danger is even higher because Objective-C has all that fancy object reference counting and so on.

1 Like

Thanks for your replies, guys! Much appreciated!
The whole point of migrating the app to C++ is because I want to move to Windows as well so using libdispatch directly is not an option.

I want to use JUCE’s functionality in my macOS native app and won’t be using JUCEApplication (using a hybrid approach). I assume the MessageManager needs this to work. The Windows version will be JUCE only though.

So looks like I will write myself some functions which use dispatch_async on the Mac and your suggested functions on Windows

Thanks for your help!

Check out this cross-platform port of libdispatch: