gpt4 book ai didi

c++ - 顺便说一下原子交换(没有返回值)和存储的区别?这是关于带有原子库的彼得森算法

转载 作者:行者123 更新时间:2023-12-01 14:23:01 25 4
gpt4 key购买 nike

std::atomic<int> flag0(0),flag1(0),turn(0);

void lock(unsigned index)
{
if (0 == index)
{
flag0.store(1, std::memory_order_relaxed);
turn.exchange(1, std::memory_order_acq_rel);
//turn.store(1)

while (flag1.load(std::memory_order_acquire)
&& 1 == turn.load(std::memory_order_relaxed))
std::this_thread::yield();
}
else
{
flag1.store(1, std::memory_order_relaxed);
turn.exchange(0, std::memory_order_acq_rel);
//turn.store(0)

while (flag0.load(std::memory_order_acquire)
&& 0 == turn.load(std::memory_order_relaxed))
std::this_thread::yield();
}
}

void unlock(unsigned index)
{
if (0 == index)
{
flag0.store(0, std::memory_order_release);
}
else
{
flag1.store(0, std::memory_order_release);
}
}

没有 left 的 turn.exchange(0)(使用类似于 void 返回函数)的工作方式类似于“turn.store(0)”。

是否有任何理由使用“交换”方法?

在这个算法中,这段代码不需要保存以前的值。

最佳答案

主要区别在于 x86 交换转换为 lock xchg 指令,该指令顺序一致,即使您将其指定为 std::memory_order_acq_rel!如果您要使用带有 std::memory_order_release 的存储,内部存储缓冲区会破坏您的互斥保证(即,您的锁会被破坏)!但是,如果您使用带有 std::memory_order_seq_cst 的存储,许多编译器也会将其简单地转换为 lock xchg,因此您最终会得到相同的机器代码。

也就是说,您应该依赖交换隐式顺序一致的事实。相反,您应该根据需要指定 C++ 内存顺序,以确保您的代码根据 C++ 标准正确运行。

更新
存在各种顺序一致性的定义,试图用不同的术语来解释相同的想法。Leslie Lamport 是这样描述的:

... the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program."

C++标准提供了如下定义:

There shall be a single total order S on all memory_order_seq_cst operations, consistent with the "happens before" order and modification orders for all affected locations, such that each memory_order_seq_cst operation B that loads a value from an atomic object M observes one of the following values:

  • (3.1) the result of the last modification A of M that precedes B in S, if it exists, or
  • (3.2) if A exists, the result of some modification of M that is not memory_order_seq_cst and that does not happen before A, or
  • (3.3) if A does not exist, the result of some modification of M that is not memory_order_seq_cst.

本质上这意味着如果交换和加载操作都是顺序一致的,那么它们严格按总顺序 S 排序 - 因此要么交换在加载之前排序,要么反之反之亦然。如果交换在加载之前被排序,那么加载可以保证看到交换存储的值(或者如果存在的话,一些更晚的值)。如果您有一个顺序不一致的存储,则您没有有这样的保证,即,在这种情况下,两个线程都可能成功获取锁,原因很简单,因为它们没有“看到” "另一个线程存储的值。

x86内存模型很强,每 strip 锁前缀的指令都是顺序一致的。这就是为什么在许多情况下,如果您在 x86 CPU 上运行,您甚至没有注意到您的代码没有强制执行必要的 happens before 关系。但是,如果您要在 ARM 或 Power 上运行它,事情就不会那么顺利。

关于c++ - 顺便说一下原子交换(没有返回值)和存储的区别?这是关于带有原子库的彼得森算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61399770/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com