MessageManagerLock, timer and deadlock


#1

Hi,

we are currently implementing some application with a hiResTimer, and because GUI is controlled from it, we use MessageManagerLock as reported in the documentation.
The StopTimer() is called from shutdown function.

Still, when closing the application, we enter a deadlock.

We surely do something wrong, can you please help?

Thank you
Nathaniel


#2

The problem is that when calling stopTimer(), the HiResolutionTimer will yield to the timer one last time - and your code will try to lock the MessageManager. However, if you look at the documentation of JUCEApplication::shutdown, it states that the MessageManager will no longer process any more messages. However, the shutdown method itself is called from the MessageManager (i.e. the MessageManager will be locked). Therefore calling stopTimer in the shutdown method is already too late.

You have two options:

  1. change your code so that you call stopTimer at the point where the quit event is generated. The message manager will still be running at this point and all messages will still be processed.

or

  1. add a flag to your JUCEApplication to no longer lock the MessageManager if shutdown has been called:

    bool isShuttingDown;

    void hiResTimerCallback() override
    {
    if (isShuttingDown) return;

     const MessageManagerLock mmLock;
    
    // do some stuff here
    

    }

    void shutdown() override { isShuttingDown = true; stopTimer(); }


#3

If you’re going to lock the message manager, then there’s really no point in using a high-res timer!

Acquiring the MessageManagerLock could take any amount of time, so that’s going to screw up the timing of anything that happens in your timer thread after that point, and defeats the whole purpose of the high-res timer class!

If you’re doing something that’s time-critical then you should use the high-res timer to do all the threaded work, and then make it asynchronously post a message or AsyncUpdater or Timer or something to take care of any GUI tasks that come out of it later. That’d also avoid these deadlocks.

And in general, avoid using the MessageManagerLock at all, unless there’s really no other solution, as it’s way too easy to cause horrible deadlocks with it… Even Fabian’s suggestion above will occasionally go wrong and deadlock! And always use the MessageManagerLock constructor that takes a Thread pointer so it can fail if the thread is trying to stop.