Mam klasę kolejki, która działa super gdy jest tylko jeden wytwórca. Kolejka to prosty ring buffer. Mam już metodę Pop
zaimplementowaną dla kilku czytających i działa jak natura chciała. Nie mogę jednak poprawnie napisać metody puszującej. Próbowałem pozycję do której chcemy pusznąć element wziąć w pętlę CAS, ale apka się po prostu zawiesza i nie chce wyjść z tej pętli.
template<typename T, uint size = 1>
struct mpWriter
{
bool push(const T& element)
{
while (true) {
uint oldWritePosition = writePosition.load();
uint newWritePosition = getPositionAfter(oldWritePosition);
// jeśli pozycja wpisania jest starą pozycją
// zamień ją na nową
// i dodaj dane na starej pozycji
// i zwróć true
// jeśli to w ogóle ma jakiś sens
if (writePosition.compare_exchange_strong(oldWritePosition, newWritePosition)) {
ringBuffer[oldWritePosition].store(element);
return true;
}
}
}
static constexpr uint getPositionAfter(uint position) noexcept
{
return ++position == ringBufferSize ? 0 : position;
}
static constexpr uint ringBufferSize = size + 1;
std::atomic<T> ringBuffer[ringBufferSize];
std::atomic<uint> writePosition = 0;
};
int main()
{
mpWriter<int, 50> ints;
std::vector<std::thread> producers;
for(int i = 0; i < 50; ++i) {
producers.push_back(std::thread([&](){
ints.push(0);
}));
}
for (auto& producer : producers) {
producer.join();
}
return 0;
}
Co jest nie tak z tym kodem? Jak poprawnie to napisać? Nie chce używać już napisanych kolejek. Chce zrozumieć o co w tym chodzi.