使用CAS习惯用法时,ABA与推送/插入操作相关吗?

问题描述

以下伪代码摘自http://15418.courses.cs.cmu.edu/spring2013/article/46

while (1) {
  n->next = p->next;
  Node *old_next = p->next;
  if (compare_and_swap(&p->next,old_next,n) == old_next)
    return;
}

这是无锁堆栈的push操作,该操作使用比较和交换惯用法,但自动进行。似乎ABA问题在这里并不重要,我想知道推送和插入操作通常是否如此?

解决方法

您是正确的,该函数不会遇到ABA问题,因为在调用old_next之前,没有任何内容取决于compare_and_swap的值。

考虑(简化的)弹出操作:

  while (1) {
    Node *top = s->top;
    if (top == NULL)
      return NULL;
    Node *new_top = top->next;
    if (compare_and_swap(&s->top,top,new_top);
      return top;
  }
}

这里,我们将s->top加载到top中,然后在s->top上以top作为期望值执行CAS。但是在CAS之前,我们读了top->next,所以我们执行的操作取决于top!这就是导致ABA问题的原因。

通常不可能声明所有推入/插入操作都没有ABA问题,因为这取决于更多细节。作为一个有些人为的示例,请考虑仅在该值更大时才有条件地推送该值的推送操作。

while (1) {
  n->next = p->next;
  Node *old_next = p->next;
  if (n->value < old_next->value)
    return;
  if (compare_and_swap(&p->next,old_next,n) == old_next)
    return;
}

这也遭受ABA问题的困扰,因为它可能破坏我们对值进行严格排序的不变性。

,

此代码没有ABA问题,但这确实是因为它执行的不是很多。

从根本上讲,问题是您使用compare_and_swap(&p->next,n)来确保自从您上次查看堆栈以来,堆栈没有发生变化,但是它确实做到了( )可靠。

在您读n->next和您读compare_and_swap的时间之间,其他线程可能具有:

  1. 弹出n->next
  2. 推了很多其他东西
  3. 重新按旧的n->next

那么即使堆栈已更改,您的compare_and_swap也会成功。

这对您来说不是问题,因为您从未看过n->next的任何字段。堆栈已更改没关系,因为您只关心n->next指针。

但是,如果您必须必须查看该对象的内部,则您的代码将被破坏。例如,如果您添加了一个stack_size字段以原子方式跟踪堆栈大小,那么您将设置n->stack_size = old_next->stack_size+1,如果堆栈已更改,这将是错误如上所述。

因此,插入操作是ABA防护的,通常不是

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...