c++原子操作中compare_exchange_weak和compare_exchange_strong的MSVC与GCC源码和用法说明

这两个函数都属于 原子操作的cas操作也就是Compare-and-swap操作,经常在无锁并行或并发结构中用到。以compare_exchange_strong为例子来做个基本的使用说明:


int              tst_val = 4;
int              new_val = 5;
std::atomic<int> atomic_0 = 3;


auto exchanged = atomic_0.compare_exchange_strong(tst_val, new_val);
/*
上面这句代码执行后, 各个相关变量中的值如下:

atomic_0 = 3,  tst_val = 3,  new_val = 5,  exchanged = false

由于atomic_0 和 tst_val两个变量实际内存中的值不相等,所以atomic_0的值依旧是3并没有被设置为new_val的值5, atomic_0的值依旧是3。atomic_0.compare_exchange_strong(...)函数的返回值是false。但是,这句代码执行之后,tst_val的内存值被设置为atomic_0原子变量的内存值3。相当于执行了把atomic_0变量内存中的值载入到tst_val变量中的载入操作。
*/

auto exchanged = atomic_0.compare_exchange_strong(tst_val, new_val);
/*
上面这句代码执行后, 各个相关变量中的值如下:

atomic_0 = 5,  tst_val = 3,  new_val = 5,  exchanged = true

由于atomic_0 和 tst_val两个变量实际内存中的值相等,所以atomic_0的值被设置为new_val的值5。atomic_0.compare_exchange_strong(...)函数的返回值是true。注意,这句代码执行之后,tst_val的内存值没有变。相当于执行了将new_val内存中的值存储到atomic_0变量内存中的设置操作。
*/

compare_exchange_weak和compare_exchange_strong用法一样,只不过由于在某些弱内存顺序的CPU架构下compare_exchange_weak执行会反馈出伪失败。也正因为如此,实际不考虑特别的性能以及考虑到兼容性,用compare_exchange_weak就行了。反正一般的无锁并行或者并发数据结构实现中都是将compare_exchange_weak放在一个while循环里面循环调用的,如下所示:

while (!atomic_var.compare_exchange_weak(old_value, new_value))
{
    // ...
}

当然,你用compare_exchange_strong也可以,但是,很显然 compare_exchange_weak 已经够用了,反正都有循环检测,理论上性能还会更好(为何说理论上,后面看看各系统的实现就能知道)。

备注:

        1. 例如ARM 、 Itanium 、 Power PC这些CPU架构就是弱内存顺序的而Inter x86就是强内存顺序架构。它们的内存操作顺序需要借助内存栅栏来控制。细节请见std::memory_order - cppreference.com

        2. 基于上面的代码说明, 即便atomic_0 和 tst_val两个变量实际内存中的值相等,函数的返回值也是false。这就是伪失败,这时候一句代码搞不定,就需要循环调用才能拿到正确的结果。

看看源码,更清晰。

先看LInux GCC的代码实现。

_GLIBCXX_ALWAYS_INLINE bool
compare_exchange_weak(__int_type& __i1, __int_type __i2,
			    memory_order __m1,
			    memory_order __m2) volatile noexcept
{
__glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));

return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1, int(__m1), int(__m2));
}

_GLIBCXX_ALWAYS_INLINE bool
compare_exchange_strong(__int_type& __i1, __int_type __i2,
			      memory_order __m1, memory_order __m2) noexcept
{
__glibcxx_assert(__is_valid_cmpexch_failure_order(__m2));

return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0, int(__m1), int(__m2));
}

gcc是通过系统内置的 __atomic_compare_exchange_n 函数来实现compare_exchange_weak和compare_exchange_strong功能。__atomic_compare_exchange_n 函数定义如下:

bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder)

由第四个bool类型的参数 weak,来确定是实际执行strong还是weak操作。细节请见:__atomic Builtins (Using the GNU Compiler Collection (GCC))

再来看看Windows MSVC 的代码实现

bool compare_exchange_strong(_TVal& _Expected, const _TVal _Desired,
    const memory_order _Order = memory_order_seq_cst) noexcept { // CAS with given memory order
    long _Expected_bytes = _Atomic_reinterpret_as<long>(_Expected); // read before atomic operation
    long _Prev_bytes;
    _ATOMIC_CHOOSE_INTRINSIC(_Order, _Prev_bytes, _InterlockedCompareExchange, _Atomic_address_as<long>(_Storage),
        _Atomic_reinterpret_as<long>(_Desired), _Expected_bytes);
    if (_Prev_bytes == _Expected_bytes) {
        return true;
    }
    _CSTD memcpy(_STD addressof(_Expected), &_Prev_bytes, sizeof(_TVal));
    return false;
}
bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Success,
    const memory_order _Failure) volatile noexcept {
    static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails");
    return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure));
}
bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Success,
    const memory_order _Failure) volatile noexcept {
    static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails");
    return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure));
}

MSVC 中compare_exchange_weak和compare_exchange_strong的实现,更狠。直接就compare_exchange_weak调用了ompare_exchange_strong,而ompare_exchange_strong调用_InterlockedCompareExchange这个系统内置API,这个api实现如下:

__MACHINE(long __MACHINECALL_CDECL_OR_DEFAULT _InterlockedCompareExchange(long volatile * _Destination, long _Exchange, long _Comparand))

什么weak、strong,不重要了。可能是因为Windows系统程序就是Intel架构系的吧。这也是上面有"理论上"三个字。

还有些细节,可以这位大神的文章:c++并发编程3. CAS原语 - 知乎 这里就不赘述了。

注意, 这些cas操作在多线程工作环境下会有ABA问题,可以用所谓的Double-CAS来解决。对于指针这样的原子变量,ABA问题还会演化为悬空引用问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: compare_exchange_weakC++11的一个原子操作函数,用于比较并交换操作。它可以在多线程环境下保证数据的原子性,避免出现数据竞争的情况。与compare_exchange_strong相比,它的弱版本在交换操作失败时不会抛出异常,而是返回一个bool值表示操作是否成功。 ### 回答2: compare_exchange_weakC++原子操作函数之一。它的作用是比较给定的值和内存的值,如果相等,则将内存的值替换为一个新的值。 compare_exchange_weak函数的使用方式如下: ``` bool compare_exchange_weak(T& expected, T desired); ``` 其expected是一个引用参数,表示期望的值;desired是新的值。函数首先比较内存的值和expected,如果相等,则将内存的值替换为desired并返回true;如果不相等,则将内存的值赋给expected并返回false。 compare_exchange_weak函数是弱的比较和替换原子操作。之所以称为"弱",是因为它在比较和替换期间可能会受到其他线程的干扰,需要重试。这种重试可以保证代码的正确性,但可能会影响性能。 与之相对的是compare_exchange_strong函数,它是"强"的比较和替换原子操作compare_exchange_strong函数不需要重试,因此使用起来更简单,但有可能导致不必要的循环开销。 需要注意的是,compare_exchange_weak函数的返回值不仅表示比较和替换的结果,还表示内存的值是否被替换。因此,在使用该函数时,需要根据返回值判断操作是否成功。 总之,compare_exchange_weakC++原子操作函数,用于比较给定值和内存的值,并在相等时替换。它是一种弱的比较和替换操作,可能需要重试以保证正确性。 ### 回答3: compare_exchange_weak是一种原子操作,其目的是在多线程环境下实现对共享变量的原子比较和交换操作。在C++compare_exchange_weak函数通常与一个参数一起使用,该参数用于表示预期值。此函数会比较共享变量的值与预期值是否相等,如果相等,则将共享变量的值修改为新值,返回true;如果不相等,则不进行修改,返回false。 与compare_exchange_strong函数相比,compare_exchange_weak函数在性能上可能略有优势,但在并发度较高的情况下,可能会出现一些问题,因为它可能会被其他线程断,导致原子操作失败。在这种情况下,函数会返回false,但同时还会返回共享变量的当前值,并将预期值修改为当前值。 compare_exchange_weak函数通常与循环结合使用,以确保原子操作的成功。在循环,可以不断尝试进行原子操作,直到成功为止。这种方法可以有效地避免由于竞态条件而导致的共享变量值的错误结果。 总而言之,compare_exchange_weak函数是一种用于实现原子比较和交换操作的方式。尽管它在某些情况下可能会失败,但通过循环的方式,我们可以确保操作的成功,并保证共享变量的一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值