arduino-audio-tools
QueueLockFree.h
1 
2 #pragma once
3 #include <stdint.h>
4 
5 #include <atomic>
6 #include <cstddef>
7 
8 namespace audio_tools {
9 
13 template <typename T>
15  public:
16  QueueLockFree(size_t capacity, Allocator& allocator = DefaultAllocator) {
17  setAllocator(allocator);
18  resize(capacity);
19  }
20 
21  ~QueueLockFree() {
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)
33  capacity_mask |= capacity_mask >> i;
34  capacity_value = capacity_mask + 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  bool empty() { return size() == 0;}
51 
52  size_t size() const {
53  size_t head = head_pos.load(std::memory_order_acquire);
54  return tail_pos.load(std::memory_order_relaxed) - head;
55  }
56 
57  bool enqueue(const T&& data) {
58  return enqueue(data);
59  }
60 
61  bool enqueue(const T& data) {
62  Node* node;
63  size_t tail = tail_pos.load(std::memory_order_relaxed);
64  for (;;) {
65  node = &p_node[tail & capacity_mask];
66  if (node->tail.load(std::memory_order_relaxed) != tail) return false;
67  if ((tail_pos.compare_exchange_weak(tail, tail + 1,
68  std::memory_order_relaxed)))
69  break;
70  }
71  new (&node->data) T(data);
72  node->head.store(tail, std::memory_order_release);
73  return true;
74  }
75 
76  bool dequeue(T& result) {
77  Node* node;
78  size_t head = head_pos.load(std::memory_order_relaxed);
79  for (;;) {
80  node = &p_node[head & capacity_mask];
81  if (node->head.load(std::memory_order_relaxed) != head) return false;
82  if (head_pos.compare_exchange_weak(head, head + 1,
83  std::memory_order_relaxed))
84  break;
85  }
86  result = node->data;
87  (&node->data)->~T();
88  node->tail.store(head + capacity_value, std::memory_order_release);
89  return true;
90  }
91 
92  void clear() {
93  T tmp;
94  while (dequeue(tmp));
95  }
96 
97  protected:
98  struct Node {
99  T data;
100  std::atomic<size_t> tail;
101  std::atomic<size_t> head;
102  };
103 
104  Node* p_node = nullptr;
105  size_t capacity_mask;
106  size_t capacity_value;
107  std::atomic<size_t> tail_pos;
108  std::atomic<size_t> head_pos;
109  Vector<Node> vector;
110 };
111 } // namespace audio_tools
Memory allocateator which uses malloc.
Definition: Allocator.h:22
A simple single producer, single consumer lock free queue.
Definition: QueueLockFree.h:14
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:859
Definition: QueueLockFree.h:98