首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么不能释放从lock_free_stack中的pop()中的原子lock_free_stack中检索的节点?

为什么不能释放从lock_free_stack中的pop()中的原子lock_free_stack中检索的节点?
EN

Stack Overflow用户
提问于 2022-06-30 15:59:07
回答 2查看 93关注 0票数 1

我正在读“第二行动中的由安东尼威廉姆斯第7.2.2节停止这些讨厌的泄漏:管理内存的无锁数据结构。

在本节之前,我们实现了一个lock_free_stack

代码语言:javascript
运行
复制
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()应该是:

代码语言:javascript
运行
复制
  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;
  }

如何理解安东尼说的话?

EN

Stack Overflow用户

发布于 2022-06-30 16:26:49

比赛到了

代码语言:javascript
运行
复制
  while (old_head && !head.compare_exchange_weak(old_head, old_head->next));
                                                           ^^^^^^^^^^^^^^

一个可能的竞赛是:

exchange

  • Thread 2调用old_head

  • Thread 2调用head.load(),检索地址X

  • 线程2调用head.load()的节点,检索地址X

  • Thread 2上的节点是否在地址X

  • Thread 1尝试读取compare_exchange_weak

之前执行自己的操作

票数 3
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72818797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档