我正在读“第二行动中的由安东尼威廉姆斯第7.2.2节停止这些讨厌的泄漏:管理内存的无锁数据结构。
在本节之前,我们实现了一个lock_free_stack
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));
return old_head ? old_head->data : std::shared_ptr<T>();
}
};安东尼在第7.2.2节中说:
当您第一次查看pop()时,您选择了泄漏节点,以避免出现这样的情况:一个线程删除一个节点,而另一个线程仍然保存一个指向它即将取消引用的指针。
--我不明白,如果两个线程同时调用pop(),每个线程将得到不同的头,因此每个线程的old_head彼此不同,它们可以自由地删除old_head。
在我看来,没有内存泄漏的pop()应该是:
std::shared_ptr<T> pop() {
node *old_head = head.load();
while (old_head && !head.compare_exchange_weak(old_head, old_head->next));
std::shared_ptr<T> res = old_head ? old_head->data : std::shared_ptr<T>();
delete old_head;
return res;
}如何理解安东尼说的话?
发布于 2022-06-30 16:26:49
比赛到了
while (old_head && !head.compare_exchange_weak(old_head, old_head->next));
^^^^^^^^^^^^^^一个可能的竞赛是:
exchange
compare_exchange_weak之前执行自己的操作
发布于 2022-06-30 16:27:23
让我们假设两个线程同时进入pop,但是线程2被中断了一点,如下所示:
Thread 1 Thread 2
node *old_head = head.load(); node *old_head = head.load();
while (old_head &&
!head.compare_exchange_weak(old_head,
old_head->next));
std::shared_ptr<T> res =
old_head ? old_head->data
: std::shared_ptr<T>();
delete old_head;
while (old_head &&
!head.compare_exchange_weak(old_head,
old_head->next));两个线程都以相同的old_head = head.load();启动。然后线程1删除对象,在该线程2访问old_head->next之后。这是免费的。
https://stackoverflow.com/questions/72818797
复制相似问题