ccls/src/threaded_queue.h

92 lines
2.1 KiB
C
Raw Normal View History

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:
// 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.
void Enqueue(T&& t) {
2017-03-25 19:18:25 +00:00
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(t));
2017-03-25 19:18:25 +00:00
cv_.notify_one();
}
// Return all elements in the queue.
std::vector<T> DequeueAll() {
std::lock_guard<std::mutex> lock(mutex_);
std::vector<T> result;
result.reserve(priority_.size() + queue_.size());
while (!priority_.empty()) {
result.emplace_back(std::move(priority_.front()));
priority_.pop();
}
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_);
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);
}
if (!priority_.empty()) {
auto val = std::move(priority_.front());
priority_.pop();
return val;
}
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() {
std::lock_guard<std::mutex> lock(mutex_);
if (priority_.empty() && queue_.empty())
2017-03-25 19:18:25 +00:00
return nullopt;
if (!priority_.empty()) {
auto val = std::move(priority_.front());
priority_.pop();
return val;
}
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:
std::queue<T> priority_;
2017-03-25 19:18:25 +00:00
std::queue<T> queue_;
mutable std::mutex mutex_;
std::condition_variable cv_;
};