Hi there,
In another thread there is a brief exchange about this but the thread grew too long I didn’t want to slide it with a long question.
- Timur Doumler Talks on C++ Audio (Sharing data across threads)](Timur Doumler Talks on C++ Audio (Sharing data across threads))
The part that interested me is the FIFO solution to swap the resource on the audio thread which results in the non-realtime thread deallocating it upon overwriting it. Someone asks if the Sampler Plugin Demo uses a FIFO solution suggested by @reuk, to which he replies that it uses an “incoming and outgoing buffer”.
The queue is a lock-free circular buffer. Adding an item to the queue only happens on the main thread. When adding an item, you overwrite the object that used to occupy that position in the buffer, which frees that object. When removing an item from the queue, you do a swap, so after the swap, the ‘reader’ owns the item that was at that queue position, and that queue position is occupied by the reader’s last state.
Question 1: I can see the the incoming but cannot see the outgoing buffer or anything that handles deallocation. Does this demo actually not handle deallocation? To avoid verbosity for a simple demo app or something?
class SetSampleCommand
{
public:
...
void operator() (SamplerAudioProcessor& proc)
{
// Realtime thread.
proc.readerFactory = std::move (readerFactory);
auto sound = proc.samplerSound;
sound->setSample (std::move (sample)); // See MPESamplerSound::setSample
...
class MPESamplerSound final
{
public:
void setSample (std::unique_ptr<Sample> value)
{
// Realtime thread.
sample = std::move (value); // Deallocation if sample != nullptr before this assign.
setLoopPointsInSeconds (loopPoints);
}
...
private:
std::unique_ptr<Sample> sample; // Sample holds an audio buffer to Huge File.
Another part that interested me is Timur questioning the usage of a FIFO (for another solution) if only one object is being passed at a time.
You are only sharing the last object that was written on the GUI thread with the audio thread. Why don’t you atomically publish that one value to the audio thread? A FIFO is needed if you have a sequence of objects that are being pumped from one thread to another, but in this case there is no sequence, just a single object that is periodically updated.
Question 2: FIFO of size 1 does sound like overkill, but what’s the alternative if atomic<shared_ptr> is not lock free?
Question 3: Anyone know of any example implementations of this FIFO solution? I know it looks simple enough to just go in and do it, I’m just curious how others are doing it and if they ran into any edge cases they needed to handle.