void push(stored_ptr &&new_data) { counted_node_ptr new_next{ 1, allocate_node() }; counted_node_ptr old_tail = tail.load(); for (;;) { increase_external_count(tail, old_tail); T* old_data = nullptr; if (old_tail.get()->data.compare_exchange_strong(old_data, new_data.get())) { counted_node_ptr old_next = { 0, nullptr }; if (!old_tail.get()->next.compare_exchange_strong(old_next, new_next)) { deallocate_node(new_next.get()); new_next = old_next; } set_new_tail(old_tail, new_next); new_data.release(); break; } else { counted_node_ptr old_next = { 0, nullptr }; if (old_tail.get()->next.compare_exchange_strong(old_next, new_next)) { old_next = new_next; new_next.set(allocate_node()); } set_new_tail(old_tail, old_next); } } }
stored_ptr pop() { counted_node_ptr old_head = head.load(std::memory_order_relaxed); for (;;) { increase_external_count(head, old_head); node * const ptr = old_head.get(); if (ptr == tail.load().get()) return nullptr; counted_node_ptr next = ptr->next.load(); if (head.compare_exchange_strong(old_head, next)) { T * const res = ptr->data.exchange(nullptr); free_external_counter(old_head); return stored_ptr(res); } if (!ptr->release_ref()) deallocate_node(ptr); } }
std::unique_ptr<T> pop() { counted_node_ptr old_head=head.load(std::memory_order_relaxed); for(;;) { increase_external_count(head,old_head); node* const ptr=old_head.ptr; if(ptr==tail.load().ptr) { return std::unique_ptr<T>(); } counted_node_ptr next=ptr->next.load(); if(head.compare_exchange_strong(old_head,next)) { T* const res=ptr->data.exchange(nullptr); free_external_counter(old_head); return std::unique_ptr<T>(res); } ptr->release_ref(); } }