9
// for look free access, this value has to be >= the number of value using threads
10
// value must be a fraction of an integer
11
const int cRingSize = 8;
12
// there are basicly unlimited readers allowed at each ring element
13
// but we have to count them so max() is just fine.
14
// NOTE(rryan): Wrapping max with parentheses avoids conflict with the max macro
15
// defined in windows.h.
16
const int cReaderSlotCnt = (std::numeric_limits<int>::max)();
18
// A single instance of a value of type T along with an atomic integer which
19
// tracks the current number of readers or writers of the slot. The value
20
// m_readerSlots starts at cReaderSlotCnt and counts down to 0. If the value is
21
// 0 or less then reads to the value fail because there are either too many
22
// readers or a write is occurring. A write to the value will fail if
23
// m_readerSlots is not equal to cReaderSlotCnt (e.g. there is an active
26
class ControlRingValue {
30
m_readerSlots(cReaderSlotCnt) {
33
bool tryGet(T* value) const {
34
// Read while consuming one readerSlot
35
bool hasSlot = (m_readerSlots.fetchAndAddAcquire(-1) > 0);
39
(void)m_readerSlots.fetchAndAddRelease(1);
43
bool trySet(const T& value) {
44
// try to lock this element entirely for reading
45
if (m_readerSlots.testAndSetAcquire(cReaderSlotCnt, 0)) {
47
m_readerSlots.fetchAndAddRelease(cReaderSlotCnt);
55
mutable QAtomicInt m_readerSlots;
58
// Ring buffer based implementation for all Types sizeof(T) > sizeof(void*)
60
// An implementation of ControlValueAtomicBase for non-atomic types T. Uses a
61
// ring-buffer of ControlRingValues and a read pointer and write pointer to
62
// provide getValue()/setValue() methods which *sacrifice perfect consistency*
63
// for the benefit of wait-free read/write access to a value.
64
template<typename T, bool ATOMIC = false>
65
class ControlValueAtomicBase {
67
inline T getValue() const {
69
unsigned int index = (unsigned int)m_readIndex
71
while (m_ring[index].tryGet(&value) == false) {
73
// 1) there are more then cReaderSlotCnt reader (get) reading the same value or
74
// 2) the formerly current value is locked by a writer
75
// Case 1 does not happen because we have enough (0x7fffffff) reader slots.
76
// Case 2 happens when the a reader is delayed after reading the
77
// m_currentIndex and in the mean while a reader locks the formaly current value
78
// because it has written cRingSize times. Reading the less recent value will fix
79
// it because it is now actualy the current value.
80
index = (index - 1) % (cRingSize);
85
inline void setValue(const T& value) {
86
// Test if we can read atomic
87
// This test is const and will be mad only at compile time
90
index = (unsigned int)m_writeIndex.fetchAndAddAcquire(1)
92
// This will be repeated if the value is locked
93
// 1) by an other writer writing at the same time or
94
// 2) a delayed reader is still blocking the formerly current value
95
// In both cases writing to the next value will fix it.
96
} while (!m_ring[index].trySet(value));
97
m_readIndex = (int)index;
101
ControlValueAtomicBase()
104
// NOTE(rryan): Wrapping max with parentheses avoids conflict with the
105
// max macro defined in windows.h.
106
Q_ASSERT(((std::numeric_limits<unsigned int>::max)() % cRingSize) == (cRingSize - 1));
110
// In worst case, each reader can consume a reader slot from a different ring element.
111
// In this case there is still one ring element available for writing.
112
ControlRingValue<T> m_ring[cRingSize];
113
QAtomicInt m_readIndex;
114
QAtomicInt m_writeIndex;
117
// Specialized template for types that are deemed to be atomic on the target
118
// architecture. Instead of using a read/write ring to guarantee atomicity,
119
// direct assignment/read of an aligned member variable is used.
121
class ControlValueAtomicBase<T, true> {
123
inline T getValue() const {
127
inline void setValue(const T& value) {
132
ControlValueAtomicBase()
137
#if defined(__GNUC__)
138
T m_value __attribute__ ((aligned(sizeof(void*))));
139
#elif defined(_MSC_VER)
141
T __declspec(align(8)) m_value;
143
T __declspec(align(4)) m_value;
150
// ControlValueAtomic is a wrapper around ControlValueAtomicBase which uses the
151
// sizeof(T) to determine which underlying implementation of
152
// ControlValueAtomicBase to use. For types where sizeof(T) <= sizeof(void*),
153
// the specialized implementation of ControlValueAtomicBase for types that are
154
// atomic on the architecture is used.
156
class ControlValueAtomic
157
: public ControlValueAtomicBase<T, sizeof(T) <= sizeof(void*)> {
161
: ControlValueAtomicBase<T, sizeof(T) <= sizeof(void*)>() {
165
#endif /* CONTROLVALUE_H */