Code: Select all
std::unordered_map
Code: Select all
_consumerThreadUpdatesTable
Code: Select all
_producerThreadUpdatesTable
Code: Select all
_bridgeUpdatesTable
Code: Select all
#include
#include
// This object lets us safely transport sets of key-value pair updates from a single ProducerThread to a single ConsumerThread without requiring any Mutex locking
class KeyedParameterBridge
{
public:
KeyedParameterBridge() : _consumerOwnsBridgeUpdatesTable(false)
{
// empty
}
/** Called by the producer thread; places a pending update into the producer-thread's local pending-update-table. */
void ProducerPutUpdate(int parameterID, float parameterValue) {_producerThreadUpdatesTable[parameterID] = parameterValue;}
/** Called by the producer thread; attempts to push all of the updates currently placed (via ProducerPutUpdate()) to
* the _bridgeUpdatesTable where the consumer thread will be able to access them
* @returns true if we were able to push some updates in this call, or false if didn't push any updates
*/
bool ProducerPushUpdatesToConsumer()
{
if (_producerThreadUpdatesTable.size() == 0) return false; // no updates to push
if (_consumerOwnsBridgeUpdatesTable.load()) return false; // can't safely do anything yet; we'll have to wait until the ConsumerThread consumes _bridgeUpdatesTable's current contents
_bridgeUpdatesTable = std::move(_producerThreadUpdatesTable); // O(1) pointer-move from _producerThreadUpdatesTable to _bridgeUpdatesTable
_consumerOwnsBridgeUpdatesTable = true; // so the ConsumerThread will know the _bridgeUpdatesTable is safe for him to access now
_producerThreadUpdatesTable.clear(); // make sure our producer-side table is in a known-empty state
return true;
}
/** Called periodically by the consumer thread; returns any available updates for the consumer thread to apply to its local data structure */
const std::unordered_map & ConsumerConsumeUpdates()
{
_consumerThreadUpdatesTable.clear(); // make sure our consumer-side table is in a known-empty state
if (_consumerOwnsBridgeUpdatesTable.load()) // see if we have access
{
_consumerThreadUpdatesTable = std::move(_bridgeUpdatesTable); // O(1) pointer-move from _bridgeUpdatesTable to _consumerThreadUpdatesTable
_consumerOwnsBridgeUpdatesTable = false; // so the ProducerThread will know we already grabbed the update and he can push again now
}
return _consumerThreadUpdatesTable;
}
private:
std::atomic _consumerOwnsBridgeUpdatesTable; // true iff the _bridgeUpdatesTable currently contains data for the consumer thread to consume
std::unordered_map _producerThreadUpdatesTable; // populated by the producer-thread, never accessed by the consumer thread
std::unordered_map _bridgeUpdatesTable; // access to this table is governed by the state of (_consumerOwnsBridgeUpdatesTable)
std::unordered_map _consumerThreadUpdatesTable; // read by the consumer-thread, never accessed by the producer thread
};