C++11 当我们实现无锁数据结构时,为什么需要管理内存?
当我们实现无锁数据结构时,为什么需要管理内存?考虑下面的堆栈示例,为什么POP函数中的“删除OLDYHEAD”语句,如书所说,会导致其他线程出现问题?我不认为“取消对悬空指针的引用”会发生,我运行了几次代码,没有得到任何错误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
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
的值现在是垃圾。是的。我真傻。非常感谢你。