1 /*** 2 This file is part of snapcast 3 Copyright (C) 2014-2020 Johannes Pohl 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 ***/ 18 19 #ifndef QUEUE_H 20 #define QUEUE_H 21 22 #include <atomic> 23 #include <condition_variable> 24 #include <deque> 25 #include <mutex> 26 #include <thread> 27 28 template <typename T> 29 class Queue 30 { 31 public: pop()32 T pop() 33 { 34 std::unique_lock<std::mutex> mlock(mutex_); 35 while (queue_.empty()) 36 cond_.wait(mlock); 37 38 // std::lock_guard<std::mutex> lock(mutex_); 39 auto val = queue_.front(); 40 queue_.pop_front(); 41 return val; 42 } 43 abort_wait()44 void abort_wait() 45 { 46 { 47 std::lock_guard<std::mutex> mlock(mutex_); 48 abort_ = true; 49 } 50 cond_.notify_one(); 51 } 52 wait_for(const std::chrono::microseconds & timeout)53 bool wait_for(const std::chrono::microseconds& timeout) const 54 { 55 std::unique_lock<std::mutex> mlock(mutex_); 56 abort_ = false; 57 if (!cond_.wait_for(mlock, timeout, [this] { return (!queue_.empty() || abort_); })) 58 return false; 59 60 return !queue_.empty() && !abort_; 61 } 62 63 bool try_pop(T& item, const std::chrono::microseconds& timeout = std::chrono::microseconds(0)) 64 { 65 std::unique_lock<std::mutex> mlock(mutex_); 66 abort_ = false; 67 if (timeout.count() > 0) 68 { 69 if (!cond_.wait_for(mlock, timeout, [this] { return (!queue_.empty() || abort_); })) 70 return false; 71 } 72 73 if (queue_.empty() || abort_) 74 return false; 75 76 item = std::move(queue_.front()); 77 queue_.pop_front(); 78 79 return true; 80 } 81 pop(T & item)82 void pop(T& item) 83 { 84 std::unique_lock<std::mutex> mlock(mutex_); 85 while (queue_.empty()) 86 cond_.wait(mlock); 87 88 item = queue_.front(); 89 queue_.pop_front(); 90 } 91 push_front(const T & item)92 void push_front(const T& item) 93 { 94 { 95 std::lock_guard<std::mutex> mlock(mutex_); 96 queue_.push_front(item); 97 } 98 cond_.notify_one(); 99 } 100 back_copy(T & copy)101 bool back_copy(T& copy) 102 { 103 std::lock_guard<std::mutex> mlock(mutex_); 104 if (queue_.empty()) 105 return false; 106 copy = queue_.back(); 107 return true; 108 } 109 front_copy(T & copy)110 bool front_copy(T& copy) 111 { 112 std::lock_guard<std::mutex> mlock(mutex_); 113 if (queue_.empty()) 114 return false; 115 copy = queue_.front(); 116 return true; 117 } 118 push_front(T && item)119 void push_front(T&& item) 120 { 121 { 122 std::lock_guard<std::mutex> mlock(mutex_); 123 queue_.push_front(std::move(item)); 124 } 125 cond_.notify_one(); 126 } 127 push(const T & item)128 void push(const T& item) 129 { 130 { 131 std::lock_guard<std::mutex> mlock(mutex_); 132 queue_.push_back(item); 133 } 134 cond_.notify_one(); 135 } 136 push(T && item)137 void push(T&& item) 138 { 139 { 140 std::lock_guard<std::mutex> mlock(mutex_); 141 queue_.push_back(std::move(item)); 142 } 143 cond_.notify_one(); 144 } 145 size()146 size_t size() const 147 { 148 std::lock_guard<std::mutex> mlock(mutex_); 149 return queue_.size(); 150 } 151 empty()152 bool empty() const 153 { 154 return (size() == 0); 155 } 156 157 Queue() = default; 158 Queue(const Queue&) = delete; // disable copying 159 Queue& operator=(const Queue&) = delete; // disable assignment 160 161 private: 162 std::deque<T> queue_; 163 mutable std::atomic<bool> abort_; 164 mutable std::mutex mutex_; 165 mutable std::condition_variable cond_; 166 }; 167 168 169 #endif 170