UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Chaos::TTripleBufferedData< DataType > Class Template Reference

#include <TripleBufferedData.h>

Public Member Functions

 TTripleBufferedData ()
 
DataType * ExchangeProducerBuffer ()
 
DataType * ExchangeConsumerBuffer ()
 

Detailed Description

template<class DataType>
class Chaos::TTripleBufferedData< DataType >

A lock free paradigm for sharing data between threads.

Called a triple buffer because at any point in time, there may be 3 buffers available: 1 owned by the producing thread, 1 owned by the consuming thread, and 1 waiting in an atomic variable. The third storage location enables transfer of ownership such that if you have a copy of the data, you own it without worry of contention.

Producer thread:

struct AnimXf
{
};
struct MyProducer
{
MyConsumer Consumer; // Owns the triple buffer.
AnimXf* Buffer = nullptr;
// This function is called repeatedly at some interval by the producing thread.
void Produce()
{
// Get a new buffer if we need one.
if(!Buffer)
Buffer = Consumer.AnimXfTripleBuffer.ExchangeProducerBuffer();
// This class now has exclusive ownership of the memory pointed to by Buffer.
Buffer->Xf = ...;
Buffer->Velocity = ...;
// Push the new values to the consumer, and get a new buffer for next time.
Buffer = Consumer.AnimXfTripleBuffer.ExchangeProducerBuffer();
}
};
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
Definition Array.h:670

Consumer thread:

struct MyConsumer
{
// In this example the consumer owns the triple buffer, but that's
// not a requirement.
AnimXf* Buffer = nullptr;
// This function is called repeatedly at some interval by the consuming thread.
void Consume()
{
// Get a new view of the data, which can be null or old.
Buffer = AnimXfTripleBuffer.ExchangeAnimXfConsumerBuffer();
// This class now has exclusive ownership of the memory pointed to by Buffer.
if(Buffer)
{
... = Buffer->Xf;
... = Buffer->Velocity;
}
}
};
Definition TripleBufferedData.h:73

Constructor & Destructor Documentation

◆ TTripleBufferedData()

template<class DataType >
Chaos::TTripleBufferedData< DataType >::TTripleBufferedData ( )
inline

Member Function Documentation

◆ ExchangeConsumerBuffer()

template<class DataType >
DataType * Chaos::TTripleBufferedData< DataType >::ExchangeConsumerBuffer ( )
inline

Get an updated buffer for the consuming thread to read from.

The returned pointer may be null if the producer thread hasn't done an update since the last time this function was called.

The same capacity for a race condition exists with this functions return value as with ExchangeProducerBuffer().

...
int X = *MyCopy; // Ok
IntBuffer.ExchangeConsumerBuffer(); // Mem holding X returned to producer thread.
int Y = *MyCopy; // Race condition!
DataType * ExchangeConsumerBuffer()
Definition TripleBufferedData.h:152
@ Y
Definition SimulationModuleBase.h:153
@ X
Definition SimulationModuleBase.h:152

Always refresh the same variable.

...
int X = *MyCopy; // Ok
MyCopy = IntBuffer.ExchangeConsumerBuffer(); // Mem holding X returned to producer thread.
int Y = *MyCopy; // Ok

◆ ExchangeProducerBuffer()

template<class DataType >
DataType * Chaos::TTripleBufferedData< DataType >::ExchangeProducerBuffer ( )
inline

Get a new buffer for the producing thread to write to, while at the same time making the previous buffer available to the consumer.

This function will manufacture new instances of DataType, if it needs to. Thus, the returned pointer will never be null.

The DataType value is returned by shared pointer to simplify ownership semantics, particularly with respect to cleanup. It is important to not mistake that for exclusive ownership of the memory, and retain the return value of this function too long. For instance:

...
(*MyCopy) = 1; // Ok
IntBuffer.ExchangeProducerBuffer(); // Mem holding "1" now available to consumer thread.
(*MyCopy) = 2; // Race condition!
DataType * ExchangeProducerBuffer()
Definition TripleBufferedData.h:114

Instead, always reuse the same shared pointer, or dereference the returned shared pointer if you're not worried about copying the data.

...
(*MyCopy) = 1; // Ok
MyCopy = IntBuffer.ExchangeProducerBuffer(); // Mem holding "1" now available to consumer thread.
(*MyCopy) = 2; // Ok

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