| 134 | // elements are returned in order of dequeue (top to bottom; see example in unittest) |
| 135 | template <typename TCollection> |
| 136 | void DequeueAll(TCollection* res) { |
| 137 | ++DequeueCount; |
| 138 | for (TNode* current = Head.load(std::memory_order_acquire); current;) { |
| 139 | if (Head.compare_exchange_weak(current, nullptr)) { |
| 140 | for (TNode* x = current; x;) { |
| 141 | res->push_back(std::move(x->Value)); |
| 142 | x = x->Next; |
| 143 | } |
| 144 | // EraseList(current); // ABA problem |
| 145 | // even more complex node deletion |
| 146 | TryToFreeMemory(); |
| 147 | if (--DequeueCount == 0) { |
| 148 | // no other Dequeue()s, can safely reclaim memory |
| 149 | EraseList(current); |
| 150 | } else { |
| 151 | // Dequeue()s in progress, add nodes list to free list |
| 152 | TNode* currentLast = current; |
| 153 | while (currentLast->Next) { |
| 154 | currentLast = currentLast->Next; |
| 155 | } |
| 156 | for (TNode* freePtr = FreePtr.load(std::memory_order_acquire);;) { |
| 157 | currentLast->Next.store(freePtr, std::memory_order_release); |
| 158 | if (FreePtr.compare_exchange_weak(freePtr, current)) { |
| 159 | break; |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | return; |
| 164 | } |
| 165 | } |
| 166 | TryToFreeMemory(); |
| 167 | --DequeueCount; |
| 168 | } |
| 169 | bool DequeueSingleConsumer(T* res) { |
| 170 | for (TNode* current = Head.load(std::memory_order_acquire); current;) { |
| 171 | if (Head.compare_exchange_weak(current, current->Next)) { |