template<typename T> class LockFreeStack { private: struct Node { std::shared_ptr<T> data; Node* next; Node(T const& value): data(std::make_shared<T>(value)) {} }; std::atomic<Node*> head; std::atomic<size_t> threadsInPopCount; std::atomic<Node*> toBeDeletedChainHead; static void deleteNodes(Node* nodes) { while(nodes != nullptr){ auto const next = nodes->next; delete nodes; nodes = next; } } void tryReclaim(Node* oldHead) { // If only this thread in the pop. if (threadsInPopCount == 1) { auto toBeDeletedList = toBeDeletedChainHead.exchange(nullptr); // Now, if only this thread in the pop. if (--threadsInPopCount == 0){ deleteNodes(toBeDeletedList); } // If some nodes to be deleted still waiting. else if (toBeDeletedList != nullptr){ pushListToDelChain(toBeDeletedList); } delete oldHead; } else{ // If more than one thread in the pop. pushNodeToDelChain(oldHead); --threadsInPopCount; } } void pushListToDelChain(Node* nodes) { auto last = nodes; while (auto const next = last->next) { last = next; } pushListToDelChain(nodes, last); } void pushListToDelChain(Node* first, Node* last) { last->next = toBeDeletedChainHead; // Put current head of delete chain to the next of the last. // Then let the first be the head. while(!toBeDeletedChainHead.compare_exchange_weak(last->next, first)); } void pushNodeToDelChain(Node* node) { pushListToDelChain(node, node); } public: void push(T const& value) { auto const newNode = new Node(value); newNode->next = head.load(); while (!head.compare_exchange_weak(newNode, newNode->next)); } std::shared_ptr<T> pop() { ++threadsInPopCount; auto oldHead = head.load(); while(oldHead && !head.compare_exchange_weak(oldHead, oldHead->next)); std::shared_ptr<T> result; if (oldHead){ result.swap(oldHead->data); } tryReclaim(oldHead); return result; } };
时间: 2024-10-26 15:30:31