#pragma once /* Thread safe queue (with fine grain locks). Based on the book by Williams. No wait_and_pop. */ #include #include template class queue { private: struct node { std::shared_ptr data; std::unique_ptr next; }; std::mutex head_mutex; std::unique_ptr head; std::mutex tail_mutex; node* tail; node* get_tail(){ std::lock_guard lock(tail_mutex); return tail; } std::unique_ptr pop_head(){ std::lock_guard lock(head_mutex); if(head.get() == get_tail()){ return nullptr; } std::unique_ptr 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 try_pop(){ std::unique_ptr old_head = pop_head(); return old_head ? old_head->data : nullptr; } void push(T value){ auto new_data = std::make_shared(std::move(value)); std::unique_ptr p(new node); node* const new_tail = p.get(); std::lock_guard lock(tail_mutex); tail->data = new_data; tail->next = std::move(p); tail = new_tail; } };