Locking and the fantastic world of multithreading

The components in Juce can be put together, with a thread queue (such as the one in DSP Filters) thrown in, to achieve lock-free updating. This solution works as follows:

  1. Master object holds the authoritative ValueTree and provides a multi-threading API

  2. Master object API includes a Listener abstract interface for receiving change notifications

  3. When another thread wants to get a read-only copy of the ValueTree, it calls a function of the Master object. This function takes the thread, its associated thread queue, and a pointer to a Listener derived object. The function returns a reference to a duplicate ValueTree which is owned by the associated thread.

  4. When the application desires to change a value, it calls a function on the Master object with the key / new value pair. The implementation queues an asynchronous change function call which executes on the thread that owns the Master object. The change function stores the new value in the value tree and then queues an asynchronous change function call for all threads which have registered to receive read-only copies of the ValueTree. The read-only copies are changed on the thread that owns the copy.

Using this system, a GUI control changes its appearance only in response to thread queue / listener notifications. So when a user manipulates a slider, for example, the change makes a round trip through the Master object and back to the message thread before the screen updates.

The consequence of this technique is that the read-only copies will usually lag a little bit behind time-wise from the actual value. In practice, this is not a problem.

1 Like