Skip to content

Commit d30ee41

Browse files
Fix an issue while improving performance.
1 parent 80d1ba4 commit d30ee41

File tree

1 file changed

+35
-63
lines changed

1 file changed

+35
-63
lines changed

WaitFreeRingBufferUtilities/Include/details/ring-buffer-type-constructor.inl

Lines changed: 35 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@ namespace WaitFreeRingBufferUtilities
1616
{
1717
namespace Details
1818
{
19-
template <typename T, typename... ElementFeatures>
20-
struct Element : ElementFeatures...
19+
namespace ElementState
2120
{
22-
using ElementType = T;
21+
enum : std::uint_fast8_t
22+
{
23+
IN_PROGRESS,
24+
READY_FOR_PUSH,
25+
READY_FOR_POP,
26+
};
27+
} // namespace ElementState
2328

24-
std::atomic<T *> value_ptr;
29+
template <typename T>
30+
struct Element
31+
{
32+
using ElementType = T;
33+
CacheAlignedAndPaddedObject<std::atomic<std::uint_fast8_t>> state{ElementState::READY_FOR_PUSH};
34+
T *value_ptr;
2535
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
2636

2737
Element() : value_ptr(nullptr)
@@ -36,9 +46,8 @@ struct Element : ElementFeatures...
3646

3747
~Element()
3848
{
39-
const auto local_value_ptr = value_ptr.load(std::memory_order_relaxed);
40-
if (local_value_ptr)
41-
local_value_ptr->~T();
49+
if (value_ptr)
50+
value_ptr->~T();
4251
}
4352
};
4453

@@ -78,9 +87,7 @@ struct RingBufferTypeConstructor : ProducerTypeTraits::template Behavior<
7887
typename ConsumerTypeTraits::template Behavior<
7988
typename ProducerTypeTraits::template SharedState<
8089
typename ConsumerTypeTraits::template SharedState<
81-
RingBufferStateBase<
82-
Element<T, typename ProducerTypeTraits::ElementFeature, typename ConsumerTypeTraits::ElementFeature>,
83-
Count>>>>>
90+
RingBufferStateBase<Element<T>, Count>>>>>
8491
{
8592
};
8693

@@ -108,20 +115,13 @@ struct MultiProducerTypeTraits
108115
{
109116
const std::size_t local_end = end.fetch_add(1, std::memory_order_acquire);
110117
const std::size_t element_index = local_end & BaseType::COUNT_MASK;
111-
bool expected_is_pusher_processing = false;
112-
if (std::atomic_compare_exchange_strong(&BaseType::elements[element_index].is_pusher_processing, &expected_is_pusher_processing, true))
118+
119+
auto expected_element_state = ElementState::READY_FOR_PUSH;
120+
if (std::atomic_compare_exchange_strong(&BaseType::elements[element_index].state, &expected_element_state, ElementState::IN_PROGRESS))
113121
{
114-
if (BaseType::elements[element_index].value_ptr.load(std::memory_order_acquire))
115-
{
116-
BaseType::elements[element_index].is_pusher_processing.store(false, std::memory_order_relaxed);
117-
continue;
118-
}
119-
120-
BaseType::elements[element_index].value_ptr.store(new (&BaseType::elements[element_index].storage) ElementType(std::forward<Args>(args)...),
121-
std::memory_order_release);
122+
BaseType::elements[element_index].value_ptr = new (&BaseType::elements[element_index].storage) ElementType(std::forward<Args>(args)...);
123+
BaseType::elements[element_index].state.store(ElementState::READY_FOR_POP, std::memory_order_release);
122124
BaseType::pop_task_count.fetch_add(1, std::memory_order_release);
123-
124-
BaseType::elements[element_index].is_pusher_processing.store(false, std::memory_order_release);
125125
return true;
126126
}
127127
}
@@ -134,11 +134,6 @@ struct MultiProducerTypeTraits
134134
protected:
135135
CacheAlignedAndPaddedObject<std::atomic<std::int64_t>> push_task_count{static_cast<std::int64_t>(BaseType::COUNT)};
136136
};
137-
138-
struct ElementFeature
139-
{
140-
CacheAlignedAndPaddedObject<std::atomic_bool> is_pusher_processing{false};
141-
};
142137
};
143138

144139
struct MultiConsumerTypeTraits
@@ -163,25 +158,16 @@ struct MultiConsumerTypeTraits
163158
while (true)
164159
{
165160
const std::size_t local_begin = begin.fetch_add(1, std::memory_order_acquire);
166-
167161
const std::size_t element_index = local_begin & BaseType::COUNT_MASK;
168-
bool expected_is_popper_processing = false;
169-
if (std::atomic_compare_exchange_strong(&BaseType::elements[element_index].is_popper_processing, &expected_is_popper_processing, true))
170-
{
171-
const auto value_ptr = BaseType::elements[element_index].value_ptr.load(std::memory_order_acquire);
172-
if (!value_ptr)
173-
{
174-
BaseType::elements[element_index].is_popper_processing.store(false, std::memory_order_relaxed);
175-
continue;
176-
}
177162

178-
OptionalType<ElementType> result{std::move(*value_ptr)};
179-
value_ptr->~ElementType();
163+
auto expected_element_state = ElementState::READY_FOR_POP;
164+
if (std::atomic_compare_exchange_strong(&BaseType::elements[element_index].state, &expected_element_state, ElementState::IN_PROGRESS))
165+
{
166+
OptionalType<ElementType> result{std::move(*BaseType::elements[element_index].value_ptr)};
167+
BaseType::elements[element_index].value_ptr->~ElementType();
180168

181-
BaseType::elements[element_index].value_ptr.store(nullptr, std::memory_order_release);
169+
BaseType::elements[element_index].state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
182170
BaseType::push_task_count.fetch_add(1, std::memory_order_release);
183-
184-
BaseType::elements[element_index].is_popper_processing.store(false, std::memory_order_release);
185171
return result;
186172
}
187173
}
@@ -194,11 +180,6 @@ struct MultiConsumerTypeTraits
194180
protected:
195181
CacheAlignedAndPaddedObject<std::atomic<std::int64_t>> pop_task_count{std::int64_t{0}};
196182
};
197-
198-
struct ElementFeature
199-
{
200-
CacheAlignedAndPaddedObject<std::atomic_bool> is_popper_processing{false};
201-
};
202183
};
203184

204185
struct SingleProducerTypeTraits
@@ -236,10 +217,10 @@ struct SingleProducerTypeTraits
236217
{
237218
const std::size_t element_index = (state.end++) & BaseType::COUNT_MASK;
238219

239-
if (!BaseType::elements[element_index].value_ptr.load(std::memory_order_acquire))
220+
if (BaseType::elements[element_index].state.load(std::memory_order_acquire) == ElementState::READY_FOR_PUSH)
240221
{
241-
BaseType::elements[element_index].value_ptr.store(new (&BaseType::elements[element_index].storage) ElementType(std::forward<Args>(args)...),
242-
std::memory_order_release);
222+
BaseType::elements[element_index].value_ptr = new (&BaseType::elements[element_index].storage) ElementType(std::forward<Args>(args)...);
223+
BaseType::elements[element_index].state.store(ElementState::READY_FOR_POP, std::memory_order_release);
243224
BaseType::pop_task_count.fetch_add(1, std::memory_order_release);
244225

245226
return true;
@@ -254,10 +235,6 @@ struct SingleProducerTypeTraits
254235
protected:
255236
CacheAlignedAndPaddedObject<std::atomic_size_t> push_task_count{BaseType::COUNT};
256237
};
257-
258-
struct ElementFeature
259-
{
260-
};
261238
};
262239

263240
struct SingleConsumerTypeTraits
@@ -294,13 +271,12 @@ struct SingleConsumerTypeTraits
294271
{
295272
const std::size_t element_index = (state.begin++) & BaseType::COUNT_MASK;
296273

297-
const auto value_ptr = BaseType::elements[element_index].value_ptr.load(std::memory_order_acquire);
298-
if (value_ptr)
274+
if (BaseType::elements[element_index].state.load(std::memory_order_acquire) == ElementState::READY_FOR_POP)
299275
{
300-
OptionalType<ElementType> result{std::move(*value_ptr)};
301-
value_ptr->~ElementType();
276+
OptionalType<ElementType> result{std::move(*BaseType::elements[element_index].value_ptr)};
277+
BaseType::elements[element_index].value_ptr->~ElementType();
302278

303-
BaseType::elements[element_index].value_ptr.store(nullptr, std::memory_order_release);
279+
BaseType::elements[element_index].state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
304280
BaseType::push_task_count.fetch_add(1, std::memory_order_release);
305281

306282
return result;
@@ -315,10 +291,6 @@ struct SingleConsumerTypeTraits
315291
protected:
316292
CacheAlignedAndPaddedObject<std::atomic_size_t> pop_task_count{std::size_t{0}};
317293
};
318-
319-
struct ElementFeature
320-
{
321-
};
322294
};
323295

324296
} // namespace Details

0 commit comments

Comments
 (0)