Missmiaom
3/10/2020 - 2:38 PM

atomic

CAS

声明:

bool compare_exchange_weak( T& expected, T desired,
                            std::memory_order success,
                            std::memory_order failure ) noexcept;

更新失败时,会将当前 atomic 对象值赋给 expected

例子:

template <typename T>
void UpdateMaximum(std::atomic<T>& maximum_value, T const& value) noexcept {
  T prev_value = maximum_value;
  while (prev_value < value &&
         !maximum_value.compare_exchange_weak(prev_value, value)) {
  }
}

compare_exchange_weak 在缺少单条 CAS 操作的机器上,处理器不能保证其能够自动完成,所以即使当原始值与期望值一样时,存储也可能不成功。这称为 “伪失败”。

compare_exchange_strong 保证了原始值与期望值一样时,操作一定成功。

如果不论预期值是什么都需要修改原子变量的值,那么可以循环调用 compare_exchange() 函数。

  • 如果值容易存储,那么使用 compare_exchange_weak 能够避免双重循环(compare_exchange_strong 中包含一个循环),即使可能发生伪失败。
  • 如果值不容易存储,那么使用 compare_exchange_strong 能够避免对值的重复计算。

std::atomic

用户自定义类型的原子变量有很多严格的限制,对于 std::atomic<MyType>MyType 需要:

  • 对于 MyTypeMyType 的所有基类和 MyType 的所有非静态成员的拷贝构造函数必须是 trivial (编译器自动生成的)。
  • MyType 不能具有虚拟方法或基类。
  • MyType 必须按位比较,以便可以应用C函数 memcpymemcmp

你可以使用 std::is_trivially_copy_constructiblestd::is_polymorphicstd::is_trivial 来对其进行约束检查。 这些所有功能都是 type-traits 库的一部分。

volatile and atomic

volatile

  1. 与平台无关的多线程程序,volatile几乎无用(Java的volatile除外)
  2. volatile 不保证原子性(一般需使用CPU提供的LOCK指令)
  3. volatile 不保证执行顺序
  4. volatile 不提供内存屏障(Memory Barrier)和内存栅栏(Memory Fence)
  5. 多核环境中内存的可见性和 CPU 执行顺序不能通过 volatile 来保障,而是依赖于 CPU 内存屏障