anjana_sreekumar@infosys.com | 991c206 | 2020-01-08 11:42:57 +0530 | [diff] [blame^] | 1 | /* |
| 2 | * This code is in public domain. |
| 3 | * Implementation and its platform dependent issues discussed in |
| 4 | * https://kjellkod.wordpress.com/2012/11/28/c-debt-paid-in-full-wait-free-lock-free-queue/ |
| 5 | */ |
| 6 | |
| 7 | #ifndef INCLUDE_CMN_CIRCULARFIFO_H_ |
| 8 | #define INCLUDE_CMN_CIRCULARFIFO_H_ |
| 9 | |
| 10 | #include <atomic> |
| 11 | #include <cstddef> |
| 12 | |
| 13 | namespace cmn { |
| 14 | namespace utils { |
| 15 | template<typename Element, size_t Size> |
| 16 | class CircularFifo |
| 17 | { |
| 18 | public: |
| 19 | enum { Capacity = Size + 1 }; |
| 20 | |
| 21 | CircularFifo() : _tail(0), _head(0){} |
| 22 | virtual ~CircularFifo() {} |
| 23 | |
| 24 | bool push(Element* item); |
| 25 | bool pop(Element*& item); |
| 26 | |
| 27 | bool wasEmpty() const; |
| 28 | bool wasFull() const; |
| 29 | bool isLockFree() const; |
| 30 | |
| 31 | private: |
| 32 | size_t increment(size_t idx) const; |
| 33 | |
| 34 | std::atomic <size_t> _tail; |
| 35 | Element* _array[Capacity]; |
| 36 | std::atomic<size_t> _head; |
| 37 | }; |
| 38 | |
| 39 | template<typename Element, size_t Size> |
| 40 | bool CircularFifo<Element, Size>::push(Element* item) |
| 41 | { |
| 42 | const auto current_tail = _tail.load(std::memory_order_relaxed); |
| 43 | const auto next_tail = increment(current_tail); |
| 44 | if(next_tail != _head.load(std::memory_order_acquire)) |
| 45 | { |
| 46 | _array[current_tail] = item; |
| 47 | _tail.store(next_tail, std::memory_order_release); |
| 48 | return true; |
| 49 | } |
| 50 | |
| 51 | return false; |
| 52 | } |
| 53 | |
| 54 | template<typename Element, size_t Size> |
| 55 | bool CircularFifo<Element, Size>::pop(Element*& item) |
| 56 | { |
| 57 | const auto current_head = _head.load(std::memory_order_relaxed); |
| 58 | if(current_head == _tail.load(std::memory_order_acquire)) |
| 59 | return false; |
| 60 | |
| 61 | item = _array[current_head]; |
| 62 | _head.store(increment(current_head), std::memory_order_release); |
| 63 | return true; |
| 64 | } |
| 65 | |
| 66 | template<typename Element, size_t Size> |
| 67 | bool CircularFifo<Element, Size>::wasEmpty() const |
| 68 | { |
| 69 | return (_head.load() == _tail.load()); |
| 70 | } |
| 71 | |
| 72 | template<typename Element, size_t Size> |
| 73 | bool CircularFifo<Element, Size>::wasFull() const |
| 74 | { |
| 75 | const auto next_tail = increment(_tail.load()); |
| 76 | return (next_tail == _head.load()); |
| 77 | } |
| 78 | |
| 79 | template<typename Element, size_t Size> |
| 80 | bool CircularFifo<Element, Size>::isLockFree() const |
| 81 | { |
| 82 | return (_tail.is_lock_free() && _head.is_lock_free()); |
| 83 | } |
| 84 | |
| 85 | template<typename Element, size_t Size> |
| 86 | size_t CircularFifo<Element, Size>::increment(size_t idx) const |
| 87 | { |
| 88 | return (idx + 1) % Capacity; |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | |
| 94 | #endif /* INCLUDE_CMN_CIRCULARFIFO_H_ */ |