Arduino DLNA Server
QueueLockFree.h
Go to the documentation of this file.
1 
2 #pragma once
3 #include <stdint.h>
4 
5 #include <atomic>
6 #include <cstddef>
7 
8 namespace tiny_dlna {
9 
13 template <typename T>
15  public:
16  QueueLockFree(size_t capacity, Allocator& allocator = DefaultAllocator) {
17  setAllocator(allocator);
19  }
20 
22  for (size_t i = head_pos; i != tail_pos; ++i)
23  (&p_node[i & capacity_mask].data)->~T();
24 
25  delete[] (char*)p_node;
26  }
27 
28  void setAllocator(Allocator& allocator) { vector.setAllocator(allocator); }
29 
30  void resize(size_t capacity) {
31  capacity_mask = capacity - 1;
32  for (size_t i = 1; i <= sizeof(void*) * 4; i <<= 1)
35 
36  vector.resize(capacity);
37  p_node = vector.data();
38 
39  for (size_t i = 0; i < capacity; ++i) {
40  p_node[i].tail.store(i, std::memory_order_relaxed);
41  p_node[i].head.store(-1, std::memory_order_relaxed);
42  }
43 
44  tail_pos.store(0, std::memory_order_relaxed);
45  head_pos.store(0, std::memory_order_relaxed);
46  }
47 
48  size_t capacity() const { return capacity_value; }
49 
50  size_t size() const {
51  size_t head = head_pos.load(std::memory_order_acquire);
52  return tail_pos.load(std::memory_order_relaxed) - head;
53  }
54 
55  bool enqueue( T&& data) {
56  return enqueue(data);
57  }
58 
59  bool enqueue( T& data) {
60  Node* node;
61  size_t tail = tail_pos.load(std::memory_order_relaxed);
62  for (;;) {
63  node = &p_node[tail & capacity_mask];
64  if (node->tail.load(std::memory_order_relaxed) != tail) return false;
65  if ((tail_pos.compare_exchange_weak(tail, tail + 1,
66  std::memory_order_relaxed)))
67  break;
68  }
69  new (&node->data) T(data);
70  node->head.store(tail, std::memory_order_release);
71  return true;
72  }
73 
74  bool dequeue(const T&& data) {
75  return dequeue(data);
76  }
77 
78  bool dequeue(T& result) {
79  Node* node;
80  size_t head = head_pos.load(std::memory_order_relaxed);
81  for (;;) {
82  node = &p_node[head & capacity_mask];
83  if (node->head.load(std::memory_order_relaxed) != head) return false;
84  if (head_pos.compare_exchange_weak(head, head + 1,
85  std::memory_order_relaxed))
86  break;
87  }
88  result = node->data;
89  (&node->data)->~T();
90  node->tail.store(head + capacity_value, std::memory_order_release);
91  return true;
92  }
93 
94  void clear() {
95  T tmp;
96  while (dequeue(tmp));
97  }
98 
99  protected:
100  struct Node {
101  T data;
102  std::atomic<size_t> tail;
103  std::atomic<size_t> head;
104  };
105 
109  std::atomic<size_t> tail_pos;
110  std::atomic<size_t> head_pos;
112 };
113 } // namespace audio_tools
Memory allocateator which uses malloc.
Definition: Allocator.h:21
A simple single producer, single consumer lock free queue.
Definition: QueueLockFree.h:14
void clear()
Definition: QueueLockFree.h:94
Vector< Node > vector
Definition: QueueLockFree.h:111
bool dequeue(const T &&data)
Definition: QueueLockFree.h:74
void resize(size_t capacity)
Definition: QueueLockFree.h:30
size_t size() const
Definition: QueueLockFree.h:50
~QueueLockFree()
Definition: QueueLockFree.h:21
size_t capacity() const
Definition: QueueLockFree.h:48
bool enqueue(T &data)
Definition: QueueLockFree.h:59
QueueLockFree(size_t capacity, Allocator &allocator=DefaultAllocator)
Definition: QueueLockFree.h:16
size_t capacity_value
Definition: QueueLockFree.h:108
bool enqueue(T &&data)
Definition: QueueLockFree.h:55
std::atomic< size_t > tail_pos
Definition: QueueLockFree.h:109
size_t capacity_mask
Definition: QueueLockFree.h:107
std::atomic< size_t > head_pos
Definition: QueueLockFree.h:110
bool dequeue(T &result)
Definition: QueueLockFree.h:78
Node * p_node
Definition: QueueLockFree.h:106
void setAllocator(Allocator &allocator)
Definition: QueueLockFree.h:28
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Definition: Allocator.h:6
Definition: QueueLockFree.h:100
std::atomic< size_t > head
Definition: QueueLockFree.h:103
std::atomic< size_t > tail
Definition: QueueLockFree.h:102
T data
Definition: QueueLockFree.h:101