Skip to content

Commit b60e5fd

Browse files
Fix small compilation issues.
1 parent d30ee41 commit b60e5fd

File tree

2 files changed

+62
-95
lines changed

2 files changed

+62
-95
lines changed

Test/Source/single-producer-single-conumer-test.cpp

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ namespace Iyp
99
{
1010
namespace SingleProducerSingleConsumerRingBufferTest
1111
{
12-
13-
constexpr static std::size_t RingSize = 4096;
12+
static constexpr std::size_t RingSize = 4096;
13+
static constexpr std::size_t NumberOfTries = 4096;
1414
using TestRingBufferType = WaitFreeRingBufferUtilities::RingBuffer<std::size_t,
1515
WaitFreeRingBufferUtilities::AccessRequirements::SINGLE_CONSUMER |
1616
WaitFreeRingBufferUtilities::AccessRequirements::SINGLE_PRODUCER,
1717
RingSize>;
1818

1919
TEST(SingleProducerSingleConsumerRingBufferTest, EmptyAndFullRingTest)
2020
{
21-
constexpr std::size_t NumberOfTries = 256;
22-
2321
TestRingBufferType ring;
2422

2523
EXPECT_FALSE(ring.pop());
@@ -40,8 +38,6 @@ TEST(SingleProducerSingleConsumerRingBufferTest, EmptyAndFullRingTest)
4038

4139
TEST(SingleProducerSingleConsumerRingBufferTest, PushPopIntegrity)
4240
{
43-
constexpr std::size_t NumberOfTries = 256;
44-
4541
TestRingBufferType ring;
4642

4743
for (std::size_t try_index = 0; try_index < NumberOfTries; try_index++)
@@ -64,8 +60,6 @@ TEST(SingleProducerSingleConsumerRingBufferTest, PushPopIntegrity)
6460

6561
TEST(SingleProducerSingleConsumerRingBufferTest, OrderedPushPop)
6662
{
67-
constexpr std::size_t NumberOfTries = 256;
68-
6963
TestRingBufferType ring;
7064

7165
for (std::size_t try_index = 0; try_index < NumberOfTries; try_index++)
@@ -81,44 +75,33 @@ TEST(SingleProducerSingleConsumerRingBufferTest, OrderedPushPop)
8175
}
8276
}
8377

84-
TEST(SingleProducerSingleConsumerRingBufferTest, SingleProducerSingleConsumerPushPopIntergrity)
78+
TEST(SingleProducerSingleConsumerRingBufferTest, SingleProducerSingleConsumerPushPopIntergrityAndOrder)
8579
{
86-
constexpr std::size_t NumberOfTries = 256;
87-
8880
TestRingBufferType ring;
8981

9082
std::array<std::atomic_size_t, RingSize> pop_counts;
9183

9284
for (auto &pop_count : pop_counts)
9385
pop_count = 0;
9486

95-
std::thread popper([&ring, &pop_counts, NumberOfTries]() {
87+
std::thread popper([&ring, &pop_counts]() {
9688
for (std::size_t try_index = 0; try_index < NumberOfTries; try_index++)
97-
{
98-
for (std::size_t i = 0; i < RingSize; i++)
89+
for (std::size_t i = 0; i < RingSize;)
9990
{
100-
while (true)
91+
const auto popped_value = ring.pop();
92+
if (popped_value)
10193
{
102-
const auto popped_value = ring.pop();
103-
if (popped_value)
104-
{
105-
pop_counts[*popped_value].fetch_add(1, std::memory_order_relaxed);
106-
break;
107-
}
94+
if (popped_value.get() == i)
95+
pop_counts[i].fetch_add(1, std::memory_order_relaxed);
96+
i++;
10897
}
10998
}
110-
}
11199
});
112100

113101
for (std::size_t try_index = 0; try_index < NumberOfTries; try_index++)
114-
{
115-
for (std::size_t i = 0; i < RingSize; i++)
116-
{
117-
while (!ring.push(i))
118-
{
119-
}
120-
}
121-
}
102+
for (std::size_t i = 0; i < RingSize;)
103+
if (ring.push(i))
104+
i++;
122105

123106
popper.join();
124107

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

Lines changed: 49 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,11 @@ template <typename T>
3030
struct Element
3131
{
3232
using ElementType = T;
33-
CacheAlignedAndPaddedObject<std::atomic<std::uint_fast8_t>> state{ElementState::READY_FOR_PUSH};
33+
std::atomic<std::uint_fast8_t> state{ElementState::READY_FOR_PUSH};
3434
T *value_ptr;
3535
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
3636

37-
Element() : value_ptr(nullptr)
38-
{
39-
}
37+
Element() = default;
4038

4139
Element(const Element &) = delete;
4240
Element(Element &&) = delete;
@@ -46,7 +44,7 @@ struct Element
4644

4745
~Element()
4846
{
49-
if (value_ptr)
47+
if (state.load(std::memory_order_acquire) == ElementState::READY_FOR_POP)
5048
value_ptr->~T();
5149
}
5250
};
@@ -80,6 +78,14 @@ struct CountInt64CompatibilityCheck
8078
{
8179
static_assert(Count <= static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max()), "Count exceeds the maximum. Count should fit in a std::int64_t.");
8280
};
81+
82+
struct DummyAtomicSizeT
83+
{
84+
std::size_t fetch_add(const std::size_t, const std::memory_order)
85+
{
86+
return 0;
87+
}
88+
};
8389
} // namespace Private
8490

8591
template <typename ProducerTypeTraits, typename ConsumerTypeTraits, typename T, std::size_t Count>
@@ -113,14 +119,14 @@ struct MultiProducerTypeTraits
113119

114120
while (true)
115121
{
116-
const std::size_t local_end = end.fetch_add(1, std::memory_order_acquire);
117-
const std::size_t element_index = local_end & BaseType::COUNT_MASK;
122+
const std::size_t element_index = end.fetch_add(1, std::memory_order_acquire) & BaseType::COUNT_MASK;
123+
auto &element = BaseType::elements[element_index];
118124

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))
125+
std::uint_fast8_t expected_element_state = ElementState::READY_FOR_PUSH;
126+
if (std::atomic_compare_exchange_strong(&element.state, &expected_element_state, std::uint_fast8_t(ElementState::IN_PROGRESS)))
121127
{
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);
128+
element.value_ptr = new (&element.storage) ElementType(std::forward<Args>(args)...);
129+
element.state.store(ElementState::READY_FOR_POP, std::memory_order_release);
124130
BaseType::pop_task_count.fetch_add(1, std::memory_order_release);
125131
return true;
126132
}
@@ -157,16 +163,16 @@ struct MultiConsumerTypeTraits
157163

158164
while (true)
159165
{
160-
const std::size_t local_begin = begin.fetch_add(1, std::memory_order_acquire);
161-
const std::size_t element_index = local_begin & BaseType::COUNT_MASK;
166+
const std::size_t element_index = begin.fetch_add(1, std::memory_order_acquire) & BaseType::COUNT_MASK;
167+
auto &element = BaseType::elements[element_index];
162168

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))
169+
std::uint_fast8_t expected_element_state = ElementState::READY_FOR_POP;
170+
if (std::atomic_compare_exchange_strong(&element.state, &expected_element_state, std::uint_fast8_t(ElementState::IN_PROGRESS)))
165171
{
166-
OptionalType<ElementType> result{std::move(*BaseType::elements[element_index].value_ptr)};
167-
BaseType::elements[element_index].value_ptr->~ElementType();
172+
OptionalType<ElementType> result{std::move(*element.value_ptr)};
173+
element.value_ptr->~ElementType();
168174

169-
BaseType::elements[element_index].state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
175+
element.state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
170176
BaseType::push_task_count.fetch_add(1, std::memory_order_release);
171177
return result;
172178
}
@@ -190,50 +196,39 @@ struct SingleProducerTypeTraits
190196
private:
191197
struct State
192198
{
193-
std::size_t pushed_task_count{0};
194-
std::size_t local_push_task_count{BaseType::COUNT};
195199
std::size_t end{0};
196200
};
197201

198-
CacheAlignedAndPaddedObject<State> state{};
202+
CacheAlignedAndPaddedObject<State> state;
199203

200204
public:
201205
using ElementType = typename BaseType::ElementType;
202206

203207
template <typename... Args>
204208
bool push(Args &&... args)
205209
{
206-
if (state.local_push_task_count == state.pushed_task_count)
207-
{
208-
const auto stack_local_push_task_count = BaseType::push_task_count.load(std::memory_order_acquire);
209-
if (state.local_push_task_count == stack_local_push_task_count)
210-
return false;
211-
state.local_push_task_count = stack_local_push_task_count;
212-
}
210+
const std::size_t element_index = state.end & BaseType::COUNT_MASK;
211+
auto &element = BaseType::elements[element_index];
213212

214-
state.pushed_task_count++;
215-
216-
while (true)
213+
if (element.state.load(std::memory_order_acquire) == ElementState::READY_FOR_PUSH)
217214
{
218-
const std::size_t element_index = (state.end++) & BaseType::COUNT_MASK;
219-
220-
if (BaseType::elements[element_index].state.load(std::memory_order_acquire) == ElementState::READY_FOR_PUSH)
221-
{
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);
224-
BaseType::pop_task_count.fetch_add(1, std::memory_order_release);
215+
element.value_ptr = new (&element.storage) ElementType(std::forward<Args>(args)...);
216+
element.state.store(ElementState::READY_FOR_POP, std::memory_order_release);
217+
BaseType::pop_task_count.fetch_add(1, std::memory_order_release);
225218

226-
return true;
227-
}
219+
state.end++;
220+
return true;
228221
}
222+
else
223+
return false;
229224
}
230225
};
231226

232227
template <typename BaseType>
233228
struct SharedState : BaseType
234229
{
235230
protected:
236-
CacheAlignedAndPaddedObject<std::atomic_size_t> push_task_count{BaseType::COUNT};
231+
Private::DummyAtomicSizeT push_task_count{};
237232
};
238233
};
239234

@@ -245,51 +240,40 @@ struct SingleConsumerTypeTraits
245240
private:
246241
struct State
247242
{
248-
std::size_t popped_task_count{0};
249-
std::size_t local_pop_task_count{0};
250243
std::size_t begin{0};
251244
};
252245

253-
CacheAlignedAndPaddedObject<State> state{};
246+
CacheAlignedAndPaddedObject<State> state;
254247

255248
public:
256249
using ElementType = typename BaseType::ElementType;
257250

258251
OptionalType<ElementType> pop()
259252
{
260-
if (state.local_pop_task_count == state.popped_task_count)
261-
{
262-
const auto stack_local_pop_task_count = BaseType::pop_task_count.load(std::memory_order_acquire);
263-
if (state.local_pop_task_count == stack_local_pop_task_count)
264-
return OptionalType<ElementType>{};
265-
state.local_pop_task_count = stack_local_pop_task_count;
266-
}
267-
268-
state.popped_task_count++;
253+
const std::size_t element_index = state.begin & BaseType::COUNT_MASK;
254+
auto &element = BaseType::elements[element_index];
269255

270-
while (true)
256+
if (element.state.load(std::memory_order_acquire) == ElementState::READY_FOR_POP)
271257
{
272-
const std::size_t element_index = (state.begin++) & BaseType::COUNT_MASK;
258+
OptionalType<ElementType> result{std::move(*element.value_ptr)};
259+
element.value_ptr->~ElementType();
273260

274-
if (BaseType::elements[element_index].state.load(std::memory_order_acquire) == ElementState::READY_FOR_POP)
275-
{
276-
OptionalType<ElementType> result{std::move(*BaseType::elements[element_index].value_ptr)};
277-
BaseType::elements[element_index].value_ptr->~ElementType();
278-
279-
BaseType::elements[element_index].state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
280-
BaseType::push_task_count.fetch_add(1, std::memory_order_release);
261+
element.state.store(ElementState::READY_FOR_PUSH, std::memory_order_release);
262+
BaseType::push_task_count.fetch_add(1, std::memory_order_release);
281263

282-
return result;
283-
}
264+
state.begin++;
265+
return result;
284266
}
267+
else
268+
return OptionalType<ElementType>{};
285269
}
286270
};
287271

288272
template <typename BaseType>
289273
struct SharedState : BaseType
290274
{
291275
protected:
292-
CacheAlignedAndPaddedObject<std::atomic_size_t> pop_task_count{std::size_t{0}};
276+
Private::DummyAtomicSizeT pop_task_count{};
293277
};
294278
};
295279

0 commit comments

Comments
 (0)