Data races in the initialization code

When executing under a thread sanitizer on a Mac OS, I am getting a report of two data races in the initialization code. Essentially a new thread is launched before the original thread finishes initializing the state used by the newly launched thread.

Since attaching files is not allowed for new users - including these two reports below.
———————-
FMOD Bug Report: Data Race in Manager::init() During AsyncManager Thread Startup
FMOD Version: 2.03.11 (build 158528)
Platform: macOS ARM64
Detection Tool: ThreadSanitizer (TSAN)

Summary
A data race occurs during FMOD::Studio::System::initialize() between the main initialization thread and the AsyncManager thread that is spawned during initialization.

Description
When calling FMOD::Studio::System::initialize(), the RuntimeAPI::Manager::init() function creates an AsyncManager thread. This async thread starts executing asyncThreadLoop() and reads from Manager state while the main thread is still writing to it.

Stack Trace (FMOD code only)
WARNING: ThreadSanitizer: data race

Write of size 4 at 0x000132b48a2c by thread T25:
#0 FMOD::RuntimeAPI::Manager::init(int, unsigned int, unsigned int, void*)
#1 FMOD::Studio::System::initialize(int, unsigned int, unsigned int, void*)

Previous read of size 4 at 0x000132b48a2c by thread T42:
#0 FMOD::AsyncManager::asyncThreadLoop()
#1 FMOD::AsyncManager::asyncThreadFunc(void*)
#2 FMOD::thread::callback(void*)
#3 FMOD_OS_Thread_Callback(void*)

Location is heap block of size 3336 at 0x000132b48a00 allocated by thread T25:
#0 FMOD_OS_Memory_Alloc
#1 FMOD::Memory_DefaultMalloc(unsigned int, unsigned int, char const*)
#2 FMOD::MemPool::alloc(int, char const*, int, unsigned int, bool, bool)
#3 FMOD::RuntimeAPI::Manager::create(FMOD::RuntimeAPI::Manager**)
#4 FMOD::Studio::System::create(FMOD::Studio::System**, unsigned int)

Thread T42 created by thread T25 at:
#0 FMOD_OS_Thread_Create
#1 FMOD::thread::initThread(…)
#2 FMOD::AsyncManager::init(FMOD::RuntimeAPI::Manager*, bool, float)
#3 FMOD::RuntimeAPI::Manager::init(int, unsigned int, unsigned int, void*)
#4 FMOD::Studio::System::initialize(int, unsigned int, unsigned int, void*)

Analysis
The race occurs because:

Manager::init() calls AsyncManager::init() which spawns a worker thread (T42)
T42 immediately begins executing asyncThreadLoop() and reads Manager state
Manager::init() continues writing to state at offset +0x2C after spawning T42
No synchronization ensures T42 waits for Manager::init() to complete
Impact
Potential corruption of FMOD internal state
Non-deterministic behavior during initialization
Possible audio glitches or crashes under certain timing conditions
Suggested Fix
Add synchronization to ensure the AsyncManager thread waits for Manager::init() to complete before accessing Manager state, or defer thread startup until after initialization completes.
———————-
FMOD Bug Report: Data Race in CoreAudio Output Between Mixer and Feeder Threads

FMOD Version: 2.03.11
Platform: macOS (arm64)
Output Type: CoreAudio

Summary:
ThreadSanitizer detects a data race between the mixer thread and CoreAudio feeder thread accessing shared state in OutputRingBuffer. Both threads are created during FMOD::Output::start().

Race Details:

Read by mixer thread in FMOD::OutputCoreAudio::mixerThreadCallback()
Write by feeder thread in FMOD::OutputRingBuffer::read() via FMOD::OutputCoreAudio::feederThreadCallback()
Thread T39 (Mixer Thread) - Read:

#0 FMOD::OutputCoreAudio::mixerThreadCallback(void*)
#1 FMOD::thread::callback(void*)
#2 FMOD_OS_Thread_Callback(void*)

Thread T40 (CoreAudio Feeder Thread) - Write:

#0 FMOD::OutputRingBuffer::read(char*, int, bool)
#1 FMOD::OutputCoreAudio::feederThreadCallback(void*, unsigned int*, AudioTimeStamp const*, unsigned int, unsigned int, AudioBufferList*)

Thread T39 Creation:

#0 FMOD_OS_Thread_Create
#1 FMOD::thread::initThread(…)
#2 FMOD::OutputCoreAudio::startCallback(FMOD_OUTPUT_STATE*)
#3 FMOD::Output::start()
#4 FMOD::SystemI::init(int, unsigned int, void*)
#5 FMOD::System::init(int, unsigned int, void*)
#6 FMOD::RuntimeAPI::Manager::init(int, unsigned int, unsigned int, void*)
#7 FMOD::Studio::System::initialize(int, unsigned int, unsigned int, void*)

Thread T40 Creation:

#0 HALB_IOThread::DispatchPThread(void* ()(void), void*) [CoreAudio]
#1 FMOD::Output::start()
#2 FMOD::SystemI::init(int, unsigned int, void*)
#3 FMOD::System::init(int, unsigned int, void*)
#4 FMOD::RuntimeAPI::Manager::init(int, unsigned int, unsigned int, void*)
#5 FMOD::Studio::System::initialize(int, unsigned int, unsigned int, void*)

Memory Allocation (race location):

#0 FMOD_OS_Memory_Alloc
#1 FMOD::Memory_DefaultMalloc(unsigned int, unsigned int, char const*)
#2 FMOD::MemPool::alloc(…)
#3 FMOD::MemPool::calloc(…)
#4 FMOD::PluginFactory::createOutput(FMOD::FMOD_OUTPUT_DESCRIPTION_EX*, FMOD::Output**)
#5 FMOD::SystemI::setOutputInternal(FMOD_OUTPUTTYPE, int)

Analysis:
Both the mixer thread and CoreAudio feeder thread are spawned during FMOD::Output::start() and appear to race on shared OutputRingBuffer state before proper synchronization is established.