i have a thread that tries to build a SVG Drawable. This thread runs in the background loading a preparing things. Unfortunately, this causes a conflict with the message manager. A Juce assert tells me to use a MessageManagerLock, but this is bad because of two reasons:
i don’t want the background thread blocking the foreground UI, otherwise i might as well not use a thread for this at all.
i get deadlock whenever the UI is waits for the results of the thread, because the UI will, at this time, be already holding the MM lock.
Ok, so perusing the Juce code reveals the issue is because, in theory, the components being assembled by the thread could potentially be updating the screen etc. However, this is never the case, since the objects in question are yet to be used.
Now, for my purposes here, if i comment out the Juce assert that insists on the lock and ignore locking, everything works fine. i know this is fine here because of what i’m doing. But, of course, this is not true in general.
So, i was thinking of two possible ways around this for Juce.
- Factor out the SVG parsing stuff so that a bunch of Drawables could be constructed quickly from some sort of `ParsedSVGTree’ or somesuch.
- Introduce a new Component flag, eg
inactive' (as opposed to disabled), whereby components with this flag never frob the UI or the event system and therefore do not insist on, or need, a MessageManagerLock. The idea here would be to construct Drawables in aninactive’ state, and then “activate” them later before adding them to the UI.
or is there something obvious i’ve missed.
Correct me if I’m wrong (Jules?) but I believe the assumption is that Component methods are only safe to call from the message thread.
i think, generally, you would only want to call the component methods from the UI thread. However, there are cases such as when you might want to unpack a component from a stream that you might want to do this on another thread. Basically, anything other than drawing is a candidate for this.
Regarding the MessageManagerLock, if another thread must acquire this lock to affect components, potentially blocking the UI thread, then it doesn’t really make any gain to do this on a separate thread. instead, it could dispatch a message to the UI thread to perform it.
I want to construct a Drawable on a background thread and “hand it over” to the UI thread to draw, without blocking the UI. Once i’ve handed it over, i wont be calling any methods outside of the drawing thread.
Interesting… I’ve just had a quick go at making the assertions less strict, as I don’t really think there’s any reason for them to fire unless the component’s actually part of an on-screen hierarchy. This should help, but let me know if you hit any other assertions that I’ve missed!
Hi, Sorry for the delay.
Thanks for these awesome fixes. your assertion changes sort this out. there’s only one place missing; void Component::removeFromDesktop() requires also, CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN (gets called from `addChildComponent’).
otherwise works nicely.
Getting a CHECK_MESSAGE_MANAGER_IS_LOCKED in Component::addComponentListener (line 2165) when creating a drawable from an SVG on a different thread. Can this use the CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN check?
Yes… I guess so… It’s not technically correct, because it does open up the chance of race conditions, but I will add that change to stop it moaning in the case of drawables.
(TBH at some point I may decide to stop Drawables inheriting from Component, I think I made a bad decision when I set it up like that)