对于add / sub / inc / dec,使用std :: memory_order_acq_rel和一个原子变量是足够的吗?

时间:2015-08-07 12:48:58

标签: c++ multithreading c++11 arm lock-free

众所周知,当我们使用只有一个原子变量来存储或加载它时,使用Release-Acquire排序(std::memory_order_acq_rel)就足够了https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

但是,对于其他基本的无等待函数是否正确,例如:加法,减法,递增和递减?

即。对于弱(arm-cpu,...)和strong(x86-cpu,...)内存模型,next()函数在以下C ++代码中是否是线程安全的,或者是否需要另一个屏障排序(低/高)?

#include <iostream>
#include <atomic>
using namespace std;

class progression_lf {
 public:
 progression_lf() : n(0) {}

 int next() {
    // memory_order_acq_rel - enough, and increases performance for the weak memory models: arm, ...
    int const current_n = n.fetch_add(1, std::memory_order_acq_rel);
    int result = 2 + (current_n - 1)*3;
    return result;
 }

 bool is_lock_free() { return ATOMIC_INT_LOCK_FREE; }

 private:
 std::atomic<int> n;
};

int main() {

    // reference (single thread)
    for(int n = 0; n < 10; ++n) {
        std::cout << (2+(n-1)*3) << ", ";
    }
    std::cout << std::endl;

    // wait-free (multi-thread safety)
    progression_lf p;
    for(int n = 0; n < 10; ++n) {
        std::cout << (p.next()) << ", ";
    }
    std::cout << std::endl; 

    std::cout << "lock-free & wait-free: " << 
        std::boolalpha << p.is_lock_free() << 
        std::endl;

    return 0;
}

1 个答案:

答案 0 :(得分:2)

如果您的线程只需要一个唯一的数字,我担心您不需要任何比放松更强的C ++内存排序。原子性足够,std::memory_order_relaxed保证:

  

轻松操作:没有同步或排序约束,此操作只需要原子性。

虽然事实上,具有原子读 - 修改 - 写操作的代码仍将在x86上生成硬件指令,这意味着完全的内存屏障。

您可以看到不同编译器为不同平台生成的内容here