【问题标题】:atomic_compare_exchange with greater-than instead of equals?atomic_compare_exchange 大于而不是等于?
【发布时间】:2023-04-05 00:34:01
【问题描述】:

C++11 对atomic variables 有一个“比较和交换”操作。

语义是:

原子地比较obj指向的值和expected指向的值,如果它们相等,用desired替换前者(执行读-修改-写手术)。否则,将obj 指向的实际值加载到*expected 中(执行加载操作)。

我也想这样做,但不是在值相等时设置*obj,而是希望在一个大于另一个时设置它(假设我们正在谈论关于有序类型)。

这是否以某种方式支持?也许可以通过一些 hack 来实现?

注意: CAS 循环不适合我,因为我比较的两个值都可能在非原子操作之间发生变化。

【问题讨论】:

  • 这个循环很简单,相信很快就会有人给你详细的,但是告诉我,你想怎么用这个操作?
  • 你可以做一个 CAS 循环,比如 stackoverflow.com/questions/16190078/… 。即使我理解正确,这也可能是重复的。
  • 你的意思是 obj 是一个指向有序对象的指针,你想根据你指向的两个对象的比较结果来设置一个指针吗?如果是这样:这是不可能的,因为 CAS 只处理一个内存地址。您的请求至少处理两个内存地址:指针变量的地址(您要交换的东西)和您要比较的数据的地址。
  • 我也希望它存在,但它不存在(当然,除了在概念上,以及(可能)使用多个原子指令的变通方法)。

标签: c++ c++11 atomic compare-and-swap


【解决方案1】:

我认为您误解了比较和交换/交换的工作原理:基本思想是查看当前值后,您可以计算出一些相应的新值 - 然后您尝试进行更新。如果它成功了 - 很好 - 继续你需要的任何东西,但如果它失败了,那就重新开始:查看其他线程放入的新值,并考虑你现在需要的值。

我希望在一个大于另一个时设置它(假设我们谈论的是有序类型)。

假设您想要存储 11,但前提是现有值仍然原子地小于 11。您不会找到直接执行此操作的指令,但您可以使用现有的比较和交换轻松完成:

int target_value = 11;
do {
    int snapped_x = x;
    if (snapped_x >= target_value)
        what do you want to do instead?
} while (!compare_and_swap(x, snapped_x, target_value));
         // ...or whatever your exact calling convention is...

你仍然可以得到你想要的行为,只是失败/旋转率可能更高......

【讨论】:

  • 这对我没有帮助,因为我的目标值会在我在这个循环中执行的每条原子指令之后发生变化。
  • 所以?只需将重新计算的说明放入“你想做什么”语句中......
  • 这没有帮助。一旦我达到 while 条件,target_value 就不再是“要做什么”语句中的内容了。
  • 为什么不呢? “要做什么”语句是 立即 后跟 while 条件...您可以完全控制 target_value 变量。无意粗鲁,但要么我们在这里有巨大的沟通分歧(我正在努力寻找解释),我应该找到另一个职业,或者你完全没有理解 CAS 的工作原理,也许应该看看在一些简单的事情的实现中,比如增加一个计数器 - 确保它们沉入......?
  • 也许值得一提的是,设置一个目标值并不意味着您期望该目标值在 CAS 启动时仍然有效......重点在于当前值snapped_x 和目标值,如果snapped_x 没有同时被另一个线程更改,那么您可以确定目标仍然有效。如果snapped_x 发生更改,您将重新计算目标...
【解决方案2】:

根据要求,这是我的评论作为答案:


我也希望它存在,但据我所知,它不存在(当然不是 x86/x64),当然,除了在概念上,以及(可能)使用多个原子指令的解决方法(工作但不是免等待)。

【讨论】:

    【解决方案3】:

    这可能是一个老问题,但我想很多人会想要这种功能。 我想出一个主意,这里展示一下伪代码(我是linux内核的人,所以使用一些内核函数)。

    update(new)
    {
      old = atomic_read(&pvalue);
      while (old < new) {
        v = atomic_cmpxchg(&pvalue, old, new);
        if (v != old) {
          old = v;
          continue;
        }
      }
    }
    

    代码不会尝试 cmpxchg 旧值小于新值。
    如果有并发问题,请告诉我。谢谢:)

    【讨论】:

      猜你喜欢
      • 2012-10-14
      • 1970-01-01
      • 2017-09-05
      • 2013-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-25
      相关资源
      最近更新 更多