我想用C ++ 11中提供的原子CAS实现JD Valois'paper 实现无锁队列。
例如,Valois'算法定义了Enqueue
函数:
Enqueue(x) {
q = new Record();
q->value = x;
q->next = NULL;
do {
p = tail;
} while( ! CAS(p->next, NULL, q) ); // 1
CAS(tail, p, q); // 2
}
我写了这样的代码
struct Node {
T * val;
Node * next;
};
std::atomic<Node *> head, tail;
void enqueue(T * t) {
Node * nd = new Node();
nd->val = t;
nd->next = nullptr;
std::atomic<Node *> p;
do {
p = tail; // 1
} while ( /* CAS1 */ ! std::atomic_compare_exchange_weak(&(p->next), nullptr, nd) );
/* CAS2 */ std::atomic_compare_exchange_weak(&tail, p.load(), nd)
}
然后我发现错误地使用了两个cas函数CAS1
和CAS2
。出于一个原因,p->next
不是std::atomic
的类型,而对于另一个原因,expected
的第二个参数atomic_compare_exchange_weak
需要指针。在问题documentation中,cas函数会将*expected
设置为当前值,从而导致取消引用nullptr
。此外,stmt 1,p = tail
也失败了,因为原子的operator=
被删除了。那么如何根据JD Valois的论文实现无锁队列?
答案 0 :(得分:1)
您正确描述了所有问题。下一步只是修复代码。
struct Node {
T * val;
std::atomic<Node *> next;
};
std::atomic<Node *> head, tail;
void enqueue(T * t) {
Node * nd = new Node();
nd->val = t;
nd->next = nullptr;
Node *p, *next;
do {
p = tail.load(); // 1
next = nullptr;
} while (/* CAS1 */ !std::atomic_compare_exchange_weak(&p->next, &next, nd));
/* CAS2 */ std::atomic_compare_exchange_weak(&tail, &p, nd);
}