LibQuicR
safe_queue.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) 2024 Cisco Systems
2 // SPDX-License-Identifier: BSD-2-Clause
3 
4 #pragma once
5 
6 #include <atomic>
7 #include <condition_variable>
8 #include <iostream>
9 #include <mutex>
10 #include <optional>
11 #include <queue>
12 
13 namespace quicr {
14 
24  template<typename T>
25  class SafeQueue
26  {
27  public:
33  SafeQueue(uint32_t limit = 5'000)
34  : stop_waiting_{ false }
35  , limit_{ limit }
36  {
37  }
38 
42 
53  bool Push(T const& elem)
54  {
55  bool rval = true;
56 
57  std::lock_guard<std::mutex> _(mutex_);
58 
59  if (queue_.empty()) {
60  cv_.notify_one();
61  empty_ = false;
62  }
63 
64  else if (limit_ != 0 && queue_.size() >= limit_) { // Make room by removing first element
65  queue_.pop();
66  rval = false;
67  }
68 
69  queue_.push(elem);
70 
71  return rval;
72  }
73 
80  bool Push(T&& elem)
81  {
82  bool rval = true;
83 
84  std::lock_guard<std::mutex> _(mutex_);
85 
86  if (queue_.empty()) {
87  cv_.notify_one();
88  empty_ = false;
89  }
90 
91  else if (limit_ != 0 && queue_.size() >= limit_) { // Make room by removing first element
92  queue_.pop();
93  rval = false;
94  }
95 
96  queue_.emplace(std::move(elem));
97 
98  return rval;
99  }
100 
107  std::optional<T> Pop()
108  {
109  std::lock_guard<std::mutex> _(mutex_);
110  return PopInternal();
111  }
112 
119  std::optional<T> Front()
120  {
121  std::lock_guard<std::mutex> _(mutex_);
122 
123  if (queue_.empty()) {
124  return std::nullopt;
125  }
126 
127  return queue_.front();
128  }
129 
133  void PopFront()
134  {
135  std::lock_guard<std::mutex> _(mutex_);
136 
137  PopFrontInternal();
138  }
139 
150  std::optional<T> BlockPop()
151  {
152  std::unique_lock<std::mutex> lock(mutex_);
153  cv_.wait(lock, [&]() { return (stop_waiting_ || (queue_.size() > 0)); });
154 
155  if (stop_waiting_) {
156  return std::nullopt;
157  }
158 
159  return PopInternal();
160  }
161 
167  size_t Size()
168  {
169  std::lock_guard<std::mutex> _(mutex_);
170  return queue_.size();
171  }
172 
177  void Clear()
178  {
179  std::lock_guard<std::mutex> _(mutex_);
180  std::queue<T> empty;
181  std::swap(queue_, empty);
182  empty_ = true;
183  }
184 
190  bool Empty() const { return empty_; }
191 
196  void StopWaiting()
197  {
198  std::lock_guard<std::mutex> _(mutex_);
199  stop_waiting_ = true;
200  cv_.notify_all();
201  }
202 
209  void SetLimit(uint32_t limit)
210  {
211  std::lock_guard<std::mutex> _(mutex_);
212  limit_ = limit;
213  }
214 
215  private:
223  std::optional<T> PopInternal()
224  {
225  if (queue_.empty()) {
226  empty_ = true;
227  return std::nullopt;
228  }
229 
230  auto elem = queue_.front();
231  queue_.pop();
232 
233  if (queue_.empty()) {
234  empty_ = true;
235  }
236 
237  return elem;
238  }
239 
245  void PopFrontInternal()
246  {
247  if (queue_.empty()) {
248  empty_ = true;
249  return;
250  }
251 
252  queue_.pop();
253 
254  if (queue_.empty()) {
255  empty_ = true;
256  }
257  }
258 
259  std::atomic<bool> empty_{ true };
260  bool stop_waiting_; // Instruct threads to stop waiting
261  uint32_t limit_; // Limit of number of messages in queue
262  std::condition_variable cv_; // Signaling for thread syncronization
263  std::mutex mutex_; // read/write lock
264  std::queue<T> queue_; // Queue
265  };
266 
267 } /* namespace quicr */
Thread-safe FIFO queue with optional bounded, drop-oldest insertion.
Definition: safe_queue.h:26
bool Push(T &&elem)
Moves an element to the back, evicting the oldest element when at a nonzero limit.
Definition: safe_queue.h:80
bool Push(T const &elem)
Copies an element to the back of the queue.
Definition: safe_queue.h:53
~SafeQueue()
Wakes current waiters before destroying the queue; callers must ensure no operation remains active.
Definition: safe_queue.h:41
bool Empty() const
Check if queue is empty.
Definition: safe_queue.h:190
void StopWaiting()
Permanently causes current and future BlockPop() calls to return without waiting.
Definition: safe_queue.h:196
SafeQueue(uint32_t limit=5 '000)
Constructs an empty queue.
Definition: safe_queue.h:33
void SetLimit(uint32_t limit)
Changes the maximum retained element count.
Definition: safe_queue.h:209
void PopFront()
Removes the oldest object, or does nothing when empty.
Definition: safe_queue.h:133
void Clear()
Removes all elements without changing the limit or stopped-waiting state.
Definition: safe_queue.h:177
std::optional< T > Front()
Get first object without removing from queue.
Definition: safe_queue.h:119
std::optional< T > BlockPop()
Block waiting for data in queue, then remove the first object from queue (oldest object)
Definition: safe_queue.h:150
std::optional< T > Pop()
Remove the first object from queue (oldest object)
Definition: safe_queue.h:107
size_t Size()
Size of the queue.
Definition: safe_queue.h:167
Definition: attributes.h:13