54 struct counted_node_ptr {
55 int external_count = 0;
61 counted_node_ptr()
noexcept {}
79 explicit node(
int external_count = 2) {
80 node_counter new_count;
81 new_count.internal_count = 0;
82 new_count.external_counters = external_count;
83 count.store(new_count);
85 counted_node_ptr node_ptr;
86 node_ptr.ptr =
nullptr;
87 node_ptr.external_count = 0;
99 node_counter new_counter;
101 new_counter = old_counter;
102 --new_counter.internal_count;
104 while (!
count.compare_exchange_strong(
105 old_counter, new_counter,
107 if (!new_counter.internal_count && !new_counter.external_counters) {
109 destruct_count.fetch_add(1);
131 void set_new_tail(counted_node_ptr& old_tail, counted_node_ptr
const& new_tail) {
132 node*
const current_tail_ptr = old_tail.ptr;
133 while (!tail.compare_exchange_weak(old_tail, new_tail) &&
134 old_tail.ptr == current_tail_ptr) {
135 this_thread::relax();
137 if (old_tail.ptr == current_tail_ptr) {
138 lock_free_queue::free_external_counter(old_tail);
140 current_tail_ptr->release_ref();
151 static void free_external_counter(counted_node_ptr& old_node_ptr) {
152 node*
const ptr = old_node_ptr.ptr;
153 int const count_increase = old_node_ptr.external_count - 2;
155 node_counter new_counter;
157 new_counter = old_counter;
158 --new_counter.external_counters;
159 new_counter.internal_count += count_increase;
162 old_counter, new_counter,
164 if (!new_counter.internal_count && !new_counter.external_counters) {
165 destruct_count.fetch_add(1);
178 static void increase_external_count(
180 counted_node_ptr& old_counter) {
181 counted_node_ptr new_counter;
183 new_counter = old_counter;
184 ++new_counter.external_count;
186 old_counter, new_counter,
188 old_counter.external_count = new_counter.external_count;
198 counted_node_ptr new_next;
199 new_next.ptr =
new node();
200 new_next.external_count = 1;
201 tail.store(new_next);
202 head.store(new_next);
211 while (
pop()) { this_thread::relax(); }
212 auto head_counted_node = head.load();
213 delete head_counted_node.ptr;
225 counted_node_ptr new_next;
226 new_next.ptr =
new node;
227 new_next.external_count = 1;
228 counted_node_ptr old_tail = tail.load();
230 lock_free_queue::increase_external_count(tail, old_tail);
231 T* old_data =
nullptr;
233 counted_node_ptr old_next;
234 counted_node_ptr now_next = old_tail.ptr->next.
load();
239 this->set_new_tail(old_tail, new_next);
243 counted_node_ptr old_next;
246 new_next.ptr =
new node;
248 this->set_new_tail(old_tail, old_next);
264 lock_free_queue::increase_external_count(head, old_head);
265 node*
const ptr = old_head.ptr;
266 if (ptr == tail.load().ptr) {
270 counted_node_ptr
next = ptr->next.
load();
271 if (head.compare_exchange_strong(old_head,
next)) {
272 T* res = ptr->data.
exchange(
nullptr);
273 lock_free_queue::free_external_counter(old_head);
291 counted_node_ptr old_head{};
293 for (
int retry = 0; retry < 3; ++retry) {
295 lock_free_queue::increase_external_count(head, old_head);
296 node* ptr = old_head.ptr;
298 if (ptr == tail.load().ptr) {
303 counted_node_ptr
next = ptr->next.
load();
304 if (head.compare_exchange_strong(old_head,
next)) {
305 T* res = ptr->data.
exchange(
nullptr);
306 lock_free_queue::free_external_counter(old_head);
327 return head_ptr.ptr == tail_ptr.ptr;
341 return push_cnt - pop_cnt;
357 this_thread::relax();