@@ -16,12 +16,22 @@ namespace WaitFreeRingBufferUtilities
16
16
{
17
17
namespace Details
18
18
{
19
- template <typename T, typename ... ElementFeatures>
20
- struct Element : ElementFeatures...
19
+ namespace ElementState
21
20
{
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
23
28
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;
25
35
typename std::aligned_storage<sizeof (T), alignof (T)>::type storage;
26
36
27
37
Element () : value_ptr(nullptr )
@@ -36,9 +46,8 @@ struct Element : ElementFeatures...
36
46
37
47
~Element ()
38
48
{
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 ();
42
51
}
43
52
};
44
53
@@ -78,9 +87,7 @@ struct RingBufferTypeConstructor : ProducerTypeTraits::template Behavior<
78
87
typename ConsumerTypeTraits::template Behavior<
79
88
typename ProducerTypeTraits::template SharedState<
80
89
typename ConsumerTypeTraits::template SharedState<
81
- RingBufferStateBase<
82
- Element<T, typename ProducerTypeTraits::ElementFeature, typename ConsumerTypeTraits::ElementFeature>,
83
- Count>>>>>
90
+ RingBufferStateBase<Element<T>, Count>>>>>
84
91
{
85
92
};
86
93
@@ -108,20 +115,13 @@ struct MultiProducerTypeTraits
108
115
{
109
116
const std::size_t local_end = end.fetch_add (1 , std::memory_order_acquire);
110
117
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))
113
121
{
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);
122
124
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);
125
125
return true ;
126
126
}
127
127
}
@@ -134,11 +134,6 @@ struct MultiProducerTypeTraits
134
134
protected:
135
135
CacheAlignedAndPaddedObject<std::atomic<std::int64_t >> push_task_count{static_cast <std::int64_t >(BaseType::COUNT)};
136
136
};
137
-
138
- struct ElementFeature
139
- {
140
- CacheAlignedAndPaddedObject<std::atomic_bool> is_pusher_processing{false };
141
- };
142
137
};
143
138
144
139
struct MultiConsumerTypeTraits
@@ -163,25 +158,16 @@ struct MultiConsumerTypeTraits
163
158
while (true )
164
159
{
165
160
const std::size_t local_begin = begin.fetch_add (1 , std::memory_order_acquire);
166
-
167
161
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
- }
177
162
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 ();
180
168
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);
182
170
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);
185
171
return result;
186
172
}
187
173
}
@@ -194,11 +180,6 @@ struct MultiConsumerTypeTraits
194
180
protected:
195
181
CacheAlignedAndPaddedObject<std::atomic<std::int64_t >> pop_task_count{std::int64_t {0 }};
196
182
};
197
-
198
- struct ElementFeature
199
- {
200
- CacheAlignedAndPaddedObject<std::atomic_bool> is_popper_processing{false };
201
- };
202
183
};
203
184
204
185
struct SingleProducerTypeTraits
@@ -236,10 +217,10 @@ struct SingleProducerTypeTraits
236
217
{
237
218
const std::size_t element_index = (state.end ++) & BaseType::COUNT_MASK;
238
219
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 )
240
221
{
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);
243
224
BaseType::pop_task_count.fetch_add (1 , std::memory_order_release);
244
225
245
226
return true ;
@@ -254,10 +235,6 @@ struct SingleProducerTypeTraits
254
235
protected:
255
236
CacheAlignedAndPaddedObject<std::atomic_size_t > push_task_count{BaseType::COUNT};
256
237
};
257
-
258
- struct ElementFeature
259
- {
260
- };
261
238
};
262
239
263
240
struct SingleConsumerTypeTraits
@@ -294,13 +271,12 @@ struct SingleConsumerTypeTraits
294
271
{
295
272
const std::size_t element_index = (state.begin ++) & BaseType::COUNT_MASK;
296
273
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)
299
275
{
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 ();
302
278
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);
304
280
BaseType::push_task_count.fetch_add (1 , std::memory_order_release);
305
281
306
282
return result;
@@ -315,10 +291,6 @@ struct SingleConsumerTypeTraits
315
291
protected:
316
292
CacheAlignedAndPaddedObject<std::atomic_size_t > pop_task_count{std::size_t {0 }};
317
293
};
318
-
319
- struct ElementFeature
320
- {
321
- };
322
294
};
323
295
324
296
} // namespace Details
0 commit comments