我正在阅读Anthony Williams的 C ++ Concurrency in Action ,并且不理解push
类的lock_free_stack
实现。
为什么原子load
不在while循环中?他给出的理由是:
因此,您不必每次都通过循环重新加载头部, 因为编译器会为你做这件事。
但我不明白。有人可以对此有所了解吗?
template<typename T>
class lock_free_stack
{
private:
struct node
{
T data;
node* next;
node(T const& data_) :
data(data_)
{}
};
std::atomic<node*> head;
public:
void push(T const& data)
{
node* const new_node=new node(data);
new_node->next=head.load();
while(!head.compare_exchange_weak(new_node->next,new_node));
}
};
答案 0 :(得分:6)
密钥位于compare_exchange_weak
的接口中,在这种情况下需要2个参数。第一个是对期望值的引用,第二个是期望值。如果原子的当前值不等于预期输入,则它将返回false并将预期输入设置为当前值。
所以在这种情况下,它正在做的是设置new_node->next = head
。然后,它说head
仍然等于new_node->next
,将其交换为head
。如果它不再是该值,则会使用new_node->next
的引用为其分配当前值head
。由于失败的循环的每次迭代也用new_node->next
的当前值替换head
,因此没有读取在循环体中复制它。
答案 1 :(得分:3)
来自compare_exchange_weak
的文档:
以原子方式将* this中存储的值与值进行比较 预期,如果这些是平等的,则取代前者 (执行读 - 修改 - 写操作)。否则,加载实际 存储在* this中的值到期望值(执行加载操作)。
如您所见,否则将head
的实际值加载到预期中。