c++ - 有没有更有效的方法来原子地添加两个 float ?

标签 c++ multithreading atomic c++03

我有一堆由各种线程更新的 float 。数组的大小远大于线程数。因此,同时访问特定的 float 是相当罕见的。我需要 C++03 的解决方案。

以下代码以原子方式将一个值添加到其中一个 float ( live demo )。假设它有效,它可能是最好的解决方案。 我能想到的唯一选择是将数组分成几束,并用互斥锁保护每一束。但我不希望后者更有效率。

我的问题如下。有没有其他解决方案可以原子地添加 float ?任何人都可以预测哪个是最有效的吗?是的,我愿意做一些基准测试。也许可以通过放宽内存约束来改进下面的解决方案,即将 __ATOMIC_SEQ_CST 换成其他东西。我没有这方面的经验。

void atomic_add_float( float *x, float add )
{
  int *ip_x= reinterpret_cast<int*>( x ); //1
  int expected= __atomic_load_n( ip_x, __ATOMIC_SEQ_CST ); //2
  int desired;
  do  {
    float sum= *reinterpret_cast<float*>( &expected ) + add; //3
    desired=   *reinterpret_cast<int*>( &sum );
  } while( ! __atomic_compare_exchange_n( ip_x, &expected, desired, //4
                                          /* weak = */ true, 
                                          __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) );
}

其工作原理如下。在 //1 处,x 的位模式被解释为 int,即我假设 floatint 具有相同的大小(32 位)。在 //2 处,要增加的值以原子方式加载。在 //3 处,int 的位模式被解释为 float 并添加被加数。 (请记住,expected 包含在 ip_x == x 处找到的值。)这不会更改 ip_x == x 下的值。在 //4 如果没有其他线程更改该值,则求和结果仅存储在 ip_x == x 中,即如果 expected == *ip_x(docu)。如果不是这种情况,则 do-loop 继续并且 expected 包含找到的更新值 ad ip_x == x

GCC 的原子访问函数(__atomic_load_n__atomic_compare_exchange_n)可以很容易地被其他编译器的实现交换。

最佳答案

Are there any alternative solutions for adding floats atomically? Can anyone anticipate which is the most efficient?

当然,至少有几个想到:

  1. 使用同步原语,即自旋锁。会比 compare-exchange 慢一点。

  2. 交易扩展 ( see Wikipedia )。会更快,但此解决方案可能会限制可移植性。

总的来说,您的解决方案非常合理:速度很快,而且可以在任何平台上运行。

在我看来,所需的内存顺序是:

  • __ATOMIC_ACQUIRE -- 当我们读取 __atomic_load_n()
  • 中的值时
  • __ATOMIC_RELEASE -- 当 __atomic_compare_exchange_n() 成功时
  • __ATOMIC_ACQUIRE -- 当 __atomic_compare_exchange_n() 失败时

关于c++ - 有没有更有效的方法来原子地添加两个 float ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48746540/

相关文章:

java - 是否存在竞争条件,或者对同一对象的同一方法进行多次调用时如何工作

java - "java.net.BindException: Address already in use"尝试使用与前一个线程相同的新线程创建套接字时

c++ - 具有 std::atomic 成员变量的类的复制构造函数/赋值运算符出错

java - 实现时间滑动窗口类时使用原子类型的非锁定线程代码

java - 有ConcurrentHashMap为什么还要synchronizedMap()?

c++ - .load(std::memory_order_relaxed) 的成本是否与读取非原子变量相同?

c++ - 在 OpenCV 中使用 FeatureDetector 会导致访问冲突

c++ - 为什么 `std::is_function_v` 没有按预期工作?

c++ - "Failed writing body"CURLOPT_WRITEDATA

c++ - 类模板 : Prevent assignment of <other> type