# Is MessageManager::callAsync() real-time safe?

**URL:** <https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031>\
**Category:** Audio Plugins\
**Created:** [May 6, 2025, 11:20pm UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031 "2025-05-06T23:20:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![fuo](https://avatars.discourse-cdn.com/v4/letter/f/ba8739/32.png) [@fuo](https://forum.juce.com/u/fuo)\
**Post date:** [May 6, 2025, 11:20pm UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/1 "2025-05-06T23:20:40Z")

</div>

So, I have been using `callAsync` in most situations where something has to be done on the message thread instead of the audio thread, eg when `parameterChanged` is called from the audio thread.

I have had issue so far and I find this method much simpler and practical (although it does not coalesce) than setting an atomic bool and polling it with a timer, or using `AsyncUpdater` which is not real-time safe anyway, it appears).

It is safe (enough) for real-time use though?  
Should I replace it with real-time safe variants of `AsyncUpdater` as proposed by [dave96](https://forum.juce.com/u/dave96) in this [2020 speech](https://www.youtube.com/watch?v=JCNyd1KGjMk)?

And what about `Timer::CallAfterDelay`?

---

<div class="post-metadata">

**Author:** ![eyalamir](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/eyalamir/32/2978_2.png) [@eyalamir](https://forum.juce.com/u/eyalamir)\
**Post date:** [May 7, 2025, 5:27am UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/2 "2025-05-07T05:27:23Z")

</div>

The only real time safe way to trigger a function from the audio thread is to use a timer and poll on an atomic or a parameter.

For more ergonomic use, most of my projects use something like this:

```auto
struct ParamListener final : juce::Timer
{
    using Callback = std::function<void()>;
    using Param = juce::AudioProcessorParameter&;

    ParamListener(const Param& paramToUse,
                  const Callback& cbToUse,
                  bool trigger = true)
        : param(paramToUse)
        , cb(cbToUse)
    {
        startTimerHz(60);

        lastValue = param.getValue();

        if (trigger)
            cb();
    }

    ~ParamListener() override { stopTimer(); }

    void timerCallback() override
    {
        auto current = param.getValue();

        if (lastValue != current)
        {
            lastValue = current;
            cb();
        }
    }

    const Param& param;
    Callback cb;
    float lastValue = 0.f;
};

```

This is used like this:

```auto

struct MyWidget : juce::Component
{
    MyWidget(juce::AudioParameterFloat& paramToUse)
        : param(paramToUse)
    {
    }

    juce::AudioParameterFloat& param;
    ParamListener listener {param, [&] { repaint(); }};
};

```

This is also much more scalable than a `callAsync` because it lets you run multiple actions based on the same parameter which I think would work better for UIs, and also it lets you completely destroy the listener when the editor is closed and do nothing in that case.

(In my real world code there are a few other micro optimizations like sharing the timer for all listeners but this is the pattern generally).

---

<div class="post-metadata">

**Author:** ![Rincewind](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/rincewind/32/10645_2.png) [@Rincewind](https://forum.juce.com/u/Rincewind)\
**Post date:** [May 7, 2025, 6:56am UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/3 "2025-05-07T06:56:48Z")

</div>

Beauty of this is, you can adjust the poll-speed also dynamically.  
For example if you notice a change, you can start polling twice as fast for smoother callbacks in the UI.

---

<div class="post-metadata">

**Author:** ![Nitsuj70](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/nitsuj70/32/12754_2.png) [@Nitsuj70](https://forum.juce.com/u/Nitsuj70)\
**Post date:** [May 7, 2025, 2:14pm UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/4 "2025-05-07T14:14:43Z")

</div>

The main thing to bear in mind is that anything that interacts with or sends a message to the message queue isn’t realtime safe. It’s not just than locks might be involved somewhere down the line, it’s that there could be an inversion of priority which would really screw things up.

One way of handling is the method mentioned else where here. Use a timer and poll. However, you might want to specifically adapt this somewhat if you’ve got hundreds or thousands of parameters.

---

<div class="post-metadata">

**Author:** ![eyalamir](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/eyalamir/32/2978_2.png) [@eyalamir](https://forum.juce.com/u/eyalamir)\
**Post date:** [May 7, 2025, 5:21pm UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/5 "2025-05-07T17:21:06Z")

</div>

> [@Nitsuj70](#):
>
> However, you might want to specifically adapt this somewhat if you’ve got hundreds or thousands of parameters.

In my tests even 10,000 such timers checking an atomic at 60fps is not a performance cost - especially if you destroy them when the editor or parts of the editor that aren’t shown are closed. I’ve tried running many such timers in production code and it’s never caused an issue.

Having that said, in my ‘real’ code I actually don’t have 10,000 timer instances and instead I have one static timer that ‘listeners’ subscribe to with a broadcaster/listener mechanism.

The biggest advantage of that other a minor performance optimization is that you get all timer callbacks in the same rate/order and it’s easier to keep track of side effects happening as a result of a single parameter change.

---

<div class="post-metadata">

**Author:** ![fuo](https://avatars.discourse-cdn.com/v4/letter/f/ba8739/32.png) [@fuo](https://forum.juce.com/u/fuo)\
**Post date:** [May 9, 2025, 10:58pm UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/6 "2025-05-09T22:58:57Z")

</div>

I like the approach of getting rid of the listener altogether, thanks for sharing this!

I wonder if `callAsync` is better of worse than `AsyncUpdater` in terms of RT safety, as `AsyncUpdater` is used in a bunch of plugins on the field: if there was notable problems associated with it then surely it would have been replaced and would not be the default for parameter attachment in Juce anymore (or would it?).

---

<div class="post-metadata">

**Author:** ![zsliu98](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/zsliu98/32/22502_2.png) [@zsliu98](https://forum.juce.com/u/zsliu98)\
**Post date:** [May 10, 2025, 12:21am UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/7 "2025-05-10T00:21:17Z")

</div>

I have used parameter attachments in plugins without issues. The `AsyncUpdater` will be called from the audio thread if:

- `parameterChanged` is called from audio thread (e.g., via automation)
- and the `AsyncUpdater` is alive (i.e., the editor is open)

I would guess that this scenario may be not that common? Anyway, I will definitely avoid parameter attachments in current and future plugins for safety. My current idea is to set a bool atomic for several sliders together and use `parameterChanged` to update the atomic. Then I can check the atomic in a timer.

---

<div class="post-metadata">

**Author:** ![eyalamir](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/eyalamir/32/2978_2.png) [@eyalamir](https://forum.juce.com/u/eyalamir)\
**Post date:** [May 10, 2025, 6:18am UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/8 "2025-05-10T06:18:09Z")

</div>

> [@fuo](#):
>
> I wonder if `callAsync` is better of worse than `AsyncUpdater` in terms of RT safety, as `AsyncUpdater` is used in a bunch of plugins on the field: if there was notable problems associated with it then surely it would have been replaced and would not be the default for parameter attachment in Juce anymore (or would it?).

`AsyncUpdater` and `callAsync` are totally fine to use, just not for the audio thread.

And yes, having those as a part of JUCE’s `ParameterAttachment` is a bug in JUCE. I would expect plugins that use those all over the place to run into severe performance problems if a lot of parameters are automated and the editor is open - fortunately this isn’t the case most of the time in most user sessions, but under the right user situation I expect you would be able to observe issues with that solution.

---

<div class="post-metadata">

**Author:** ![Nitsuj70](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/nitsuj70/32/12754_2.png) [@Nitsuj70](https://forum.juce.com/u/Nitsuj70)\
**Post date:** [May 10, 2025, 10:44am UTC](https://forum.juce.com/t/is-messagemanager-callasync-real-time-safe/66031/9 "2025-05-10T10:44:49Z")

</div>

The ParameterAttachment async call is going to be very dependent on the state of the message queue and whatever else is going on. In theory it should be just posting a message which most of the time will be ok. It’s just that you don’t have RT guarantees.
