1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-30 19:30:17 +00:00

Eliminates potential race conditions on validity of delegate_.

This commit is contained in:
Thomas Harte 2020-02-18 20:33:31 -05:00
parent f43c31da1f
commit a5e1765ce4
2 changed files with 12 additions and 6 deletions

View File

@ -124,7 +124,8 @@ template <typename SampleSource> class LowpassSpeaker: public Speaker {
at construction, filtering it and passing it on to the speaker's delegate if there is one. at construction, filtering it and passing it on to the speaker's delegate if there is one.
*/ */
void run_for(const Cycles cycles) { void run_for(const Cycles cycles) {
if(!delegate_) return; const auto delegate = delegate_.load();
if(!delegate) return;
std::size_t cycles_remaining = size_t(cycles.as_integral()); std::size_t cycles_remaining = size_t(cycles.as_integral());
if(!cycles_remaining) return; if(!cycles_remaining) return;
@ -138,7 +139,7 @@ template <typename SampleSource> class LowpassSpeaker: public Speaker {
} }
if(filter_parameters.parameters_are_dirty) update_filter_coefficients(filter_parameters); if(filter_parameters.parameters_are_dirty) update_filter_coefficients(filter_parameters);
if(filter_parameters.input_rate_changed) { if(filter_parameters.input_rate_changed) {
delegate_->speaker_did_change_input_clock(this); delegate->speaker_did_change_input_clock(this);
} }
switch(conversion_) { switch(conversion_) {

View File

@ -9,6 +9,7 @@
#ifndef Speaker_hpp #ifndef Speaker_hpp
#define Speaker_hpp #define Speaker_hpp
#include <atomic>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
@ -82,12 +83,16 @@ class Speaker {
protected: protected:
void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer, bool is_stereo) { void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer, bool is_stereo) {
// Test the delegate for existence again, as it may have changed.
const auto delegate = delegate_.load();
if(!delegate) return;
++completed_sample_sets_; ++completed_sample_sets_;
// Hope for the fast path first: producer and consumer agree about // Hope for the fast path first: producer and consumer agree about
// number of channels. // number of channels.
if(is_stereo == stereo_output_) { if(is_stereo == stereo_output_) {
delegate_->speaker_did_complete_samples(this, buffer); delegate->speaker_did_complete_samples(this, buffer);
return; return;
} }
@ -106,9 +111,9 @@ class Speaker {
mix_buffer_[(c << 1) + 0] = mix_buffer_[(c << 1) + 1] = buffer[c]; mix_buffer_[(c << 1) + 0] = mix_buffer_[(c << 1) + 1] = buffer[c];
} }
} }
delegate_->speaker_did_complete_samples(this, mix_buffer_); delegate->speaker_did_complete_samples(this, mix_buffer_);
} }
Delegate *delegate_ = nullptr; std::atomic<Delegate *> delegate_ = nullptr;
private: private:
void compute_output_rate() { void compute_output_rate() {
@ -121,7 +126,7 @@ class Speaker {
float input_rate_multiplier_ = 1.0f; float input_rate_multiplier_ = 1.0f;
float output_cycles_per_second_ = 1.0f; float output_cycles_per_second_ = 1.0f;
int output_buffer_size_ = 1; int output_buffer_size_ = 1;
bool stereo_output_ = false; std::atomic<bool> stereo_output_ = false;
std::vector<int16_t> mix_buffer_; std::vector<int16_t> mix_buffer_;
}; };