这个队列在并发情况下可能存在ABA问题,即在操作过程中,某个节点被删除然后重新创建了一个新的同名节点,导致CAS操作无法正确判断节点是否被修改。
为了解决这个问题,可以使用带有引用计数的智能指针std::shared_ptr来代替原来的裸指针,并添加一个计数器来避免ABA问题。
以下是经过优化的代码:
#include <atomic>
#include <iostream>
#include <vector>
#include <memory>
template <typename T>
class LockFreeQueue
{
public:
LockFreeQueue() : head_(new Node), tail_(head_.load()) {}
~LockFreeQueue()
{
while (Node *old_head = head_.load())
{
Node *next = old_head->next_.load(std::memory_order_relaxed);
delete old_head;
head_.store(next, std::memory_order_relaxed);
}
}
void push(const T &value)
{
auto new_node = std::make_shared<Node>(value);
NodePtr tail, next;
while (true)
{
tail = tail_.load();
next = tail->next_.load();
if (tail == tail_.load())
{
if (!next)
{
if (tail->next_.compare_exchange_weak(next, new_node))
{
break;
}
}
else
{
tail_.compare_exchange_strong(tail, next);
}
}
}
tail_.compare_exchange_strong(tail, new_node);
size_.fetch_add(1, std::memory_order_release);
}
bool try_pop(T &value)
{
NodePtr old_head;
while (true)
{
old_head = head_.load();
auto old_count = old_head->count_.load();
NodePtr new_head = old_head->next_.load();
if (old_head == head_.load())
{
if (!new_head)
{
return false;
}
if (head_.compare_exchange_weak(old_head, new_head))
{
value = new_head->value_;
size_.fetch_sub(1, std::memory_order_release);
if (old_count == 1)
{
delete old_head;
}
else
{
old_head->count_.fetch_sub(1);
}
return true;
}
}
else if (old_count == 1)
{
delete old_head;
}
else
{
old_head->count_.fetch_sub(1);
}
}
}
bool empty() const
{
return size_.load(std::memory_order_acquire) == 0;
}
private:
struct alignas(64) Node
{
T value_;
std::atomic<int> count_;
std::shared_ptr<Node> next_;
Node() : value_(T()), count_(0), next_(nullptr) {}
explicit Node(const T &value) : value_(value), count_(0), next_(nullptr) {}
};
using NodePtr = std::shared_ptr<Node>;
std::atomic<NodePtr> head_;
std::atomic<NodePtr> tail_;
std::atomic<size_t> size_{0};
};




