本文介绍了原子参考计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我试图了解线程安全的原子引用计数是如何工作的,例如 std :: shared_ptr 。我的意思是,基本的概念很简单,但我真的很困惑,如何使用减法加删除避免竞争条件。 此 Boost 教程演示了如何使用Boost原子库(或C ++ 11原子库)实现原子线程安全引用计数系统。 #include< boost / intrusive_ptr.hpp> #include< boost / atomic.hpp> class X { public: typedef boost :: intrusive_ptr< X>指针; X():refcount_(0){} private: mutable boost :: atomic< int> refcount_; friend void intrusive_ptr_add_ref(const X * x) { x-> refcount_.fetch_add(1,boost :: memory_order_relaxed); } friend void intrusive_ptr_release(const X * x) { if(x-> refcount_.fetch_sub(1,boost :: memory_order_release)== 1){ boost :: atomic_thread_fence(boost :: memory_order_acquire); delete x; } } }; 好吧,所以我得到了一般的想法。但我不明白为什么下面的情况是不可能的: 说引用计数目前是 1 。 / p> 线程A :atomically将引用减少为 0 。 线程B :将引用计数原子地增加到 1 。 线程A :在托管对象指针上调用 delete 。 / em>:查看引用计数 1 ,访问托管对象指针... SEGFAULT! ol> 我不明白阻止这种情况发生的原因,因为在引用计数达到0之前,没有什么能阻止之间的数据竞争。该对象被删除。解释引用计数并调用 delete 是两个单独的非原子操作。 解决方案你可能高估了shared_ptr提供的线程安全性。 原子计数的本质是确保如果两个不同实例 shared_ptr (管理同一对象)被访问/修改,将不会有竞争条件。但是, shared_ptr 不能确保线程安全,如果两个线程访问相同的 shared_ptr 对象写)。一个例子是如果一个线程解引用指针,而另一个线程重置它。 所以关于 shared_ptr gurantees的唯一事情是,不会有双删除和泄漏,只要没有在一个shared_ptr的单个实例上的竞争(它也不会访问对象,它指向线程安全) 结果,也创建一个shared_ptr的副本只是种族免费,如果没有其他线程,可以逻辑删除/重置它在同一时间(你也可以说,它不是内部同步)。 重复一次:访问单个 shared_ptr 多个线程中的实例,其中这些访问之一是写入(指针)仍然是竞争条件。 如果你想要eg以线程安全的方式复制 std :: shared_ptr ,您必须确保所有加载和存储都通过 std :: atomic _... 专门用于 shared_ptr 。 I'm trying to understand exactly how thread-safe, atomic reference counting works, for example as with std::shared_ptr. I mean, the basic concept is simple, but I'm really confused about how the decref plus delete avoids race conditions.This tutorial from Boost demonstrates how an atomic thread-safe reference counting system can be implemented using the Boost atomic library (or the C++11 atomic library).#include <boost/intrusive_ptr.hpp>#include <boost/atomic.hpp>class X {public: typedef boost::intrusive_ptr<X> pointer; X() : refcount_(0) {}private: mutable boost::atomic<int> refcount_; friend void intrusive_ptr_add_ref(const X * x) { x->refcount_.fetch_add(1, boost::memory_order_relaxed); } friend void intrusive_ptr_release(const X * x) { if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) { boost::atomic_thread_fence(boost::memory_order_acquire); delete x; } }};Okay, so I get the general idea. But I don't understand why the following scenario is NOT possible:Say the refcount is currently 1.Thread A: atomically decrefs the refcount to 0. Thread B: atomically increfs the refcount to 1.Thread A: calls delete on the managed object pointer.Thread B: sees the refcount as 1, accesses the managed object pointer... SEGFAULT!I can't understand what prevents this scenario from occurring, since there is nothing preventing a data race from between the time the refcount reaches 0, and the object is deleted. Decrefing the refcount and calling delete are two separate, non-atomic operations. So how is this possible without a lock? 解决方案 You probably overestimate the threadsafety a shared_ptr provides. The essence of atomic ref counting is to ensure that if two different instances of a shared_ptr (that are managing the same object) are accessed/modified, there will be no race condition. However, shared_ptr doesn't ensure thread safety, if two threads access the same shared_ptr object (and one of them is a write). One example would be e.g. if one thread dereferences the pointer, while the other resets it.So about the only thing shared_ptr gurantees is that there will be no double delete and no leak as long as there is no race on a single instance of a shared_ptr (It also doesn't make accesses to the object it points to threadsafe)As a result, also creating a copy of a shared_ptr is only race free, if there is no other thread, that could logically delete/reset it at the same time (you could also say, it is not internally synchronized). This is the scenario you describe.To repeat it once more: Accessing a single shared_ptr instance from multiple threads where one of those accesses is a write (to the pointer) is still a race condition.If you want to e.g. copy a std::shared_ptrin a threadsafe manner, you have to ensure that all loads and stores happen via std::atomic_... operations which are specialized for shared_ptr. 这篇关于原子参考计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-22 15:03