2017-03-25 19:18:25 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-03-25 20:32:44 +00:00
|
|
|
#include <optional.h>
|
|
|
|
|
2017-03-25 19:18:25 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <queue>
|
|
|
|
#include <mutex>
|
|
|
|
#include <condition_variable>
|
|
|
|
|
2017-03-25 20:32:44 +00:00
|
|
|
// TODO: cleanup includes.
|
|
|
|
|
2017-03-25 19:18:25 +00:00
|
|
|
|
|
|
|
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
|
|
|
template <class T>
|
|
|
|
class ThreadedQueue {
|
|
|
|
public:
|
2017-04-20 05:46:10 +00:00
|
|
|
// Add an element to the front of the queue.
|
|
|
|
void PriorityEnqueue(T&& t) {
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
priority_.push(std::move(t));
|
|
|
|
cv_.notify_one();
|
|
|
|
}
|
|
|
|
|
2017-03-25 19:18:25 +00:00
|
|
|
// Add an element to the queue.
|
2017-04-08 06:45:28 +00:00
|
|
|
void Enqueue(T&& t) {
|
2017-03-25 19:18:25 +00:00
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
2017-04-08 06:45:28 +00:00
|
|
|
queue_.push(std::move(t));
|
2017-03-25 19:18:25 +00:00
|
|
|
cv_.notify_one();
|
|
|
|
}
|
|
|
|
|
2017-04-16 21:49:48 +00:00
|
|
|
// Return all elements in the queue.
|
|
|
|
std::vector<T> DequeueAll() {
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
|
|
|
|
std::vector<T> result;
|
2017-04-20 05:46:10 +00:00
|
|
|
result.reserve(priority_.size() + queue_.size());
|
|
|
|
while (!priority_.empty()) {
|
|
|
|
result.emplace_back(std::move(priority_.front()));
|
|
|
|
priority_.pop();
|
|
|
|
}
|
2017-04-16 21:49:48 +00:00
|
|
|
while (!queue_.empty()) {
|
|
|
|
result.emplace_back(std::move(queue_.front()));
|
|
|
|
queue_.pop();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-03-25 19:18:25 +00:00
|
|
|
// Get the "front"-element.
|
2017-03-25 20:32:44 +00:00
|
|
|
// If the queue is empty, wait untill an element is avaiable.
|
2017-03-25 19:18:25 +00:00
|
|
|
T Dequeue() {
|
|
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
2017-04-20 05:46:10 +00:00
|
|
|
while (priority_.empty() && queue_.empty()) {
|
2017-03-25 19:18:25 +00:00
|
|
|
// release lock as long as the wait and reaquire it afterwards.
|
|
|
|
cv_.wait(lock);
|
|
|
|
}
|
2017-04-08 06:45:28 +00:00
|
|
|
|
2017-04-20 05:46:10 +00:00
|
|
|
if (!priority_.empty()) {
|
|
|
|
auto val = std::move(priority_.front());
|
|
|
|
priority_.pop();
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2017-04-08 06:45:28 +00:00
|
|
|
auto val = std::move(queue_.front());
|
2017-03-25 19:18:25 +00:00
|
|
|
queue_.pop();
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2017-03-25 20:32:44 +00:00
|
|
|
// Get the first element from the queue without blocking. Returns a null
|
|
|
|
// value if the queue is empty.
|
2017-03-25 19:18:25 +00:00
|
|
|
optional<T> TryDequeue() {
|
2017-04-16 21:49:48 +00:00
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
2017-04-20 05:46:10 +00:00
|
|
|
if (priority_.empty() && queue_.empty())
|
2017-03-25 19:18:25 +00:00
|
|
|
return nullopt;
|
|
|
|
|
2017-04-20 05:46:10 +00:00
|
|
|
if (!priority_.empty()) {
|
|
|
|
auto val = std::move(priority_.front());
|
|
|
|
priority_.pop();
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2017-04-08 06:45:28 +00:00
|
|
|
auto val = std::move(queue_.front());
|
2017-03-25 19:18:25 +00:00
|
|
|
queue_.pop();
|
2017-04-14 22:30:33 +00:00
|
|
|
return std::move(val);
|
2017-03-25 19:18:25 +00:00
|
|
|
}
|
|
|
|
|
2017-03-25 20:32:44 +00:00
|
|
|
private:
|
2017-04-20 05:46:10 +00:00
|
|
|
std::queue<T> priority_;
|
2017-03-25 19:18:25 +00:00
|
|
|
std::queue<T> queue_;
|
|
|
|
mutable std::mutex mutex_;
|
|
|
|
std::condition_variable cv_;
|
|
|
|
};
|