c++11 std::atomiccompare_exchange_weak和堆栈容器
c++11 std::atomic compare_exchange_weak and the stack container
我正在为C++11编写Anthony Williams Concurrency一书。
我对无锁堆栈的pop实现有点困惑。
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));
// Does This not return the data of the next node before the head if
// compare_exchange_weak returns true
return old_head ? old_head->data : std::shared_ptr<T>();
}
};
让我感到困惑的是pop函数的最后两行。
while( old_head && !head.compare_exchange_weak(old_head, old_head->next));
return old_head ? old_head->data : std::shared_ptr<T>();
如果compare_exchange_weak函数返回true,它不会将old_head更改为堆栈中的下一个节点吗?当old_head不是nullptr时,这将导致return语句从下一个节点返回数据,而不是从堆栈顶部的旧头返回数据。
我把这个解释错了吗?
除了我的评论之外,如果compare_exchange_weak成功,它成功地将head
从值old_head
更新为值old_head->next
,因此old_head不再是列表的一部分,因此可以正确返回。
只有当它返回false
时,它才会修改old_head
的值
编辑:显示上述代码的问题。
首先,如果两个线程进入pop
,并且都读取head
(通过head.load()
),并且获得相同的old_head
值
线程1被换出(比如)
线程二继续运行,弹出头并返回给调用者,然后调用者删除保存节点的值。
线程一然后恢复并尝试读取old_head->next
,甚至调用compare_exchange_weak。
但是,old_head指向已删除的内存。未定义的行为,如果你犯错,那你就是幸运的。
其次,这有典型的ABA问题。我不想解释,因为它有很好的记录和理解。搜索它。
当head.compare_exchange_weak
返回false
时,它会修改old_head
。
当它返回true
时,它修改head
而不修改old_head
。
请参阅http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange和/或http://cpp0x.centaur.ath.cx/atomics.types.operations.req.html#p21
- 算法问题:查找从堆栈中弹出的所有序列
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 堆栈和队列是否像C++中的数组一样传递?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 堆栈中大小变量输入错误 (C++)
- 堆栈问题(平衡表达式问题集)
- C++ 在堆栈中包含多态属性的类对象存储
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 在 C++ 中使用链表进行堆栈
- 变量周围的堆栈'...'已损坏
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- C++线程的可用堆栈大小