Concurrent read writes parameters / GUI

Hi guys I've been watching this talk by Timur:

https://www.youtube.com/watch?v=boPEO2auJj4

 

First of all this explained alot for me, but also raised alot of questions. Right now I am using subclasses of AudioProcessorParameter to communicate between the GUI and the audio thread. But as told in the talk there seems to be a data race here since C++ 11? When I look at the implementation of the AudioProcessorParameter I dont see the atomic solution which is mentioned here. Is it safe to write to AudioProcessorParameters and read the values in the audio thread, or do I have to create my own atomic implementation of the parameter classes ?

 

Secondly if I didn't really understand what he meant with atomic widgets, but what would be the right way to say for example communicate a vector of data from the audio thread to the gui thread (for visualisation).

So your right, 

 

At the moment the AudioProcessorParameter class does not explcity handle atmoics/thread safety for you yet as far as I'm aware. 

 

But notce that AudioProcessorParameter::setValue(floar newValue) and AudioProcessorParameter::getValue() are pure virtual methods which you need to override. 

 

So you should create a subclass of AudioProcessorParameter and override these methods to use atomic load and store operations. 

 

i.e. your header would look something like below

//Simplified/Incomplete implementation for illustration 

class CustomAudioParameter : public AudioProcessorParameter
{
public:
    float getValue() const override;
    void setValue(float newValue) override;

private:
    std::atomic<float> value;

}

and you .cpp / implementation 

float CustomAudioParameter::getValue() const
{
    return value.load();
}

void CustomAudioParamter::setValue(float newValue)
{
    value.store(newValue);
}

 

Hopefully that gives you a quick idea of how to subclass AudioProcessorParameter and override the necessary methods to use atomics for thread safety. Apologies for any mistakes above, literally threw this together quickly whilst eating lunch at my desk. I'll try to post up an answer to your second question later on if possible. 

p.s check this link with a pdf of the slides for Timur's original cppcon talk on threading:

https://github.com/CppCon/CppCon2015/blob/master/Presentations/C%2B%2B%20In%20the%20Audio%20Industry/C%2B%2B%20In%20the%20Audio%20Industry%20-%20Timur%20Doumler%20-%20CppCon%202015.pdf

 

Just as an extra by widget Timur means any non fundamental type i.e. a user defined class or struct for example. These can be a little tricker to pass around between threads so atmoic pointer techniques are used. To pass over a buffer/stream of audio data from the audio thread to the gui thread you probably want to go for a lock free fifo structure (explained in Timur's cpp con talk i believe).

Cheers

 

 

 

 
1 Like

Thanks ! Is there some easier way to for example pass a vector or do I just pass pointers? Also why would a atomic shared ptr be the best option? Why shared in this case?

Why shared in this case?

I think because you can be sure, that the object is not destroyed while you are working on it, because you hold a reference at that moment.

Yeah that and the fact that you don't want a unique_ptr going out of scope on your audio thread (at the end of the process block) because then your getting into deallocation and memory management on the audio thread - not good. 

I can't rember right off the top of my head but I believe the memory manager/garbage collector Timur wrote waits to see if the object/widgets refernce count has dropped to 1 (so it's now only the garbage collected which holds a reference to the widget) and then destorys the widget if this is the case. 

 

What are you trying to do though ? If your just posting raw sample data to the gui thread for an oscilloscope or something similar then id saya good old lock free ring buffer/fifo. I'm sure Timur talks about fifo's and what not at some point in his ccp con talk. 

 

Cheers

Trying to write a granular synthesis visualisation

I would like to get a vector with the read positions and a vector with the amplitudes from the audio thread.