这个队列的实现基本正确,但是有几个需要优化的地方:
1.内存池的大小应该是动态的,而不是固定的。可以在构造函数中传入一个参数作为内存池大小。
2.在pop操作时,并没有考虑队列为空的情况,应该加上判断。
3.push操作可以使用load-linked/store-conditional指令替换掉relaxed顺序,使得push操作更加高效。
修改后的代码如下:
#include <atomic>
#include <iostream>
#include "terra_memory_pool.h"
template <typename T>
class LockFreeQueue {
public:
explicit LockFreeQueue(const size_t& pool_size = sizeof(Node) * 100)
: head_(new Node), tail_(head_.load()), size_{0}, capacity_{pool_size}, memory_pool_(capacity_) {}
~LockFreeQueue() {
while (Node *const old_head = head_) {
Node *next_node = old_head->value_.second;
delete old_head;
head_ = next_node;
}
}
void push(const T &value) {
Node *new_node;
while (true) {
if ((new_node = static_cast<Node *>(memory_pool_.Alloc(sizeof(Node)))) == nullptr) {
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
return;
}
new (new_node) Node(std::make_pair(value, nullptr));
Node *tail = tail_.load(std::memory_order_acquire);
Node *next = tail->value_.second;
if (tail == tail_.load(std::memory_order_relaxed)) {
if (next == nullptr) {
Node *empty = nullptr;
if (tail->value_.second.compare_exchange_weak(empty, new_node)) {
tail_.compare_exchange_strong(tail, new_node);
size_.fetch_add(1, std::memory_order_release);
return;
}
} else {
tail_.compare_exchange_strong(tail, next);
}
}
}
}
bool try_pop(T &value) {
Node *old_head = head_.load(std::memory_order_relaxed);
while (true) {
Node *head = old_head;
Node *tail = tail_.load(std::memory_order_acquire);
Node *next = head->value_.second;
if (head == head_.load(std::memory_order_relaxed)) {
if (head == tail) {
if (next == nullptr) {
return false;
}
tail_.compare_exchange_strong(tail, next);
} else {
value = next->value_.first;
if (head_.compare_exchange_weak(head, next)) {
memory_pool_.Free(old_head, sizeof(Node));
size_.fetch_sub(1, std::memory_order_release);
return true;
}
}
}
old_head = head_.load(std::memory_order_relaxed);
}
}
bool empty() const { return size_.load(std::memory_order_acquire) == 0; }
private:
struct Node {
std::pair<T, Node *> value_;
Node() : value_(std::make_pair(T(), nullptr)) {}
explicit Node(const std::pair<T, Node *> &value) : value_(value) {}
};
std::atomic<Node *> head_;
std::atomic<Node *> tail_;
std::atomic<size_t> size_;
size_t capacity_;
terra_memory_pool memory_pool_;
};