runDispatchLoopUntil(1) sometimes takes many seconds to complete


#1

Hi, here is a very short test app:

#include "../JuceLibraryCode/JuceHeader.h"

class App :    public JUCEApplication, public AsyncUpdater {
public:
    App() {}
    const String getApplicationName() { return "test_juce"; }
    const String getApplicationVersion() { return "1.0"; }
    void initialise(const String &) {
        triggerAsyncUpdate();
    }
    void handleAsyncUpdate() {
        int n = 0;
        while (!MessageManager::getInstance()->hasStopMessageBeenSent()) {
            double t0 = Time::getMillisecondCounterHiRes();
            MessageManager::getInstance()->runDispatchLoopUntil(1);
            double t1 = Time::getMillisecondCounterHiRes();

            if (t1 - t0 > 50) { DBG("WTF, dispatch loop took: " << t1-t0 << " ms"); }
            if ((++n)%1000 == 0) { DBG(n/1000); }
        }
    }
    void shutdown() {}
};
START_JUCE_APPLICATION(App)

And here is the output I am getting when I run it on my mac:

JUCE v5.1.1
WTF, dispatch loop took: 6009.07 ms
1
2
3
4
5
6
7
8
WTF, dispatch loop took: 10001.5 ms
WTF, dispatch loop took: 3994.49 ms
WTF, dispatch loop took: 1148.99 ms
WTF, dispatch loop took: 5899.7 ms
WTF, dispatch loop took: 20002.8 ms

So I wonder what is going on with the message loop. It is the call to ‘NSApp nextEventMatchingMask’ which takes all that time. Even if I set the ‘untilDate:’ argument to [NSDate distantPast]’ instead of ‘untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.001]’ , I still end up with calls to nextEventMatchingMask that take 20 seconds to complete. For some reason, clicking on the application icon seems to release whatever is clogging up the event queue.


#2

My guess would be that it can only exit that loop when an event actually gets dispatched, and in a tiny app like this there just aren’t any events happening until you click the icon. Add something like a Timer running every few ms and it’ll probably do what you expected.


#3

It turns out you’re correct \o/

Thanks a lot Jules, I though I had already tested something along that line before making that reduced test case, but I was wrong. A simple timer set to tic every second solves that issue !


#4

Mmmm no, it is not working. It seems to have worked when I first tested it , but now it is not working at all, even with a 1ms Timer.


#5

Then I don’t know…

However, I would recommend never using runDispatchLoop at all - it’s not even possible on platforms like Android, and can lead to some nasty situations.


Calling Component::repaint() in a process thread
#6

Ok thanks, I should have done that a lot time ago, indeed.