std::shared_ptr 和 std::experimental::atomic_shared_ptr 有什么区别? [英] What is the difference between std::shared_ptr and std::experimental::atomic_shared_ptr?

查看:30
本文介绍了std::shared_ptr 和 std::experimental::atomic_shared_ptr 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I read the following article by Antony Williams and as I understood in addition to the atomic shared count in std::shared_ptr in std::experimental::atomic_shared_ptr the actual pointer to the shared object is also atomic?

但是当我读到安东尼关于 lock_free_stack 的引用计数版本时"noreferrer" rel="nofollow noreferrer">C++ 并发 对我来说,std::shared_ptr 似乎也是如此,因为像 std::atomic_load 这样的函数code>、std::atomic_compare_exchnage_weak 应用于std::shared_ptr 的实例.

But when I read about reference counted version of lock_free_stack described in Antony's book about C++ Concurrency it seems for me that the same aplies also for std::shared_ptr, because functions like std::atomic_load, std::atomic_compare_exchnage_weak are applied to the instances of 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实例中的指针不是原子的,为什么上面的无锁栈实现是可能的?

What is the exact difference between this two types of smart pointers, and if pointer in std::shared_ptr instance is not atomic, why it is possible the above lock free stack implementation?

推荐答案

shared_ptr 中的原子事物"不是共享指针本身,而是它指向的控制块.这意味着只要您不跨多个线程改变 shared_ptr ,就可以.请注意,复制一个 shared_ptr 只会改变控制块,而不是 shared_ptr 本身.

The atomic "thing" in shared_ptr is not the shared pointer itself, but the control block it points to. meaning that as long as you don't mutate the shared_ptr across multiple threads, you are ok. do note that copying a shared_ptr only mutates the control block, and not the shared_ptr itself.

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 
}

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

Mutating the shared pointer itself, such as assigning it different values from multiple threads, is a data race, for example:

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);
});    

在这里,我们改变了控制块(这没问题)以及共享指针本身,通过使其指向来自多个线程的不同值.这不行.

Here, we are mutating the control block (which is ok) but also the shared pointer itself, by making it point to a different values from multiple threads. This is not ok.

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

A solution to that problem is to wrap the shared_ptr with a lock, but this solution is not so scalable under some contention, and in a sense, loses the automatic feeling of the standard shared pointer.

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

Another solution is to use the standard functions you quoted, such as std::atomic_compare_exchange_weak. This makes the work of synchronizing shared pointers a manual one, which we don't like.

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

This is where atomic shared pointer comes to play. You can mutate the shared pointer from multiple threads without fearing a data race and without using any locks. The standalone functions will be members ones, and their use will be much more natural for the user. This kind of pointer is extremely useful for lock-free data structures.

这篇关于std::shared_ptr 和 std::experimental::atomic_shared_ptr 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆