在http://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange,以下示例代码显示为std::atomic_compare_exchange_weak
的示例用法:
void append(list* s, node* n)
{
node* head;
do {
head = s->head;
n->next = head;
} while(! std::atomic_compare_exchange_weak(s->head, head, n));
}
我的理解是,这具有将*(s->head)
与head
进行比较的效果,当我认为需要将s->head
与head
进行比较时。本例中std::atomic_compare_exchange_weak
的第一个参数应该是&(s->head)
,还是我错过了什么?
更新:std::atomic_compare_exchange_weak
的规范说:
bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired) noexcept;
bool atomic_compare_exchange_weak(A* object, C * expected, C desired) noexcept;
效果:原子地,比较内存的内容 对象指向...与预期中的平等......
我认为这意味着*object
与expected
进行了比较,但进一步的研究表明实际意义是*object
与*expected
进行比较(即, “in expected
”表示“expected
指出”。这意味着我原来问题的答案是“不,没有必要在cppreference的示例代码中获取s->head
的地址”。但object
必须指向std::atomic<T>
且预期必须指向T
的事实使我很难弄清楚如何在cppreference处更正代码以便编译。我们希望将列表的头部与列表头部的副本进行比较,但如果列表的头部类型为std::atomic<T>*
,则副本必须为T*
类型,如果致电std::atomic_compare_exchange_weak
是为了编译,我找不到在没有std::atomic<T>*
的情况下将T*
分配给reinterpret_cast
的方法。即使这样,std::atomic_compare_exchange_weak
的第三个参数也需要是T
类型,但cppreference中的示例显示第二个和第三个参数属于同一类型。这告诉我,cppreference的例子被打破了。我试图修复它,但是因为需要使用感觉不对的reinterpret_cast
而受到阻碍。
有趣的是,在我尝试解决这些问题时,我检查了msdn page for std::atomic_compare_exchange_weak
,我很惊讶地看到该页面显示了std::atomic_compare_exchange_*strong*
的原型!
有人发布使用std::atomic_compare_exchange_weak
在单链表前插入节点的合理代码吗?没有必要担心ABA问题或做任何花哨的事情。我只想看到编译的骨架代码。
答案 0 :(得分:2)
一个正确的例子是:
struct list {
std::atomic<node*> head;
};
...
void append(list* s, node* n)
{
node* head;
do {
head = s->head;
n->next = head;
} while (!std::atomic_compare_exchange_weak(&(s->head), &head, n));
// or while (!s->head.compare_exchange_weak(head, n));
}
list::head
需要是std::atomic
对象,除非您想要处理未定义的行为。有问题的平台可能需要使用锁来实现部分或全部std::atomic
内容。因此,std::atomic<T*>
可能包含其他成员,而reinterpret_cast<std::atomic<T*>*>
就是UB意味着您的程序崩溃的情况。