【问题标题】:std::compare_exchange int with #define valuestd::compare_exchange int 与 #define 值
【发布时间】:2020-09-03 08:26:55
【问题描述】:
  • 我想将std::compare_exchange_strong 用于某些std::atomic<int>
  • 出于编译原因(int &)我不得不介绍int _OLD_VALUE = OLD_VALUE
  • 有没有更优雅的方法来实现这一点?
  • 这是我的例子
#include <atomic>
#include <stdio.h>
#define OLD_VALUE 16
#define NEW_VALUE 744
#define OTHER_VALUE 80
int main(int argc, char **argv)
{
    std::atomic<int> i(OTHER_VALUE);
    int _OLD_VALUE = OLD_VALUE;
    bool    status = i.compare_exchange_strong(_OLD_VALUE,NEW_VALUE);
    // bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
    if (status) { printf("good\n"); }
    return 0;
}

这是我使用注释版本时的编译错误:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:65: error: cannot bind non-const lvalue reference of type ‘std::__atomic_base<int>::__int_type& {aka int&}’ to an rvalue of type ‘int’
     bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
                                                                 ^
In file included from /usr/include/c++/7/atomic:41:0,
                 from main.cpp:1:
/usr/include/c++/7/bits/atomic_base.h:496:7: note:   initializing argument 1 of ‘bool std::__atomic_base<_IntTp>::compare_exchange_strong(std::__atomic_base<_IntTp>::__int_type&, std::__atomic_base<_IntTp>::__int_type, std::memory_order) [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]’
       compare_exchange_strong(__int_type& __i1, __int_type __i2,
       ^~~~~~~~~~~~~~~~~~~~~~~

【问题讨论】:

标签: c++ compare-and-swap


【解决方案1】:

没有。原因是变量的先前值被交换,因此如果比较不匹配,expected 值将被覆盖。

要了解幕后发生的事情,请查看 GCC 内置函数: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html

您会注意到 GCC (Linux) 的内置函数中有一个 __atomic_exchange_n,但这只是提供了一种交换,而不是比较和交换。 Windows 等价物是 InterlockedExchange : https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange

为了可读性,我会避免在变量名中使用大写字母并避免使用前导下划线:

int oldValue = OLD_VALUE;

【讨论】:

    【解决方案2】:

    实现这一点的最简单方法(我想也是唯一的方法)就是编写简单的包装器:

    bool cas_strong(std::atomic<int>& a, int cmp, int exc) {
      return a.compare_exchange_strong(cmp, exc);
    }
    

    【讨论】:

      【解决方案3】:

      compare_exchange_strong 需要一个 int&amp; 来存储在 i 中找到的当前值。在这里,您间接提供16(即在预处理时将您的宏OLD_VALUE 替换为),它是一个整数编译时常量,又名constexpr int&amp;。这与int&amp; 不兼容。

      要提供int&amp;,您最好在拨打compare_exchange_strong 的附近保留int

      std::atomic<int> i(OTHER_VALUE);
      int old_value = OLD_VALUE;
      bool status = i.compare_exchange_strong(old_value, NEW_VALUE);
      if (status) { printf("good\n"); }
      return 0;
      

      此外,更一般地说,如果在这里使用静态常量而不是宏,它显然更强大。 更多关于这个的其他问题:What is the difference between a macro and a const in C++?

      【讨论】:

      • 16 是一个int prvalue,它需要一个int glvalue。
      【解决方案4】:

      不要使用宏来定义值:

      #include <atomic>
      #include <stdio.h>
      int OLD_VALUE 16
      int NEW_VALUE 744
      int OTHER_VALUE 80
      int main(int argc, char **argv)
      {
          std::atomic<int> i(OTHER_VALUE);
          bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
          if (status) { printf("good\n"); }
          return 0;
      }
      

      【讨论】:

      • 真是个坏主意 - compare_exchange_strong 调用会覆盖 OLD_VALUE
      • 这些不是常数。 OLD_VALUEcompare_exchange_strong 修改。
      • @dewaffled 我不明白你能详细说明吗?我错误地写了“常量”,但这里当然没有常量
      • 这个想法是 OLD_VALUE 应该是常量,然后复制到一些非const 变量,该变量本身会被比较/交换。您将 OLD_VALUE 设为非常量并更改它,从而中断后续调用。
      • @idclev463035818 compare_exchange_strongOTHER_VALUE 值存储到 OLD_VALUE 参数,因此它不能在其他任何地方可靠地重复使用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-28
      • 1970-01-01
      • 2012-04-01
      • 2010-12-09
      • 2014-10-29
      相关资源
      最近更新 更多