如何用C ++ 11的CAS实现Valois'Queue

时间:2018-03-17 03:19:58

标签: c++ c++11 atomic compare-and-swap

我想用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函数CAS1CAS2。出于一个原因,p->next不是std::atomic的类型,而对于另一个原因,expected的第二个参数atomic_compare_exchange_weak需要指针。在问题documentation中,cas函数会将*expected设置为当前值,从而导致取消引用nullptr。此外,stmt 1,p = tail也失败了,因为原子的operator=被删除了。那么如何根据JD Valois的论文实现无锁队列?

1 个答案:

答案 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);
}