17#ifndef RESONANCE_AUDIO_UTILS_SEMI_LOCKLESS_FIFO_H_
18#define RESONANCE_AUDIO_UTILS_SEMI_LOCKLESS_FIFO_H_
22#include <condition_variable>
26#include "base/logging.h"
36template <
typename DataType>
39 typedef std::chrono::steady_clock::duration ClockDuration;
48 void PushBack(DataType&& input);
72 bool SleepUntilBelowSizeTarget(
size_t target_size,
73 const ClockDuration& max_wait);
84 bool SleepUntilNumElementsInQueue(
size_t target_size,
85 const ClockDuration& max_wait);
89 void EnableBlockingSleepUntilMethods(
bool enable);
94 Node() : next(
nullptr) {}
95 std::atomic<Node*> next;
106 std::atomic<size_t> fifo_size_;
109 std::mutex push_mutex_;
112 std::condition_variable pop_conditional_;
115 std::mutex pop_conditional_mutex_;
118 std::condition_variable push_conditional_;
121 std::mutex push_conditional_mutex_;
124 std::atomic<bool> enable_sleeping_;
127template <
typename DataType>
129 : fifo_size_(0), enable_sleeping_(true) {
130 head_ = tail_ =
new Node();
133template <
typename DataType>
134SemiLocklessFifo<DataType>::~SemiLocklessFifo() {
136 DCHECK_EQ(head_, tail_);
137 DCHECK(head_->next.load() ==
nullptr);
141template <
typename DataType>
142void SemiLocklessFifo<DataType>::PushBack(DataType&& input) {
143 std::lock_guard<std::mutex> lock(push_mutex_);
144 tail_->data = std::move(input);
145 Node*
const new_node =
new Node();
146 DCHECK(tail_->next.load() ==
nullptr);
147 tail_->next = new_node;
155 std::lock_guard<std::mutex> lock(push_conditional_mutex_);
157 push_conditional_.notify_all();
160template <
typename DataType>
161DataType SemiLocklessFifo<DataType>::PopFront() {
164 Node*
const front_node = head_;
165 head_ = front_node->next;
167 DataType output = std::move(front_node->data);
170 DCHECK_GT(fifo_size_.load(), 0u);
177 std::lock_guard<std::mutex> lock(pop_conditional_mutex_);
179 pop_conditional_.notify_one();
183template <
typename DataType>
184bool SemiLocklessFifo<DataType>::Empty()
const {
185 return fifo_size_.load() == 0;
188template <
typename DataType>
189void SemiLocklessFifo<DataType>::Clear() {
193 DCHECK_EQ(fifo_size_, 0u);
196template <
typename DataType>
197bool SemiLocklessFifo<DataType>::SleepUntilBelowSizeTarget(
198 size_t target_size,
const ClockDuration& max_wait) {
199 DCHECK_GT(target_size, 0);
200 std::unique_lock<std::mutex> lock(pop_conditional_mutex_);
201 pop_conditional_.wait_for(lock, max_wait, [
this, target_size]() {
202 return fifo_size_ < target_size || !enable_sleeping_.load();
204 return fifo_size_ < target_size;
207template <
typename DataType>
208bool SemiLocklessFifo<DataType>::SleepUntilNumElementsInQueue(
209 size_t target_size,
const ClockDuration& max_wait) {
210 DCHECK_GT(target_size, 0u);
211 std::unique_lock<std::mutex> lock(push_conditional_mutex_);
212 push_conditional_.wait_for(lock, max_wait, [
this, target_size]() {
213 return fifo_size_ >= target_size || !enable_sleeping_.load();
215 return fifo_size_ >= target_size;
218template <
typename DataType>
219void SemiLocklessFifo<DataType>::EnableBlockingSleepUntilMethods(
bool enable) {
220 enable_sleeping_ = enable;
224 { std::lock_guard<std::mutex> lock(pop_conditional_mutex_); }
225 { std::lock_guard<std::mutex> lock(push_conditional_mutex_); }
226 pop_conditional_.notify_one();
227 push_conditional_.notify_one();
Definition semi_lockless_fifo.h:37