MessageManagerLock from Message Thread?

I’ve got some icons (DrawablePaths) attached to my parameters, mostly they get set at startup from static path objects and such.

Since Drawable path is a component, and calls repaint() on itself when it changes, it does a quick check that the message manager is locked.

So, I call all of these within MessageManager::callAsync blocks.

Somehow, it still hits the assertion though (on the message thread). I would have thought that JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED would not assert false when called ON the message thread?

Adding a lock here causes a deadlock, of course, so that’s no good.

void ParameterValueObject::setIcon(Path pathToUse) {

    WeakReference<ParameterValueObject> param (this);
    MessageManager::callAsync([param, pathToUse]()
    {
        if (param)
        {
            jassert(MessageManager::getInstance()->isThisTheMessageThread());

            param->myIcon.setStrokeThickness(1);
            param->myIcon.setStrokeFill(Colours::grey);
            param->myIcon.setFill(Colours::darkgrey);
            param->myIcon.setPath(pathToUse);
        }
    });
}

I assume I’m missing something simple here … someone please tell me what ~ !

The problem isn’t obvious to me. Your reasoning makes sense.

JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED should not assert when called on the message thread or on a thread that is holding the MessageManagerLock.

I wonder how your static objects are set up. I have had issues in the past with certain JUCE objects that cannot safely be initialised as global static objects. If I remember correctly juce::Font is an example of an object that should not be initialised as a global static.
Are you perhaps instantiating juce::Component as global statics?

I wonder why you are doing an async operation here. Can you not just do the things inside the lambda directly in the function it is in? Or is the function called on a thread?

Visual elements must be part of the Editor domain and not the Processor domain, where the parameters “live”.

What do you expect this combination of parameters with icons to do when there is no editor and the plugin is just processing?

I advise you to read more on the relation between processor and editor, and their lifetimes within a plugin. If you adhere to the basic principles, your code will be really much more simpler.

Try to see parameters as invisible “state” and icons, etc. as their “representation”. Your editor part should be able to render a representation of the plugins internal state. But the state itself should be completely agnostic about the representation, the view.

If you follow this pattern, you will probably not need weakReferences, message manager locks, async msg callbacks, etc.

1 Like

Maybe try stepping into JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED, because there are a couple of other things that this macro checks for that could be going wrong.

1 Like

Ok, let me see if I can answer the questions.

None of this is as a global static, other than some paths … which live inside a SharedResourcePointer and I’m pretty sure it’s safe. I have seen exactly that issue with Fonts though, as you elude too.

Per calling this within a lambda: I would have to lock the MM in the lambda which would be a problem since this is done in some constructors where you really can’t lock the MM thread (hence the Async call).

Regarding best practices, I completely agree that components shouldn’t live in the processor. I was quite surprised to find that Drawables were components! You can, of course, add something like a Colour, or Path inside the processor … and I would have thought DrawablePaths were similar. Jules even says he regrets not separating the Component aspects of Drawables from the classes themselves on this thread (Is there any way to convert svg to Image on a background thread? - #5 by xenakios)

In any event, the likely best solution here is for me to get rid of the DrawablePath object in favor of Paths and Colors, which can essentially represent the same thing and just construct the DrawablePath in the relevant components.

Per JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED - good idea to step through it, I’ll take a look!!

There’s in principle no problem having the AudioProcessor own Components and other GUI things. You just won’t be able to directly use most methods of those from the audio thread code, so there’s fairly limited value in doing that. One exception that comes to mind is the AudioVisualizerComponent that explicitly has support in a few methods to be used from the audio thread.

1 Like