Call back to the Juce Message Thread in a non-C++11 way


#1

I am using Juce together with an internal SDK which has to be non-C++11 to support some old and exotic devices. Up until now I have been using juce::MessageManager::callAsync to call back to the Juce Message Thread from OpenGL Rendering threads when needed. This is, however, done using std::function/lambdas which are C++11.

So how can I call back to the Juce Message Thread in a non-C++11 way?

As an example, this is how I currently do it:

std::function<void(void)> myCoolLambda = [this]() { this->myCoolMemberFunctiion(); };
juce::MessageManager::callAsync(myCoolLambda);

I could not find a way to jump into the Juce Message Thread in the JuceApplication class. If that's possible, I could set a state variable from the OpenGL Thread and let the Juce Message Thread handle it when applicable.


#2

You can use callFunctionOnMessageThread for this (see http://www.juce.com/api/classMessageManager.html).

Hope this helps!

 


#3

Yeah, I saw that function, but I also saw the following comment from jules here: http://www.juce.com/forum/topic/help-callfunctiononmessagethread

Agh! No no no no...

You probably never want to call callFunctionOnMessageThread() - it has serious potential to deadlock. But even if it didn’t, calling it on your real-time thread is probably the worst place you could possibly use it! It blocks until the function has returned, so it’ll block your audio thread. (And possibly deadlock it too)

Just get yourself a shared atomic variable, write it in your audio thread, and use a timer or something in your UI thread to check it for changes.

This made me wonder whether it is a good idea to use callFunctionOnMessageThread  or not. And I have to call it from a real-time thread (the OpenGL Rendering thread) and jules points out that this is a bad place to call it. Or is it not?


#4

Yes, it's a bad idea to call it! Because it blocks the message thread.

The best non-C++11 way to invoke something asynchronously is with a CallbackMessage, which is safe because it's non-blocking.


#5

Thanks, CallbackMessage was easy to use and seems to work fine. Just to confirm: The description of the CallbackMessage states

Always create a new instance of a CallbackMessage on the heap, as it will be deleted automatically after the message has been delivered.

Does this mean that the following is ok to do?

{
    MyCallbackMessage* message = new MyCallbackMessage(this); // this is a QAHandler object
    message->post();
}

where myCallbackMessage is nothing but

MyCallbackMessage.h

class MyCallbackMessage : public juce::CallbackMessage
{
public:
    MyCallbackMessage(QAHandler* const qaHandler);
    ~MyCallbackMessage();
    void messageCallback() override;

private:
    juce::OptionalScopedPointer<QAHandler> mQAHandler;
};

MyCallbackMessage.cpp


MyCallbackMessage::MyCallbackMessage(QAHandler* const qaHandler) : mQAHandler(juce::OptionalScopedPointer<QAHandler>(qaHandler, false))
{
}

GetAndRunQAJsonOnJuceMessageThread::~GetAndRunQAJsonOnJuceMessageThread()
{
}

void GetAndRunQAJsonOnJuceMessageThread::messageCallback()
{
    mQAHandler->getAndRunQAJson();
}

#6

AFAIK even the following code is possible (with Foo as a CallbackMessage).

(new Foo())->post();

#7

Ok, cool, I'll do something of this sort then.