diff --git a/assignment-client/src/audio/AudioMixerSlavePool.cpp b/assignment-client/src/audio/AudioMixerSlavePool.cpp index 6403ebc4d8..9bc28ec24a 100644 --- a/assignment-client/src/audio/AudioMixerSlavePool.cpp +++ b/assignment-client/src/audio/AudioMixerSlavePool.cpp @@ -15,8 +15,8 @@ #include "AudioMixerSlavePool.h" void AudioMixerSlaveThread::run() { - while (!_stop) { - wait(); // for the audio pool to notify + while (true) { + wait(); // iterate over all available nodes SharedNodePointer node; @@ -24,7 +24,11 @@ void AudioMixerSlaveThread::run() { mix(node); } - notify(); // the audio pool we are done + bool stopping = _stop; + notify(stopping); + if (stopping) { + return; + } } } @@ -40,11 +44,14 @@ void AudioMixerSlaveThread::wait() { configure(_pool._begin, _pool._end, _pool._frame); } -void AudioMixerSlaveThread::notify() { +void AudioMixerSlaveThread::notify(bool stopping) { { Lock lock(_pool._mutex); assert(_pool._numFinished < _pool._numThreads); ++_pool._numFinished; + if (stopping) { + ++_pool._numStopped; + } } _pool._poolCondition.notify_one(); } @@ -139,18 +146,28 @@ void AudioMixerSlavePool::resize(int numThreads) { } else if (numThreads < _numThreads) { auto extraBegin = _slaves.begin() + numThreads; - // stop extra slaves... + // mark slaves to stop... auto slave = extraBegin; while (slave != _slaves.end()) { - (*slave)->stop(); + (*slave)->_stop = true; ++slave; } - // ...cycle slaves with empty queue... - _numStarted = _numFinished = 0; - _slaveCondition.notify_all(); + // ...cycle them until they do stop... + { + Lock lock(_mutex); + _numStopped = 0; + while (_numStopped != (_numThreads - numThreads)) { + _numStarted = _numFinished = _numStopped; + _slaveCondition.notify_all(); + _poolCondition.wait(lock, [&] { + assert(_numFinished <= _numThreads); + return _numFinished == _numThreads; + }); + } + } - // ...wait for them to finish... + // ...wait for threads to finish... slave = extraBegin; while (slave != _slaves.end()) { QThread* thread = reinterpret_cast(slave->get()); @@ -159,7 +176,7 @@ void AudioMixerSlavePool::resize(int numThreads) { ++slave; } - // ...and delete them + // ...and erase them _slaves.erase(extraBegin, _slaves.end()); } diff --git a/assignment-client/src/audio/AudioMixerSlavePool.h b/assignment-client/src/audio/AudioMixerSlavePool.h index 91f60f5094..33b9062b99 100644 --- a/assignment-client/src/audio/AudioMixerSlavePool.h +++ b/assignment-client/src/audio/AudioMixerSlavePool.h @@ -34,20 +34,16 @@ public: AudioMixerSlaveThread(AudioMixerSlavePool& pool) : _pool(pool) {} void run() override final; - void stop() { _stop = true; } private: friend class AudioMixerSlavePool; void wait(); - void notify(); + void notify(bool stopping); bool try_pop(SharedNodePointer& node); - // frame state AudioMixerSlavePool& _pool; - - // synchronization state - std::atomic _stop; + bool _stop; }; // Slave pool for audio mixers @@ -79,7 +75,7 @@ private: std::vector> _slaves; friend void AudioMixerSlaveThread::wait(); - friend void AudioMixerSlaveThread::notify(); + friend void AudioMixerSlaveThread::notify(bool stopping); friend bool AudioMixerSlaveThread::try_pop(SharedNodePointer& node); // synchronization state @@ -89,6 +85,7 @@ private: int _numThreads { 0 }; int _numStarted { 0 }; // guarded by _mutex int _numFinished { 0 }; // guarded by _mutex + int _numStopped { 0 }; // guarded by _mutex // frame state Queue _queue;