【问题标题】:How to perform basic operations with std::atomic when the type is not Integral?当类型不是 Integral 时,如何使用 std::atomic 执行基本操作?
【发布时间】:2014-05-31 17:30:31
【问题描述】:

确切地说,我只需要将一个 double 增加另一个 double 并希望它是线程安全的。我不想为此使用互斥锁,因为执行速度会大大降低。

【问题讨论】:

标签: c++ multithreading stdatomic


【解决方案1】:

所以使用积分原子作为内存屏障。这是一个带有来源和解释的页面:http://preshing.com/20121019/this-is-why-they-call-it-a-weakly-ordered-cpu/

【讨论】:

  • 内存屏障只有助于排序,而不是原子性。这就是为什么您需要一个 CAS(或 LL/SC)来使整个读-修改-写原子化。
【解决方案2】:

通常,C++ 标准库试图只提供可以有效实现的操作。对于std::atomic,这意味着可以在“通用”架构上的一条或两条指令中无锁执行的操作。 “通用”架构具有用于整数的原子获取和添加指令,但不适用于浮点类型。

如果您想为原子浮点类型实现数学运算,您必须自己使用 CAS(比较和交换)循环 (Live at Coliru):

std::atomic<double> foo{0};

void add_to_foo(double bar) {
  auto current = foo.load();
  while (!foo.compare_exchange_weak(current, current + bar))
    ;
}

【讨论】:

  • 谢谢你的回答,我没有意识到为了做到这一点(安全地添加两个双线程)我需要这么脏(或者至少在我看来是这样)的解决方法。
  • 我有点困惑。如果 foo != current 由于 foo 被负载和 CAS 之间的另一个线程修改,为什么这段代码不会进入无限循环?
  • @Joe compare_exchange_weak 通过引用获取其第一个参数,并在失败时将其更新为观察值。因此,如果 CAS 因foo != current 而失败,则循环会从更新的current 中计算出一个新的current + bar 并重试。
  • @Casey 感谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 2018-11-22
相关资源
最近更新 更多