【问题标题】:Atomic swap function using gcc atomic builtins使用 gcc atomic builtins 的原子交换函数
【发布时间】:2012-01-25 13:12:03
【问题描述】:

这是通用原子交换函数的正确实现吗?我正在寻找 GCC 上兼容 C++03 的解决方案。

template<typename T>
void atomic_swap(T & a, T & b) {
    static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded.");
    T * ptr = &a;
    b =__sync_lock_test_and_set(ptr, b);
    __sync_lock_release(&ptr);
}

如果没有,我该怎么做才能解决它?

另外:__sync_lock_release 总是必要的吗?在搜索其他代码库时,我发现这通常不会被调用。如果没有发布调用,我的代码如下所示:

template<typename T>
void atomic_swap(T & a, T & b) {
    static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded.");
    b = __sync_lock_test_and_set(&a, b);
}

PS:Atomic swap in GNU C++ 是一个类似的问题,但它没有回答我的问题,因为提供的答案需要 C++11 的 std::atomic 并且它具有签名 Data *swap_data(Data *new_data),这对于swap 函数。 (它实际上将提供的参数与在函数之前定义的全局变量交换。)

【问题讨论】:

  • 看起来只有对a的访问应该是原子的?
  • 为什么要重新发明轮子?看concurrencykit.org
  • @BenVoigt 那篇文章没有给出明确的答案。并将参数与全局变量交换。

标签: c++ atomic


【解决方案1】:

请记住,此版本的交换不是完全原子操作。虽然b 的值将被自动复制到a,但a 的值可能会复制另一个线程对b 值的修改。换句话说,对b 的分配对于其他线程来说不是原子的。因此,您最终可能会遇到a == 1 和b == 2 的情况,并且在gcc 内置之后,您最终会返回a == 2 和1 的值,但现在另一个线程已经改变了将b 的值改写为3,然后将b 中的值改写为1。因此,虽然您可能已经“技术上”交换了值,但您并没有以原子方式进行操作……另一个线程在 gcc atomic 内置函数的返回和该返回的分配之间触及了 b 的值值b。从组装的角度来看,您有以下内容:

lea RAX, qword ptr [RDI]  // T * ptr = &a;
mov RCX, qword ptr [RSI]  // copy out the value referenced by b into a register
xchg [RAX], RCX           // __sync_lock_test_and_set(&a, b)
mov qword ptr [RSI], RCX  // place the exchange value back into b (not atomic!!)

说实话,如果没有硬件操作(如 DCAS 或弱加载链接/存储条件)或可能使用其他方法(如事务性内存),您无法对两个单独的内存位置进行无锁原子交换(它本身倾向于使用细粒度的锁定)。

其次,由于您的函数是现在编写的,如果您希望原子操作同时具有获取和释放语义,那么是的,您将不得不放置在 __sync_lock_release 中,或者您将必须通过__sync_synchronize 添加一个完整的内存屏障。否则它只会在__sync_lock_test_and_set 上获得语义。尽管如此,它并不会原子地相互交换两个单独的内存位置......

【讨论】:

  • 我知道写入b 使其成为非原子操作,因此不是线程安全的。但是,我看不到使它安全的方法。这是否意味着指针类型的无锁交换是不可能的?
  • 差不多,除非硬件再次支持 DCAS 之类的东西,或者相当弱的加载链接/存储条件操作,因此如果有任何对内存的访问,它就会失败,或者至少缓存行上的内存访问,并且您要交换的两个值在同一缓存行上
猜你喜欢
  • 2013-01-18
  • 2010-11-12
  • 1970-01-01
  • 2014-09-19
  • 1970-01-01
  • 2016-02-09
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多