使用比较大于而不是相等的原子操作交换?

17

C++11提供了一种针对原子变量的“比较和交换”(compare and exchange)操作。

其语义为:

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

我想做同样的事情,但是不是在它们相等时设置*obj,而是在一个大于另一个时设置(假设我们正在讨论有序类型)。

这是否有支持?或者可以通过某些hack方式实现吗?

注意:对我来说,CAS循环并不能解决问题,因为我要比较的两个值可能会在非原子操作之间发生改变。


这在循环中非常容易实现,我相信很快就会有人给你详细说明,但是告诉我,你想如何使用此操作? - avakar
1
你可以像这个链接中的例子一样使用CAS循环:https://dev59.com/GmQo5IYBdhLWcg3wR9nD#16190791。如果我理解正确的话,这可能是一个重复的问题。 - zch
你的意思是obj是一个指向有序对象的指针,并且你想根据两个指向的对象的比较结果设置一个指针吗?如果是这样的话:这是不可能的,因为CAS只处理一个内存地址。你的请求涉及至少两个内存地址:指针变量的地址(你想要交换的东西)和你想要比较的数据的地址。 - mmmmmmmm
@KerrekSB:这不是重复的问题,尽管它们非常相关。任何两个值都可以“不相等”,但对于大于/小于,您需要有顺序。 - einpoklum
@Cameron:把那个作为答案? - einpoklum
显示剩余4条评论
3个回答

15

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

我希望当一个值大于另一个值时(假设我们正在谈论有序类型),将其设置为这个值。

所以,假设您想存储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...

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


2
这并没有真正帮助我,因为在此循环中执行每个原子指令后,我的目标值可能会发生改变。 - einpoklum
1
那么?只需将重新计算的指令放入“您想要执行的操作”语句中即可... - Tony Delroy
2
那并没有帮助。一旦我到达while条件,target_value不再是“应该做什么”语句中的值了。 - einpoklum
1
为什么不行呢?“应该做什么代替”语句紧接着就是while的条件...你完全可以控制target_value变量。不是要无礼,但要么我们在这里存在巨大的沟通隔阂(我很难看到需要解释的地方),要么我应该找另一个职业,或者你完全没有理解CAS的工作原理,也许应该看一些简单事物的实现,比如增加计数器-确保它们能够理解... - Tony Delroy
同时请注意,“比较并交换”通常会在操作失败后使用实际值更新“当前”值,因此不需要显式重新加载。 - Kerrek SB
显示剩余2条评论

6

根据要求,以下是我的翻译:


我也希望这个存在,但据我所知(特别是对于x86 / x64),除了概念上的存在之外,它并不存在,并且解决方法(可能)使用多个原子指令(虽然可行但不是无等待的)。


2

这可能是一个老问题,但我认为许多人都希望有这种功能。我想到了一个主意,这里展示伪代码(我是Linux内核的人,所以使用一些内核函数)。

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

这段代码没有尝试使用cmpxchg来比较旧值和新值。
如果存在并发问题,请告诉我。谢谢:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接