fix thread cleanup of audio pool

This commit is contained in:
Zach Pomerantz 2016-12-07 18:43:02 -05:00
parent d2ed3caf02
commit ce9346f524
2 changed files with 32 additions and 18 deletions

View file

@ -15,8 +15,8 @@
#include "AudioMixerSlavePool.h" #include "AudioMixerSlavePool.h"
void AudioMixerSlaveThread::run() { void AudioMixerSlaveThread::run() {
while (!_stop) { while (true) {
wait(); // for the audio pool to notify wait();
// iterate over all available nodes // iterate over all available nodes
SharedNodePointer node; SharedNodePointer node;
@ -24,7 +24,11 @@ void AudioMixerSlaveThread::run() {
mix(node); 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); configure(_pool._begin, _pool._end, _pool._frame);
} }
void AudioMixerSlaveThread::notify() { void AudioMixerSlaveThread::notify(bool stopping) {
{ {
Lock lock(_pool._mutex); Lock lock(_pool._mutex);
assert(_pool._numFinished < _pool._numThreads); assert(_pool._numFinished < _pool._numThreads);
++_pool._numFinished; ++_pool._numFinished;
if (stopping) {
++_pool._numStopped;
}
} }
_pool._poolCondition.notify_one(); _pool._poolCondition.notify_one();
} }
@ -139,18 +146,28 @@ void AudioMixerSlavePool::resize(int numThreads) {
} else if (numThreads < _numThreads) { } else if (numThreads < _numThreads) {
auto extraBegin = _slaves.begin() + numThreads; auto extraBegin = _slaves.begin() + numThreads;
// stop extra slaves... // mark slaves to stop...
auto slave = extraBegin; auto slave = extraBegin;
while (slave != _slaves.end()) { while (slave != _slaves.end()) {
(*slave)->stop(); (*slave)->_stop = true;
++slave; ++slave;
} }
// ...cycle slaves with empty queue... // ...cycle them until they do stop...
_numStarted = _numFinished = 0; {
Lock lock(_mutex);
_numStopped = 0;
while (_numStopped != (_numThreads - numThreads)) {
_numStarted = _numFinished = _numStopped;
_slaveCondition.notify_all(); _slaveCondition.notify_all();
_poolCondition.wait(lock, [&] {
assert(_numFinished <= _numThreads);
return _numFinished == _numThreads;
});
}
}
// ...wait for them to finish... // ...wait for threads to finish...
slave = extraBegin; slave = extraBegin;
while (slave != _slaves.end()) { while (slave != _slaves.end()) {
QThread* thread = reinterpret_cast<QThread*>(slave->get()); QThread* thread = reinterpret_cast<QThread*>(slave->get());
@ -159,7 +176,7 @@ void AudioMixerSlavePool::resize(int numThreads) {
++slave; ++slave;
} }
// ...and delete them // ...and erase them
_slaves.erase(extraBegin, _slaves.end()); _slaves.erase(extraBegin, _slaves.end());
} }

View file

@ -34,20 +34,16 @@ public:
AudioMixerSlaveThread(AudioMixerSlavePool& pool) : _pool(pool) {} AudioMixerSlaveThread(AudioMixerSlavePool& pool) : _pool(pool) {}
void run() override final; void run() override final;
void stop() { _stop = true; }
private: private:
friend class AudioMixerSlavePool; friend class AudioMixerSlavePool;
void wait(); void wait();
void notify(); void notify(bool stopping);
bool try_pop(SharedNodePointer& node); bool try_pop(SharedNodePointer& node);
// frame state
AudioMixerSlavePool& _pool; AudioMixerSlavePool& _pool;
bool _stop;
// synchronization state
std::atomic<bool> _stop;
}; };
// Slave pool for audio mixers // Slave pool for audio mixers
@ -79,7 +75,7 @@ private:
std::vector<std::unique_ptr<AudioMixerSlaveThread>> _slaves; std::vector<std::unique_ptr<AudioMixerSlaveThread>> _slaves;
friend void AudioMixerSlaveThread::wait(); friend void AudioMixerSlaveThread::wait();
friend void AudioMixerSlaveThread::notify(); friend void AudioMixerSlaveThread::notify(bool stopping);
friend bool AudioMixerSlaveThread::try_pop(SharedNodePointer& node); friend bool AudioMixerSlaveThread::try_pop(SharedNodePointer& node);
// synchronization state // synchronization state
@ -89,6 +85,7 @@ private:
int _numThreads { 0 }; int _numThreads { 0 };
int _numStarted { 0 }; // guarded by _mutex int _numStarted { 0 }; // guarded by _mutex
int _numFinished { 0 }; // guarded by _mutex int _numFinished { 0 }; // guarded by _mutex
int _numStopped { 0 }; // guarded by _mutex
// frame state // frame state
Queue _queue; Queue _queue;