Reputation: 13512
At http://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange, the following example code is presented as an example use of std::atomic_compare_exchange_weak
:
void append(list* s, node* n)
{
node* head;
do {
head = s->head;
n->next = head;
} while(! std::atomic_compare_exchange_weak(s->head, head, n));
}
My understanding is that this has the the effect of comparing *(s->head)
with head
, when what I believe is desired is to compare s->head
with head
. Should the first argument to std::atomic_compare_exchange_weak
in this example be &(s->head)
, or am I missing something?
UPDATE: The spec for std::atomic_compare_exchange_weak
says:
bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired) noexcept;
bool atomic_compare_exchange_weak(A* object, C * expected, C desired) noexcept;
Effects: Atomically, compares the contents of the memory pointed to by object...for equality with that in expected...
I took this to mean that *object
was compared with expected
, but further research suggests that the actual meaning is that *object
is compared with *expected
(i.e., that "in expected
" means "pointed to by expected
"). This would imply that the answer to my original question is "no, there is no need to take the address of s->head
in the example code at cppreference". But the fact that object
must point to a std::atomic<T>
and expected must point to a T
makes it hard for me to figure out how to correct the code at cppreference so that it will compile. We want to compare the head of the list with a copy of the head of the list, but if the head of the list is of type std::atomic<T>*
, the copy would have to be of type T*
if the call to std::atomic_compare_exchange_weak
is to compile, and I can't find a way to assign a std::atomic<T>*
to a T*
without a reinterpret_cast
. Even then, the third parameter to std::atomic_compare_exchange_weak
would need to be of type T
, but the example at cppreference shows both the second and third parameters to be of the same type. This suggests to me that the example at cppreference is broken. I tried to fix it, but I was stymied by the need to use a reinterpret_cast
that just feels wrong.
Interestingly, in my attempts to figure this stuff out, I checked out the msdn page for std::atomic_compare_exchange_weak
, and I was dismayed to see that that page displays the prototypes for std::atomic_compare_exchange_*strong*
!
Can somebody post plausible code that uses std::atomic_compare_exchange_weak
to insert a node at the front of a singly-linked list? There's no need to worry about the ABA problem or do anything fancy. I'd just like to see skeletal code that compiles.
Upvotes: 8
Views: 4030
Reputation:
A correct example would be:
struct list {
std::atomic<node*> head;
};
...
void append(list* s, node* n)
{
node* head;
do {
head = s->head;
n->next = head;
} while (!std::atomic_compare_exchange_weak(&(s->head), &head, n));
// or while (!s->head.compare_exchange_weak(head, n));
}
The list::head
would need to be a std::atomic
object, unless you want to deal with undefined behavior. The platform in question might need some or all of the std::atomic
stuff to be implemented using locks. Therefore, std::atomic<T*>
might include additional members and reinterpret_cast<std::atomic<T*>*>
would be the case where UB means that your program crashes.
Upvotes: 2