AsyncUpdater vs MessageManager::callAsync

gui

#1

I know Java but am new to C++ and am familiarizing myself with the language and the Juce API. I have a background thread (a HighResolutionTimer) from which I make UI updates via a periodically invoked callback.

I have working code using both AsyncUpdater (which my main component class extends) and MessageManager::callAsync.

Here are two callback implementations, one with AsyncUpdater the other with callAsync:

    // callback using AsyncUpdater
    void hiResTimerCallback() override
    {
        // a Component that extends AsyncUpdater and
        // kicks off component state changes at each tick of the timer
        asyncUpdaterComponent->triggerAsyncUpdate();
    }

    // alt callback impl using callAsync
    void hiResTimerCallback() override
    {
        Component* label = mainComponent->findChildWithID("headerBar")->findChildWithID("testLabel");
        MessageManager::callAsync(
          [=] () {
              if (label->isVisible()) {
                  label->setVisible(false);
              } else {
                  label->setVisible(true);
              }
          }
        );
    }

The net effect on the UI is the same for both impls but is there a preference between one over the other? Is capturing local variables (a component in this case) by value rather than reference okay for callAsync? Tangentially related, is navigating a component hierarchy using findChildWithID commonly used to “drill down” into a component and access children components?

Thanks,
Ben


#2

In this case you are capturing only a pointer to the label, so it doesn’t matter. (You must not capture a reference here anyway because the local variable has went out of scope by the time the lambda will be executed.)

Are you sure need to use the HighResolutionTimer anyway? Have you checked the normal Timer doesn’t work and HighResolutionTimer does something better?


#3

That’s not strictly true. You should never capture raw pointers or references in async code because the Component may have been deleted by the time the callback happens.
The correct way to do this is with a weak reference, in this case, a `Component::SafePointer (C++14 example):

MessageManager::callAsync (
      [auto sp = Component::SafePointer<Component> (this)]
      {
          if (sp == nullptr)
              return;

          // Safe to use sp here
      }
    );

#4

Obviously I was assuming in my original reply that the code can assume the pointed to object itself is not deleted before the callback. (Which isn’t always easy to guarantee and something like your solution should be used instead.)


#5

Thanks for the responses. Sounds like AsyncUpdater is the less error prone choice in this context.

I’m using the HighResolutionTimer for a clock signal, which seems more appropriate than a Timer running on the main message thread. I’m not entirely sure though TBH; I’ve been working with Juce (and C++ in general) for about 2 weeks now.


#6

There’s really no point in using a high-resolution timer if the only thing is does is to post a message to the message thread! That class is designed for high-accuracy tasks where it’s important that it doesn’t get blocked. If all you need to do is update some GUI stuff, just use a normal Timer, whose callback is on the message thread.


#7

@jules, I’m sending MIDI data from the callback, in addition to updating GUI elements per tick of the timer.
Is the Timer okay for that? I didn’t get the impression that using Timer would be good if I need to send MIDI.


#8

oh yeah, for midi you’d want a high-res timer. Stick to the AsyncUpdater then!


#9

Super. Thanks!