You are right that this function does not suffer from the ABA problem, because there is nothing that depends on the old_next
value before the call to compare_and_swap
.
Consider the (simplified) pop operation:
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;
}
}
Here we load s->top
into top
and later perform a CAS on s->top
with top
as expected value. But before the CAS, we read top->next
, so we perform an operation that depends on top
! This is what causes the ABA problem.
It is not possible to generally state that all push/insert operations are free of the ABA problem, since it depends on more details. As a somewhat contrived example, consider a push operation that conditionally pushes the value only if it is greater.
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;
}
This also suffers from the ABA problem, because it might break our invariant that the values are strictly ordered.