非阻塞线程安全堆栈

Non-blocking thread-safe stack

本文关键字:安全 堆栈 线程      更新时间:2023-10-16

最近我一直在阅读 Anthony Williams - C++ 并发在行动,我到了作者建议非阻塞线程安全堆栈实现的章节。在 pop() 的第一个实现中,据说该方法不是线程安全的。问题是为什么它不是线程安全的?换句话说 - 有人可以指出我数据竞赛在哪里吗?

#include <memory>
#include <thread>
#include <iostream>
#include <atomic>
using namespace std;
template <class T>
class lock_free_stack
{
  private:
    struct Node
    {
        std::shared_ptr<T> data_;
        Node *next;

        Node(const T& data): data_(std::make_shared<T>(data)) 
        {
        }
    };
    std::atomic<Node *> head;

    public:
    lock_free_stack() { head.store(nullptr); }
    void push(T const& data)  
    {
        Node* const newNode = new Node(data);
        newNode->next = head.load();
        while(!head.compare_exchange_weak(newNode->next, newNode));
    }
    // The following function is not thread-safe
    std::shared_ptr<T> pop()
    {
        Node* old_head = head.load();
        while (old_head && !head.compare_exchange_weak(old_head, old_head->next)); // Atomically
        unique_ptr<Node> deleter;
        if(old_head)
            deleter.reset(old_head);
        return old_head ? old_head->data_ : std::shared_ptr<T>();
    }
};

竞争条件是一个线程可以评估old_head->next,就在调用unique_ptr的析构函数删除old_head指向的节点时(或之后)。