我正在阅读安东尼·威廉姆斯的“在行动中的C++并发”,并且不理解它对lock_free_stack类的推送实现。清单7.12准确地说
void push(T const& data)
{
counted_node_ptr new_node;
new_node.ptr=new node(data);
new_node.external_count=1;
new_node.ptr->next=head.load(std::memory_order_relaxed)
while(!head.compare_exchange_weak(new_node.ptr->next,new_node, std::memory_order_release, std::memory_order_relaxed));
}因此,假设有两个线程(A、B)调用push函数。它们都在循环时到达,但没有启动。因此,他们都从head.load(std::memory_order_relaxed)读取相同的值。
接下来我们要做的事情如下:
B线程因任何原因被删除。A线程启动循环,显然成功地将一个新节点添加到堆栈中。B线程回到正轨,并启动循环。在我看来,这就是有趣的地方。因为在成功的情况下,有一个带有、load、和compare_exchange_weak(..., std::memory_order_release, ...)的std::memory_order_relaxed加载操作,所以线程之间似乎没有同步。我是说,这就像std::memory_order_relaxed - std::memory_order_release ,而不是 std::memory_order_acquire - std::memory_order_release。
因此,B线程将简单地将一个新节点添加到堆栈中,但在堆栈中没有节点时将其添加到它的初始状态,并将头重置到这个新节点。
我一直在做关于这个问题的研究,我所能找到的最好的就是在这篇exchange按修改顺序读取最后值?上。
所以问题是,这是真的吗?所有的RMW函数都以修改的顺序看到最后的值?无论我们使用什么std::memory_order,如果我们使用RMW操作,它将与所有线程(CPU等)同步,并找到被写入原子操作的最后一个值被调用?
发布于 2017-01-13 08:46:56
因此,经过一些研究,并问了一群人,我相信我找到了正确的答案,这个问题,我希望这将是一个帮助的人。
所以问题是,这是真的吗?所有的RMW函数都以修改的顺序看到最后的值?
是的,这是真的。
无论我们使用什么std::memory_order,如果我们使用RMW操作,它将与所有线程(CPU等)同步,并找到被写入原子操作的最后一个值被调用?
是的,这也是事实,但是有一些事情需要强调。
RMW运行将只同步与一起工作的原子变量。在我们的例子中,它是head.load
也许您会问,如果RMW完成了同步,那么我们为什么需要发布-获取语义,即使是在轻松的内存顺序下。
答案是因为RMW只与它同步的变量一起工作,但是在RMW之前发生的其他操作可能在另一个线程中看不到。
让我们再看一下push函数:
void push(T const& data)
{
counted_node_ptr new_node;
new_node.ptr=new node(data);
new_node.external_count=1;
new_node.ptr->next=head.load(std::memory_order_relaxed)
while(!head.compare_exchange_weak(new_node.ptr->next,new_node, std::memory_order_release, std::memory_order_relaxed));
}在这个例子中,如果使用两个推送线程,它们在某种程度上不会被同步,但在这里可以允许。
两个线程都会看到最新的头,因为compare_exchange_weak提供了这个。并且一个新的节点将始终添加到堆栈的顶部。但是,如果我们试图在这行之后获得类似于这个*(new_node.ptr->next)的值,那么new_node.ptr->next=head.load(std::memory_order_relaxed)就很容易变得丑陋:空指针可能被取消引用的。这可能是因为处理器可以改变指令的顺序,而且由于线程之间没有同步,第二个线程甚至在初始化前就可以看到指向顶级节点的指针!
这正是发布-获取语义来帮助的地方。它保证了在发布操作之前发生的所有操作都会出现在获取部分!查看并比较书中的清单5.5和5.8。
我还建议您阅读这篇关于处理器如何工作的文章,它可能为更好地理解提供一些基本信息。记忆屏障
https://stackoverflow.com/questions/41117053
复制相似问题