Hi everybody,
I have been toying around with a class that tries to prevent stupid calls on the audio thread (eg. String creations or HeapBlock allocations) and I think this might be a good addition to JUCE.
In production code, you most likely won’t need it, however I am running a scripting engine in the audio thread and people are starting to do stupid things there, so this prevents the scripting code from doing allocations, etc.
I also have tracked down a few allocations that are not super critical, but might cause issues under certain conditions (ScopedReadLock::tryEnter, I am looking at you).
How to use it
1. Enable the JUCE_ENABLE_AUDIO_GUARD
macro
If this is disabled, all calls to AudioThreadGuards get redirected to a dummy object so the compiler will most likely throw it away. This results in effectively no overhead if not wanted.
2. Subclass AudioThreadGuard::Instance
You can define a custom logic for testing / logging with this class
3. Create a AudioThreadGuard in your processBlock method
void processBlock(AudioSampleBuffer& b, MidiBuffer& m)
{
AudioThreadGuard guard(pointerToMyGuard);
// From now on all calls to illegal methods will fire a warning until guard goes out of scope.
};
4. Add the warning code to illegal operations
In every method that should not be called from the audio thread, add this line:
WARN_IF_AUDIO_THREAD(condition, operationId);
The condition
argument can be used to prevent false positives as most operations do no harm under certain circumstances (eg. setting an array element without reallocating).
The operationId
is an integer that can be used to identify the culprit if debug symbols are not present (otherwise calling SystemStats::getStackBacktrace()
in your warning code is the best option during development).
For example, the destructor of the HeapBlock will look like this:
` ~HeapBlock()
{
WARN_IF_AUDIO_THREAD(data != nullptr, IllegalAudioThreadOps::HeapBlockDeallocation);
std::free (data);
}
@jules is this a sensible addition? I know this would mean adding the warnings at a lot of places in the JUCE codebase. The WARN_IF_AUDIO_THREAD
macro will get ifdefed away if not used but it would add some verbosity to these methods (however I don’t think that’s such a bad thing since it explicitly states that the method has nothing to do in an audio thread).
How it works internally
When an AudioThreadGuard is created, it will fetch the current thread id and add it to the list of audio thread ids (this should make it work in multithreaded audio applications). Whenever you call WARN_IF_AUDIO_THREAD
, it will check if the current thread id is in the list of audio threads and fire the warning after passing a few tests.
There are a few helper classes that suspend the guard (useful when printing debugging strings), or temporarily set another Instance.
Below you can find the code (same license as all juce_core
files).
I tried to follow the JUCE coding style as much as possible making a possible merge into the official codebase more straight-forward - although I am sure you nit-picky guys find something
juce_AudioThreadGuard.cpp (3.4 KB)
juce_AudioThreadGuard.h (6.4 KB)