本文介绍了区别btw原子交换(没有返回值)和存储?关于具有原子库的Peterson算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

turn.exchange(0)不带左(使用像void return函数一样)的工作方式类似于'turn.store(0)'.

turn.exchange(0) without left (using like void return function) works similarly to 'turn.store(0)'.

有什么理由要使用兑换"方法吗?

Is there any reason for using 'exchange' method?

在此算法中,此代码无需保存先前的值.

In this algorithm, this code doesn't need to save previous value.

推荐答案

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

The main difference is than on x86 exchange translates to a lock xchg instruction which is sequentially consistent, even tough you specified it as std::memory_order_acq_rel! If you were to use a store with std::memory_order_release, the internal store buffer would spoil your mutual exclusion guarantee (i.e., your lock would be broken)!. However, if you use a store with std::memory_order_seq_cst, many compiler will simply translate it to lock xchg as well, so you end up with the same machine code.

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

That said, you should NOT rely on the fact that exchange is implicitly sequentially consistent. Instead you should specify the C++ memory orders as required, to ensure your code behaves correctly with respect to the C++ standard.

更新
存在各种顺序一致性定义,这些定义试图用不同的术语来解释同一思想.莱斯利·兰珀特对此描述如下:

UPDATE
There exist various definitions of sequential consistency that try to explain the same idea it in different terms.Leslie Lamport described it as follows:

C ++标准提供以下定义:

The C++ standard provides the following definition:

  • (3.1)对在 S 中的 B 之前的M的最后修改A的结果(如果存在),或
  • (3.2)如果存在 A ,则是对 M 的某些修改的结果,该修改不是memory_order_seq_cst,并且不会在 A 或
  • (3.3)如果 A 不存在,则是对 M 的某些修改而不是memory_order_seq_cst的结果.
  • (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 进行排序-因此,交换是在加载之前进行的,否则是在交换之前进行的反之亦然.如果在装载之前对交换器进行了订购,则可以保证装载看到交换器存储的值(如果存在此值,则可以查看一些更晚的值).如果您的商店的存储顺序不一致,那么您 not 不会有这样的保证,即,在这种情况下,可能发生两个线程都成功获取了锁的情况,这很简单,因为它们没有看到" 另一个线程存储的值.

Essentially what this means is that if the exchange and the load operations are both sequentially consistent, then they are strictly ordered in the total order S - so either the exchange is ordered before the load or vice versa. If the exchange is ordered before the load, then the load is guaranteed to see the value stored by the exchange (or some later value if such exists). If you have a store that is not sequentially consistent, you do not have such a guarantee, i.e., in this case it could happen that both threads succeed in acquiring the lock, simple because they did not "see" the value stored by the other thread.

x86内存模型非常强大,并且每个带锁前缀的指令都是顺序一致的.这就是为什么在很多情况下,即使在x86 CPU上运行,您甚至都不会注意到代码没有强制关系发生必要的事情.但是,如果要在ARM或Power上运行,事情就不会那么顺利.

The x86 memory model is very strong, and every lock prefixed instruction is sequentially consistent. That's why in many cases you don't even notice that your code does not enforce the necessary happens before relations if you are running on a x86 CPU. But things wouldn't run as smoothly if you were to run it on ARM or Power.

这篇关于区别btw原子交换(没有返回值)和存储?关于具有原子库的Peterson算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-21 04:23