1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/*
* SimpleSafeQueue.h
*
* Created on: 20 Feb 2018
* Author: jeremy
*/
#ifndef SOURCE_UTIL_SIMPLESAFEQUEUE_H_
#define SOURCE_UTIL_SIMPLESAFEQUEUE_H_
#include <atomic>
#include <array>
#include <cstddef>
namespace Util
{
/**
* A thread-safe Single Producer Single Consumer queue.
* Its size is fixed, it's a circular buffer.
* Default size = 32.
*/
template<typename T, size_t Length = 64>
class SimpleSafeQueue
{
public:
/**
* @brief Pushes new value to the queue, and returns true if successful.
* @param value
* @return true if the queue isn't full, false otherwise.
*/
bool Push(const T& value)
{
const auto oldWriterIndex = writerIndex.load(std::memory_order_relaxed);
const auto newWriterIndex = GetNextIndex(oldWriterIndex);
// Is the queue full?
if(newWriterIndex == readerIndex.load(std::memory_order_acquire))
{
return false;
}
buffer[oldWriterIndex] = value;
writerIndex.store(newWriterIndex, std::memory_order_release);
return true;
}
/**
* @brief Pops an element from the queue, and returns true if successful.
* @param value
* @return true if the queue isn't empty, false otherwise.
*/
bool Pop(T& value)
{
const auto oldWriterIndex = writerIndex.load(std::memory_order_acquire);
const auto oldReaderIndex = readerIndex.load(std::memory_order_relaxed);
// Is the queue empty?
if(oldWriterIndex == oldReaderIndex)
{
return false;
}
value = std::move(buffer[oldReaderIndex]);
readerIndex.store(GetNextIndex(oldReaderIndex), std::memory_order_release);
return true;
}
/**
* @brief Returns the number of elements that the queue can hold.
* @return
*/
constexpr size_t Capacity() const { return Length; }
private:
static constexpr size_t GetNextIndex(size_t pos) noexcept
{
return (++pos == bufferSize)? 0 : pos;
}
static constexpr size_t bufferSize = Length + 1;
std::array<T, bufferSize> buffer;
std::atomic<size_t> writerIndex{0};
std::atomic<size_t> readerIndex{0};
};
}
#endif /* SOURCE_UTIL_SIMPLESAFEQUEUE_H_ */
|