C++11 当我们实现无锁数据结构时,为什么需要管理内存?

C++11 当我们实现无锁数据结构时,为什么需要管理内存?,c++11,concurrency,lock-free,C++11,Concurrency,Lock Free,当我们实现无锁数据结构时,为什么需要管理内存?考虑下面的堆栈示例,为什么POP函数中的“删除OLDYHEAD”语句,如书所说,会导致其他线程出现问题?我不认为“取消对悬空指针的引用”会发生,我运行了几次代码,没有得到任何错误 template<typename T> class lock_free_stack { private: struct node { std::shared_ptr<T> data; node* ne

当我们实现无锁数据结构时,为什么需要管理内存?考虑下面的堆栈示例,为什么POP函数中的“删除OLDYHEAD”语句,如书所说,会导致其他线程出现问题?我不认为“取消对悬空指针的引用”会发生,我运行了几次代码,没有得到任何错误

template<typename T>
class lock_free_stack
{
private:
    struct node
    {
        std::shared_ptr<T> data;
        node* next;
        node(T const& data_) :
            data(std::make_shared<T>(data_))
        {}
    };
    std::atomic<node*> head;

public:
    void push(T const& data)
    {
        node* const new_node = new node(data);
        new_node->next = head.load();
        while (!head.compare_exchange_weak(new_node->next, new_node));
    }

    std::shared_ptr<T> pop()
    {
        node* old_head = head.load();
        while (old_head &&
            !head.compare_exchange_weak(old_head, old_head->next));
        auto res = old_head ? old_head->data : nullptr;
        delete old_head;
        return res;
    }
};
模板
类锁\u自由\u堆栈
{
私人:
结构节点
{
std::共享的ptr数据;
节点*下一步;
节点(T常数和数据):
数据(标准::使共享(数据))
{}
};
原子头;
公众:
无效推送(T常量和数据)
{
node*const new_node=新节点(数据);
新建节点->下一步=head.load();
而(!head.compare_exchange_弱(新建节点->下一步,新建节点));
}
std::共享的\u ptr pop()
{
节点*old_head=head.load();
当(老)头&&
!head.compare_exchange_weak(old_head,old_head->next));
自动恢复=旧头?旧头->数据:空头;
删除旧头;
返回res;
}
};

想象两个线程同时进入
pop
。两者都为
旧头
获取相同的值。然后线程A继续执行
删除旧的\u头
。然后线程B通过一个悬空指针读取
old\u head->next
,该指针显示未定义的行为。但是,线程B通过compare\u exchange\u弱()语句读取old\u head->next,该语句可以将old\u head重置为线程a修改的新head,然后在下一个循环中,old\u head->next没有问题。否-线程B读取
old\u head->next
,然后将这样读取的值传递给
compare\u exchange\u weak
函数(该函数可以使用也可以不使用它)。与任何函数调用一样,参数的求值发生在函数体执行之前。线程A初始化
old\u head
并读取
old\u head->next
。然后,就在调用
compare\u exchange\u-weak
之前,线程B执行
pop
两次和
push
一次。纯粹出于偶然,现在可用的
old\u head
仍然指向的块被重新用于
push
中的
new\u节点。此时,线程A继续执行
compare\u exchange\u-weak
head==old\u head
因此交换发生了-但是线程A在调用之前加载的
old\u head->next
的值现在是垃圾。是的。我真傻。非常感谢你。