Real world example where std :: atomic :: compare_exchange is used with two memory_order parameters

Can you give an example in the real world, where for some reason two versions of the memory parameter are used std::atomic::compare_exchange(therefore an incorrect version of one memory_order parameter)?

+4
source share
1 answer

In many cases, the second memory ordering parameter is not compare_exchangeset to memory_order_relaxed. In such cases, as a rule, this is not the case to omit it, but is potentially less effective.

, , /, , compare_exchange_weak, .

push , , , push; .. .

template<typename T>
class mystack {

    struct node {
        node *next = nullptr;

        T data;
        int id;

        node(int id) : id{id} { }
    };

    std::atomic<node *> head{nullptr};

public:
    void push(T data, int id);
    bool pop(T &data); // not implemented
};


template<typename T>
void mystack<T>::push(T data, int id)
{
    node *newnode = new node{id};

    newnode->data = std::move(data);

    node *current_head = head.load(std::memory_order_relaxed);   // A

    for (;;)
    {
        newnode->next = current_head;

        if (head.compare_exchange_weak(current_head, newnode,
                                       std::memory_order_release,   // B
                                       std::memory_order_acquire))  // C
        {
            /*
             * 'current_head' may not be derefenced here since the initial load (at A)
             * does not order memory 'current_head' is pointing at.
             *
             * a release barrier (at B) is necessary to make 'newnode' available
             * to other threads
             */
            std::cout << "Insertion successful\n";

            break;

        } else
        {
            /*
             * 'current_head' is the updated head pointer after 'compare_exchange' failed
             * Since it was inserted by another thread (the CAS failed),
             * an acquire barrier must be set (at C) in order to be able to access data
             * 'current_head' is pointing at.
             */
            std::cout << "Insertion failed after head changed to id: " <<
                          current_head->id << std::endl;
        }
    }
}

push load ( A) , , , head , , , , .

, compare_exchange_weak , newnode , ( B). , ( pop), .

, compare_exchange_weak ( ), node current_head head. current_head , , , , current_head .
, cout current_head->id.

, load, , memory_order_relaxed, current_head->id.

+4

Source: https://habr.com/ru/post/1684029/


All Articles