我正在尝试编写一个有效的队列,其中一个线程插入元素,一个线程读取它们。我决定把它写成块的循环列表,其中每个块包含一个元素数组。为了保持效率,我试图避免原子变量和锁。 我无法找到一个原因,为什么在测试期间我的队列最终达到返回的元素不是预期元素的状态。
我用整数测试了这个。用一个线程按顺序插入它们。第二个线程检查队列是否为空,如果不是,则读取一个元素并再次检查其值是否为预期值。
我读了很多关于由编译器优化引起的内存屏障和指令重新排序的内容,但我仍然无法理解为什么它仍然无效。
我将非常感谢任何建议。代码由2个类组成,一个节点和一个队列。
template<typename T> class node {
public:
T *data = nullptr;
unsigned int size = 0;
volatile node *volatile next = nullptr;
volatile int reader = 0;
volatile int writer = 0;
node(unsigned int size = 64) : size(size) {
data = new T[size];
}
~node() {
delete[] data;
}
bool enqueue(T value) volatile {
if (writer < reader) {
return false;
}
data[writer] = value;
writer = (writer + 1) % size;
return true;
}
bool dequeue(T &value) volatile {
value = data[reader];
reader = (reader + 1) % size;
return true;
}
// must be called before every dequeue
bool empty() volatile {
return reader == writer;
}
}; // scroll further down
template <typename U> class queue {
volatile node<U> *volatile reader;
volatile node<U> *volatile writer;
public:
queue() {
writer = new node<U>();
writer->next = writer;
reader = writer;
volatile node<U> *volatile tmp = writer;
for (int i = 0; i < 5; i++) {
tmp->next = new node<U>();
tmp = tmp->next;
}
tmp->next = writer;
}
~queue() {
}
void enqueue(U value) volatile {
if (!writer->enqueue(value)) {
if (writer->next != reader && writer->next->empty()) {
writer = writer->next;
writer->enqueue(value);
} else {
node<U> *volatile n = new node<U>();
n->next = writer->next;;
writer->next = n;
writer = writer->next;
writer->enqueue(value);
}
}
}
U dequeue() volatile {
U val;
while (true) {
if (!reader->empty() && reader->dequeue(val)) {
return val;
} else {
reader = reader->next;
}
}
}
bool empty() volatile {
return reader == writer && reader->empty();
}
};