Audacity 3.2.0
Classes | Public Member Functions | Private Attributes | List of all members
MessageBuffer< Data > Class Template Reference

Communicate data atomically from one writer thread to one reader. More...

#include <MessageBuffer.h>

Inheritance diagram for MessageBuffer< Data >:
[legend]
Collaboration diagram for MessageBuffer< Data >:
[legend]

Classes

struct  UpdateSlot
 

Public Member Functions

void Initialize ()
 
template<typename Result = Data, typename... ConstructorArgs>
Result Read (ConstructorArgs &&...args)
 Move data out (if available), or else copy it out. More...
 
template<typename Arg = Data&&>
void Write (Arg &&arg)
 Reassign a slot by move or copy. More...
 

Private Attributes

NonInterfering< UpdateSlotmSlots [2]
 
std::atomic< unsigned char > mLastWrittenSlot { 0 }
 

Detailed Description

template<typename Data>
class MessageBuffer< Data >

Communicate data atomically from one writer thread to one reader.

This is not a queue: it is not necessary for each write to be read. Rather loss of a message is allowed: writer may overwrite. Data must be default-constructible and reassignable.

Definition at line 23 of file MessageBuffer.h.

Member Function Documentation

◆ Initialize()

template<typename Data >
void MessageBuffer< Data >::Initialize

Definition at line 47 of file MessageBuffer.h.

48{
49 for (auto &slot : mSlots)
50 // Lock both slots first, maybe spinning a little
51 while ( slot.mBusy.exchange( true, std::memory_order_acquire ) )
52 {}
53
54 mSlots[0].mData = {};
55 mSlots[1].mData = {};
56 mLastWrittenSlot.store( 0, std::memory_order_relaxed );
57
58 for (auto &slot : mSlots)
59 slot.mBusy.exchange( false, std::memory_order_release );
60}
NonInterfering< UpdateSlot > mSlots[2]
Definition: MessageBuffer.h:28
std::atomic< unsigned char > mLastWrittenSlot
Definition: MessageBuffer.h:30

◆ Read()

template<typename Data >
template<typename Result , typename... ConstructorArgs>
Result MessageBuffer< Data >::Read ( ConstructorArgs &&...  args)

Move data out (if available), or else copy it out.

Template Parameters
Resultis constructible from Data&& and forwards of other arguments

Definition at line 64 of file MessageBuffer.h.

65{
66 // Whichever slot was last written, prefer to read that.
67 auto idx = mLastWrittenSlot.load( std::memory_order_relaxed );
68 idx = 1 - idx;
69 bool wasBusy = false;
70 do {
71 // This loop is unlikely to execute twice, but it might because the
72 // producer thread is writing a slot.
73 idx = 1 - idx;
74 wasBusy = mSlots[idx].mBusy.exchange( true, std::memory_order_acquire );
75 } while ( wasBusy );
76
77 // Copy the slot
78 Result result(
79 std::move( mSlots[idx].mData ), std::forward<ConstructorArgs>(args)... );
80
81 mSlots[idx].mBusy.store( false, std::memory_order_release );
82
83 return result;
84}

◆ Write()

template<typename Data >
template<typename Arg >
void MessageBuffer< Data >::Write ( Arg &&  arg)

Reassign a slot by move or copy.

Definition at line 88 of file MessageBuffer.h.

89{
90 // Whichever slot was last written, prefer to write the other.
91 auto idx = mLastWrittenSlot.load( std::memory_order_relaxed );
92 bool wasBusy = false;
93 do {
94 // This loop is unlikely to execute twice, but it might because the
95 // consumer thread is reading a slot.
96 idx = 1 - idx;
97 wasBusy = mSlots[idx].mBusy.exchange( true, std::memory_order_acquire );
98 } while ( wasBusy );
99
100 mSlots[idx].mData = std::forward<Arg>(arg);
101 mLastWrittenSlot.store( idx, std::memory_order_relaxed );
102
103 mSlots[idx].mBusy.store( false, std::memory_order_release );
104}

Member Data Documentation

◆ mLastWrittenSlot

template<typename Data >
std::atomic<unsigned char> MessageBuffer< Data >::mLastWrittenSlot { 0 }
private

Definition at line 30 of file MessageBuffer.h.

◆ mSlots

template<typename Data >
NonInterfering<UpdateSlot> MessageBuffer< Data >::mSlots[2]
private

Definition at line 28 of file MessageBuffer.h.


The documentation for this class was generated from the following file: