MessageManager::callFunctionOnMessageThread failure on OS-X?


#1

In the other forum thread about the newly added static void callAsync (std::function<void(void)>) method in MessageManager, I posted an alternative way to do it and speculated it should work OK on OS-X too, because it does seem to do so on Windows. However, now that I tested it on OS-X, it does not work. There happens a hang when Juce GUI objects are manipulated. I suspected that perhaps my wrapper function causes something bad to happen. But callFunctionOnMessageThread  does not seem to be working on OS-X when called directly either, similar to :

void* label_cb_func(void* ctx)

{

  Label* lab=(Label*)ctx;

  lab->setText("callback",dontSendNotification);

  return nullptr;

}

 

void mywindow::foo()

{

  std::async(std::launch::async,[this]()

  {

    MessageManager::getInstance()->callFunctionOnMessageThread(label_cb_func,this->m_label);

  });

}

 

(std::async is a way to run a callable in another thread)

 

The code I have tested with is not exactly like above. The mywindow:foo() is actually a method that opens up a Juce Popupmenu and async stuff is launched when choosing a menu item. I wonder if the menu still being open while the async/MessageManager stuff is happening causes some havoc...?


#2

Please read the disclaimer about callFunctionOnMessageThread - it's inherently very dangerous because it blocks, and you should avoid it where possible. In the code above, it doesn't even look like it's necessary.


#3

Well, I would be willing to live with the blocking behavior...(As long as it wouldn't permanently freeze the software on OS-X!) 

And using callFunctionOnMessageThread would be necessary in the above code example because calling Label::setText from another thread (from inside the lambda given for std::async(*)) would be a complete disaster, right? (I've assumed Juce works like other GUI toolkits where GUI objects shall not be manipulated from other threads but only from the GUI thread...)

(*) In the real code, there would of course be a time consuming operation in the thread lambda before changing the label text.


#4

It will definitely cause deadlocks if you use it in a thread and try to shutdown while it's being called. Honestly, it's a horrible method to use safely, I never use it myself.

The best way to do some UI stuff from a thread is to do it in a non-blocking way with async function calls. Or as a last-resort, use a MessageManagerLock in its safe mode where you give it a thread to check and allow it to fail to take the lock, and then abort the operation somehow.


#5

OK, I will investigate other ways to do it, or just use your recently added static void callAsync (std::function<void(void)>) in the MessageManager. The void(void) function signature is slightly limiting but will probably work for 99% of use cases...


#6

void(void) should work for 100% of cases, because a lambda can take any parameters you need implicitly. And being async, it's impossible to return a value anyway.


#7

OK, it works for 100% of cases but not always with the most convenience... ;-)

Regarding async return values, there's actually std::future<T>...