I’m now wondering if there’s a race condition intrinsic to the thread model as it stands now.
My threaded code has actually been working perfectly well but I believe my worrying about these minor details before they happen will make my final code reliable.
Correct me if I’m wrong, but if you wait() and you have a lock, you keep that lock…? (So you probably shouldn’t do that.)
Given this, I don’t see a thread-safe way to wait until a flag turns true.
My best try would be:
- Take the lock.
- Check if the flag is true.
- Drop the lock.
- If the flag was false, wait(-1) until I get notified, then go to 1.
and in the other thread:
- Take the lock.
- Set the flag to true.
- Drop the lock.
- Call notify().
This almost works… unfortunately, there’s a race condition between 3 and 4, where occasionally notify() might get called from another thread before I wait() - resulting in loss-of-liveness for that thread.
Java, for example, handles this by automatically relieving you of your locks as you sleep or wait.
Such a change is clearly impossible in JUCE as you’d potentially break a lot of clients, and in subtle ways to boot; but is there some way to use any of the primitives to get a truly thread-safe “wait for flag” code fragment? I’m looking at the “threads” subdirectory but nothing seems to do it.
(In case you’re thinking that “this would never happen” - if you run your code with a race condition enough, it will crop up! And in this application, the loop occurs during the production of digital audio, which means it will be run millions of times…)
The workaround is that your loop spins instead of waiting - you call wait(10), say, instead of wait(-1). For all sorts of reasons, however, it’s bad practice to spin your threads this way (for example, because it can result in disk thrashing because the thread’s memory space keeps getting brought back into real memory, not to mention potential hiccups from the occasional random 10ms delay thrown into your execution wall clock…)
My thinking on this is that there is no way to do it with what you have there - but that adding a single class to do just this, waiting for a locked condition flag, would fix a lot of possible cases neatly.