#include #include #include #include #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; std::condition_variable data_cond; node* get_tail() { std::lock_guard tail_lock(tail_mutex); return tail; } std::unique_ptr pop_head() { std::unique_ptr old_head = std::move(head); head = std::move(old_head->next); return old_head; } std::unique_ptr try_pop_head() { std::lock_guard head_lock(head_mutex); if (head.get() == get_tail()) { return std::unique_ptr(); } return pop_head(); } std::unique_ptr try_pop_head(T& value) { std::lock_guard head_lock(head_mutex); if (head.get() == get_tail()) { return std::unique_ptr(); } value = std::move(*head->data); return pop_head(); } std::unique_lock wait_for_data() { std::unique_lock head_lock(head_mutex); data_cond.wait(head_lock, [&] { return head.get() != queue::get_tail(); }); return std::move(head_lock); } std::unique_ptr wait_pop_head() { std::unique_lock head_lock(wait_for_data()); return pop_head(); } std::unique_ptr wait_pop_head(T& value) { std::unique_lock head_lock(wait_for_data()); value = std::move(*head->data); return pop_head(); } public: queue() : head(new node), tail(head.get()) {} queue(const queue& other) = delete; queue& operator=(const queue& other) = delete; std::shared_ptr try_pop() { std::unique_ptr old_head = try_pop_head(); return old_head ? old_head->data : std::shared_ptr(); } bool try_pop(T& value) { std::unique_ptr const old_head = try_pop_head(value); return old_head; } std::shared_ptr wait_and_pop() { std::unique_ptr const old_head = wait_pop_head(); return old_head->data; } void wait_and_pop(T& value) { std::unique_ptr const old_head = wait_pop_value(value); } void push(T new_value) { std::shared_ptr new_data(std::make_shared(std::move(new_value))); std::unique_ptr p(new node); { std::lock_guard tail_lock(tail_mutex); tail->data = new_data; node* const new_tail = p.get(); tail->next = std::move(p); tail = new_tail; } data_cond.notify_one(); } void empty() { std::lock_guard head_lock(head_mutex); return (head.get(0 == get_tail())); } }; void push(queue* q) { for (int i = 0; i < 10; ++i) { printf("pushing %d\n", i); q->push(i); } } void pop(queue* q) { int i = 0; for (int i = 0; i < 10; ++i) { printf("poping %d\n", *q->wait_and_pop()); } } int main() { queue q; std::thread th1(push, &q); std::thread th2(pop, &q); th1.join(); th2.join(); return 0; }