I was wondering about locking a ValueTree in some good way. I have a situation where one value tree can be modified by 3 threads (it’s an audio plugin), so it’s the MAIN gui thread, the audio thread and the MIDI INPUT thread (from a midi device). I try to move everything to the value tree and it’s properties. I was wondering if it will be enough to lock the setProperty and getProperty methods, and how do i deal with the listener methods (valuepropertychanged), are those methods called in a async or sync way, should i add a lock to them too (this is where i react to changes so a lot of work is done in that callback).
Ooh, they’re not really designed for that kind of multi-threadedness. The tricky bit is that the callbacks are all synchronous, so changing a value in your audio thread could end up calling all kinds of other code. Nasty!
so what’s the best way to do this. Maybe i’ll explain how i designed this. I was thinking of adding a readLock for getProperty and writeLock for setProperty, the locks work on the modulatorCriticalSection.
Using any kind of lock in your audio thread is probably a bad idea. Personally, I’d suggest making your ValueTree accessible only by the UI thread, and using some other mechanism to communicate with the other threads.
- when a thread wants to change the value of the modulator, it sets an Atomic value and triggers an async update
- when the handleAsyncUpdate happens, the modulator picks up the change and acts accordingly
would that work ?
Post changes to values using a thread-safe queue and process the queue from the thread that owns the ValueTree:
When a value changes, in your Listener callback, notify each interested thread by posting a call to it’s thread queue with a copy of the value.
I had a incomming midi queue that was an Array that was CriticalSection locked, but jules just said to not do any locking.
One way or the other any change from any thread will cause an update on the audio thread, and any change from the audio thread will cause locking when using your ThreadQueue.
It makes me wonder, how much locking in the audio thread is too much, is there any way to deal without locking at all.
Right, but the difference is that the lock is held for constant time regardless of the size of the queue:
// get the list lock (); head = m_head; m_head = 0; m_tail = 0; if (head) reset(); unlock ();
The lock is held for a very short time.
It is possible to get rid of a lot of locking, especially if you have access to lock-free data structures. But a small amount of locking is okay. Also remember that operator new/delete, malloc(), and free() implementations usually take a global critical section.
Some locking is okay, but when you hold a lock in time proportional to the amount of data being processed that’s when you can start to run into trouble. This goes for any thread, if you lock for a tiny bit in the audio thread but then take the same lock for a long time elsewhere, you will block the audio thread for a long time.
Note that in the thread queue implementation, the critical section is always held for O(1).
well i definetly tried to use no new malloc free delete, that’s been stressed alot on the JUCE forums.