Search code examples
c++atomicgcc9

It is possible to getting stuck in the compare_exchange's loop?


Consider this code (from 'C++ concurrency in action' [Second edition]: page 212):

void LockFreeStack::pop (stack_data& result)
{
    Node* old_head = head.load();
    while(!head.compare_exchange_weak(old_head, old_head->next))
        ;
    result = old_head->data;
}

I think it's possible to thread-one execute pop() and after executing first line (loading head) time slicing happened to thread-two, which is executing push(T&). So now value of head atomic variable is not equal to old_head and while-loop won't break.
It's right ?


Solution

  • assuming head is a std::atomic<Node*> then the code is correct as when compare_exchange_weak fails it loads the current value of the variable into its first parameter, after the compare_exchange_weak call old_head will always contain the current value of head.

    The code is roughly equivalent to doing the following without atomics:

    Node* old_head = head;
    while (true)
    {
      std::unique_lock lock(mutex);
      if (old_head == head)
      {
         head = old_head->next;
         break;
      }
      else
      {
         old_head = head;
      }
    }
    

    Concurrent calls to pop are therefore safe and shouldn't block forever (other than due to other threads constantly calling pop and somehow always setting the value before the current thread gets a chance).