You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
1.2 KiB
67 lines
1.2 KiB
#pragma once
|
|
|
|
/* Thread safe queue (with fine grain locks).
|
|
Based on the book by Williams.
|
|
No wait_and_pop.
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
template <typename T>
|
|
class queue {
|
|
private:
|
|
struct node {
|
|
std::shared_ptr<T> data;
|
|
std::unique_ptr<node> next;
|
|
};
|
|
|
|
std::mutex head_mutex;
|
|
std::unique_ptr<node> head;
|
|
|
|
std::mutex tail_mutex;
|
|
node* tail;
|
|
|
|
node* get_tail(){
|
|
std::lock_guard<std::mutex> lock(tail_mutex);
|
|
return tail;
|
|
}
|
|
|
|
std::unique_ptr<node> pop_head(){
|
|
std::lock_guard<std::mutex> lock(head_mutex);
|
|
|
|
if(head.get() == get_tail()){
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<node> old_head = std::move(head);
|
|
head = std::move(old_head->next);
|
|
return old_head;
|
|
}
|
|
|
|
public:
|
|
queue()
|
|
: head(new node)
|
|
, tail(head.get())
|
|
{}
|
|
|
|
queue(const queue &) = delete;
|
|
queue& operator=(const queue &) = delete;
|
|
|
|
std::shared_ptr<T> try_pop(){
|
|
std::unique_ptr<node> old_head = pop_head();
|
|
return old_head ? old_head->data : nullptr;
|
|
}
|
|
|
|
void push(T value){
|
|
auto new_data = std::make_shared<T>(std::move(value));
|
|
std::unique_ptr<node> p(new node);
|
|
|
|
node* const new_tail = p.get();
|
|
std::lock_guard<std::mutex> lock(tail_mutex);
|
|
|
|
tail->data = new_data;
|
|
tail->next = std::move(p);
|
|
tail = new_tail;
|
|
}
|
|
};
|
|
|