c++ - std::shared_ptr 和 std::experimental::atomic_shared_ptr 有什么区别?

标签 c++ c++11 concurrency atomic smart-pointers

我阅读了 following Antony Williams 的文章,据我了解,除了 std::experimental::atomic_shared_ptrstd::shared_ptr 中的原子共享计数之外指向共享对象的实际指针也是原子的?

但是当我读到安东尼的书中关于 C++ Concurrencylock_free_stack 的引用计数版本时在我看来,同样适用于 std::shared_ptr,因为应用了 std::atomic_loadstd::atomic_compare_exchnage_weak 等函数到 std::shared_ptr 的实例。

template <class T>
class lock_free_stack
{
public:
  void push(const T& data)
  {
    const std::shared_ptr<node> new_node = std::make_shared<node>(data);
    new_node->next = std::atomic_load(&head_);
    while (!std::atomic_compare_exchange_weak(&head_, &new_node->next, new_node));
  }

  std::shared_ptr<T> pop()
  {
    std::shared_ptr<node> old_head = std::atomic_load(&head_);
    while(old_head &&
          !std::atomic_compare_exchange_weak(&head_, &old_head, old_head->next));
    return old_head ? old_head->data : std::shared_ptr<T>();
  }

private:
  struct node
  {
    std::shared_ptr<T> data;
    std::shared_ptr<node> next;

    node(const T& data_) : data(std::make_shared<T>(data_)) {}
  };

private:
  std::shared_ptr<node> head_;
};

这两种智能指针的确切区别是什么,如果 std::shared_ptr 实例中的指针不是原子的,为什么上面的无锁堆栈实现是可能的?

最佳答案

shared_ptr 中的原子“东西”不是共享指针本身,而是它指向的控制 block 。这意味着只要您不跨多个线程改变 shared_ptr ,就可以了。请注意复制 shared_ptr 只会改变控制 block ,而不是shared_ptr 本身。

std::shared_ptr<int> ptr = std::make_shared<int>(4);
for (auto i =0;i<10;i++){
   std::thread([ptr]{ auto copy = ptr; }).detach(); //ok, only mutates the control block 
}

改变共享指针本身,例如从多个线程为其分配不同的值,是一种数据竞争,例如:

std::shared_ptr<int> ptr = std::make_shared<int>(4);
std::thread threadA([&ptr]{
   ptr = std::make_shared<int>(10);
});
std::thread threadB([&ptr]{
   ptr = std::make_shared<int>(20);
});    

在这里,我们正在改变控制 block (这没关系)以及共享指针本身,通过使其指向来自多个线程的不同值。这不行。

解决这个问题的方法是用锁包裹 shared_ptr,但是这种解决方案在某些争用下没有那么大的可扩展性,并且在某种意义上失去了标准共享指针的自动感觉。

另一种解决方案是使用您引用的标准函数,例如 std::atomic_compare_exchange_weak。这使得同步共享指针的工作变成了我们不喜欢的手动工作。

这就是原子共享指针发挥作用的地方。您可以从多个线程中改变共享指针,而不必担心数据竞争,也无需使用任何锁。独立功能将是成员功能,它们的使用对用户来说会更加自然。这种指针对于无锁数据结构非常有用。

关于c++ - std::shared_ptr 和 std::experimental::atomic_shared_ptr 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40223599/

相关文章:

c++ - 如何初始化以结构为值的映射?

c++ - C++ qt 的其他等效库是什么

c++ - 初始化顺序失败的可能解决方案?

c++ - 在构造函数或静态中创建时qtimer崩溃

c - 在 C 中从 shell 声明全局 CHAR 数组

c++ - 在同一个头文件中定义底层的顶层类初始化

c++ - 将元素插入 std::queue 时避免复制

c++ - 为什么 lambda 返回 bool 值?

java - 收听然后发送订阅 RxJava

scala - 在 Scala 中,synchronized block 是否锁定 block 中访问的所有全局变量?