浅谈chromium中的指针管理

转载自:http://www.starwd.com/?p=164

前言

在大型C++系统中对指针的管理通常至关重要,这跟对象的生命周期相关,存在如下方面的考虑:

  • 如何确保指针所指向的对象是在适当范围内是始终存在的?
  • 如何构建一种机制,确保能正确检测指针所指向对象是否有效?

在chromium中对这类问题分别采用智能指针Scoped_refptr和弱指针WeakPtr来实现。

Scoped_refptr

Scoped_refptr 在智能指针scoped_ptr基础之上增加了引用计数功能,但尤其需要注意的是,引用计数的功能并不是由scoped_refptr提供的,而是由scoped_refptr对象本身提供的,也就说使用scoped_refptr的对象必须具备引用计数功能。Chromium中的引用计数功能由RefCouneted类提供,获取引用计数功能可以如下定义该类:

[cpp]  view plain copy
  1. Class MyClass : public RefCounted { ….}  

Scoped_refptr 实现大致如下:

  • 重载了*、-> 操作符,使之具备指针一样的功能,即像使用指针一样的使用Scoped_refptr对象,但Scoped_refptr对象一般在在栈中分配,在其作用域外自动释放;
  • 重载了 = 赋值运算符,这样确保每次scoped_refptr 的每次传递、或者其所指对象被赋值给新的scoped_refptr对象时都能导致计数加1;
  • 一般来说scoped_refptr 所包含的对象初始引用计数为0;但将其放入scoped_refptr时会导致引用计数+1;
  • Release()函数代表所有权的转移;即scoped_refptr里保存的对象指针被赋值为NULL;返回对象指向的引用计数维持不变;
  • 引用计数为0是删除scoped_refptr所包含的对象

Chromium 中Scoped_refptr使用场景一般为明确为某一线程所拥有的对象、或者某一类聚合的另一个类。对于跨线程使用的对象场合,一般使用弱指针。

Weakptr

在chromium的多线程模型里,对象通常被不同的线程访问,这就牵涉到线程同步问题;传统方法采用锁机制,关于锁机制的优劣参见Chrome源码剖析。 chromium的多线程模型实现的一个基本原则是:尽量规避锁;采取的策略则是task机制。见下图:

假设如下场景,A线程需要B线程做一些事情,然后回到A线程继续做一些事情;在chromium下你可以这样来做:生成一个Task,放到B线程的队列中,在该Task的Run方法最后,会生成另一个Task,这个Task会放回到A的线程队列,由A来执行。在该模型中一个最核心的问题就是task传递、运行过程中所涉及的对象、数据的安全性问题。在考虑上述的场景,线程A委托给线程B task1 ,task1运行需要访问对象object1;同样,线程B委托给线程A task2,task2 需要访问对象object2. 由于线程都采用消息队列机制,即轮询task队列方式实现。这就可能存在如下问题:

  • 线程B 运行 task1时 object1已经被其他线程销毁;
  • 线程A运行task2是 object2已经被其他线程销毁;

这里你可以说如果我使用引用计数机制,确保object1和object2都不会被销毁当然可以解决问题。但更多的情况下我们可能需要的另一种情况,即取消task1、task2的运行。例如UI线程委托IO线程下载某个资源时,用户刷新了当前网页,显然这时IO线程的下载task应取消。这个问题的核心就是:如何构建一种机制,确保能正确监测指针所指向对象是否有效;也就是如果其实线程B检测到Object1已经无效了,则自动取消task1的运行。这实质也是weakptr 弱指针的所需要解决的问题。

在谈论weakptr之前,我们先来探讨现实中一般如何解决这类问题。如果这个时候,存在一个第三方认证机构C,A和B能够通过向机构C来查询获取某个object的状态来确定是否执行某个task,这样问题就既然就得以解决了。实质上,这也是weakptr所采取的方法。先看weakptr的定义:

[cpp]  view plain copy
  1. Template<class T>    
  2. Class  Weakptr : public internal::WeakPtrBase {  
  3. // …….  
  4. T* ptr;  
  5. };  
  6. Class WeakPtrBase {  
  7. Protected:  
  8. WeakReference ref_;  
  9. }  


显然WeakPtr 弱指针除了包括所指对象的指针外,还包括一个额外的弱应用 WeakReference ref_。ref_可以看作是对第三方机构C的引用,即通过判断ref_是否有效来判定WeakPtr所保存的指针ptr是否有效。下面是WeakReference的定义:

[cpp]  view plain copy
  1. class WeakReference {  
  2. public:  
  3. class Flag : public RefCounted, public NonThreadSafe {  
  4. public:  
  5. Flag(Flag** handle);  
  6. ~Flag();  
  7.    
  8. void AddRef() const;  
  9. void Release() const;  
  10. void Invalidate() { handle_ = NULL; }  
  11. bool is_valid() const { return handle_ != NULL; }  
  12.    
  13. void DetachFromThread() { NonThreadSafe::DetachFromThread(); }  
  14.    
  15. private:  
  16. Flag** handle_;  
  17. };  
  18. WeakReference();  
  19. WeakReference(Flag* flag);  
  20. ~WeakReference();  
  21.    
  22. bool is_valid() const;  
  23.    
  24. private:  
  25. scoped_refptr flag_;  
  26. }  


由上面定义可知有效性的检测实质由WeakReference内的Flag对象提供。接下来问题就是第三方机构C如何建立? WeakReference ref_ 又如何使用它呢?这牵涉到类WeakReferenceOwner和WeakPtrFactory。 这里有一个事实应首先清楚:在上面的场景中 Object1可能被task1所使用、也可能被task2、… taskN所使用,而且这些task可能还在不同的线程中运行。因此为确保所有线程运行这些task时都能检测到Object1是否有效,显然这里要求WeakReference ref_ 所实质引用的对象是同一个,而且要确保该对象的生命周期可能长于Object1,即Object1被销毁了它还存在。 类WeakReferenceOwner 顾名思义,是WeakReference的owner,即它用于保证所有相关WeakPtr 中WeakReference ref_引用的是同一个对象,具体到Chromium中即为同一个Flag对象。见WeakReferenceOwner::GetRef()的实现:

[cpp]  view plain copy
  1. WeakReference WeakReferenceOwner::GetRef() const {  
  2. if (!flag_)  
  3. flag_ = new WeakReference::Flag(&flag_);  
  4. return WeakReference(flag_);  
  5. }  

接下来的问题就是如何创建WeakPtr对象,显然这里应有如下两个需求:

  • 创建出来的WeakPtr跟实质所包含的对象是相关的,即设置ptr指针;
  • WeakReference ref_ 最终所引用的flag 是同一个。

这通过WeakPtrFactory 实现,WeakPtrFactory用于创建某个Object的Weakptr,定义如下:

[cpp]  view plain copy
  1. template <typename T>  
  2. class WeakPtrFactory {  
  3.  public:  
  4.   explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {  
  5.   }  
  6.    
  7.   WeakPtr GetWeakPtr() {  
  8.     return WeakPtr(weak_reference_owner_.GetRef(), ptr_);  
  9.   }  
  10.    
  11.   // Call this method to invalidate all existing weak pointers.  
  12.   void InvalidateWeakPtrs() {  
  13.     weak_reference_owner_.Invalidate();  
  14.   }  
  15.    
  16.   // Call this method to determine if any weak pointers exist.  
  17.   bool HasWeakPtrs() const {  
  18.     return weak_reference_owner_.HasRefs();  
  19.   }  
  20.    
  21.  private:  
  22.   internal::WeakReferenceOwner weak_reference_owner_;  
  23.   T* ptr_;  
  24.   DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);  
  25. }  


WeakPtrFactory 聚合了WeakReferenceOwner,用于保证指向同一个Flag。对于WeakPtrFactory的使用,可以在 相关Object中聚合一个该WeakPtrFactory, 这样可以直接通过Object的某个方法来获取其WeakPtr对象,例如:

Object1->weakptrfactory()->GetWeakPtr();

同时在Object的析构函数中调用WeakPtrFactory的InvalidateWeakPtrs函数,来使其Flag无效,最终供WeakPtr使用者检测其有效性。 对于另一个问题,如何确保所有WeakReference ref_ 所引用的Flag对象的生命周期长于Object本身,即Object销毁时它仍然存在,直到所有的WeakReference ref_都销毁时。显然,从Flag的定义可以看出,采用引用计数方式即可。关于WeakPtr的关系见下图:

参考文献

http://www.cnblogs.com/duguguiyu/archive/2008/10/02/1303095.html

[cpp]  view plain copy
  1. /*一、本文中包括以下几个类: 
  2.     RefCountedBase                   
  3.         -->为子类增加引用计数,基类的基类,无线程安全 
  4.     RefCountedThreadSafeBase         
  5.         -->为子类增加引用计数,基类的基类,有线程安全  
  6.     RefCounted:public RefCountedBase 
  7.         -->为子类增加引用计数,基类,线程安全 
  8.     RefCountedThreadSafe:public RefCountedThreadSafeBase  
  9.         -->为子类增加引用计数,基类,线程安全 
  10.     DefaultRefCountedThreadSafeTraits 
  11.         -->为RefCountedThreadSafe提供析构支持 
  12.     RefCountedData : public base::RefCounted< base::RefCountedData<T> > 
  13.         -->为其它数据增加引用计数 
  14.     scoped_refptr 
  15.         -->自身有作用域的、其对象带引用计数的 智能指针。出作用域就析构, 
  16.         释放自己对对象的引用。 
  17. */  
  18.   
  19.   
  20.   
  21. #ifndef BASE_MEMORY_REF_COUNTED_H_  
  22. #define BASE_MEMORY_REF_COUNTED_H_  
  23.   
  24. #include <cassert>  
  25.   
  26. #include "base/atomic_ref_count.h"  
  27. #include "base/base_export.h"  
  28. #include "base/compiler_specific.h"  
  29. #include "base/threading/thread_collision_warner.h"  
  30.   
  31. namespace base {  
  32.   
  33. namespace subtle {  
  34.   
  35. class BASE_EXPORT RefCountedBase {  
  36.  public://仅有一个引用时返回true  
  37.   bool HasOneRef() const { return ref_count_ == 1; }  
  38.  protected:  
  39.   RefCountedBase();  
  40.   ~RefCountedBase();  
  41.   
  42.   void AddRef() const;//增加引用计数  
  43.   // Returns true if the object should self-delete.  
  44.   bool Release() const;//减少引用计数  
  45.  private:  
  46.   mutable int ref_count_;  
  47. #ifndef NDEBUG  
  48.   mutable bool in_dtor_;  
  49. #endif  
  50.   
  51.   DFAKE_MUTEX(add_release_);  
  52.   
  53.   DISALLOW_COPY_AND_ASSIGN(RefCountedBase);  
  54. };  
  55.   
  56. class BASE_EXPORT RefCountedThreadSafeBase {  
  57.  public:  
  58.   bool HasOneRef() const;//仅有一个引用时返回true  
  59.   
  60.  protected:  
  61.   RefCountedThreadSafeBase();  
  62.   ~RefCountedThreadSafeBase();  
  63.   
  64.   void AddRef() const;//增加引用计数,原子地+=1  
  65.   // Returns true if the object should self-delete.  
  66.   bool Release() const;//增加引用计数,原子地-=1  
  67.   
  68.  private:  
  69.   mutable AtomicRefCount ref_count_;  
  70. #ifndef NDEBUG  
  71.   mutable bool in_dtor_;  
  72. #endif  
  73.   
  74.   DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);  
  75. };  
  76.   
  77. }  // namespace subtle  
  78. /* 
  79.     对父类接口进行包装,在release时释放自己的内存 
  80. */  
  81. template <class T>  
  82. class RefCounted : public subtle::RefCountedBase {  
  83.  public:  
  84.   RefCounted() {}  
  85.   
  86.   void AddRef() const {//直接调用父类的  
  87.     subtle::RefCountedBase::AddRef();  
  88.   }  
  89.   
  90.   void Release() const {  
  91.     if (subtle::RefCountedBase::Release()) {  
  92.         //释放内存,引用为0时父类Release返回True  
  93.         //会释放内存  
  94.       delete static_cast<const T*>(this);  
  95.     }  
  96.   }  
  97.   
  98.  protected:  
  99.   ~RefCounted() {}  
  100.   
  101.  private:  
  102.   DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);  
  103. };  
  104.   
  105. // Forward declaration.  
  106. template <class T, typename Traits> class RefCountedThreadSafe;  
  107.   
  108. /* 
  109.     在多线程情况下,用户可通过Traits来确定对象release时的操作,而 
  110.     下面这个结构是默认的操作,它将调用RefCountedThreadSafe的 
  111.     DeleteInternal来删除RefCountedThreadSafe子类对象,这个有点绕。 
  112.  */  
  113. template<typename T>  
  114. struct DefaultRefCountedThreadSafeTraits {  
  115.   static void Destruct(const T* x) {   
  116.     RefCountedThreadSafe<T,  
  117.                          DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);  
  118.   }  
  119. };  
  120.    
  121. template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >  
  122. class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {  
  123.  public:  
  124.   RefCountedThreadSafe() {}  
  125.   
  126.   void AddRef() const {  
  127.     //直接调用父类的  
  128.     subtle::RefCountedThreadSafeBase::AddRef();  
  129.   }  
  130.   
  131.   void Release() const {  
  132.       //先调用父类的,当引用为0时父类Release函数会返回True  
  133.       //这样的话,会调用释放内存的函数,同时用户可以通过  
  134.       //Traits来参与进来,决定内存怎么释放。  
  135.     if (subtle::RefCountedThreadSafeBase::Release()) {  
  136.       Traits::Destruct(static_cast<const T*>(this));  
  137.     }  
  138.   }  
  139.   
  140.  protected:  
  141.   ~RefCountedThreadSafe() {}  
  142.   
  143.  private:  
  144.   friend struct DefaultRefCountedThreadSafeTraits<T>;  
  145.   static void DeleteInternal(const T* x) { delete x; }  
  146.   
  147.   DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);  
  148. };  
  149.   
  150. //  
  151. // A wrapper for some piece of data so we can place other things in  
  152. // scoped_refptrs<>.  
  153. // 给一些其它数据增加计数引用  
  154. template<typename T>  
  155. class RefCountedData : public base::RefCounted< base::RefCountedData<T> > {  
  156.  public:  
  157.   RefCountedData() : data() {}  
  158.   RefCountedData(const T& in_value) : data(in_value) {}  
  159.   
  160.   T data;  
  161.   
  162.  private:  
  163.   friend class base::RefCounted<base::RefCountedData<T> >;  
  164.   ~RefCountedData() {}  
  165. };  
  166.   
  167. }  // namespace base  
  168. /* 
  169.     scoped_refptr智能指针    
  170.  */  
  171. template <class T>  
  172. class scoped_refptr {  
  173.  public:  
  174.   typedef T element_type;  
  175.   scoped_refptr() : ptr_(NULL) {//构造  
  176.   }  
  177.   scoped_refptr(T* p) : ptr_(p) {//构造  
  178.     if (ptr_)  
  179.       ptr_->AddRef();//子类必须是能引用计数的  
  180.   }  
  181.   //拷贝构造  
  182.   scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {     
  183.     if (ptr_)  
  184.       ptr_->AddRef();  
  185.   }  
  186.   //拷贝构造  
  187.   template <typename U>  
  188.   scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {  
  189.     if (ptr_)  
  190.       ptr_->AddRef();  
  191.   }  
  192.   //析构,释放本指针的引用,导致对象引用-=1  
  193.   ~scoped_refptr() {  
  194.     if (ptr_)  
  195.       ptr_->Release();  
  196.   }  
  197.   //返回对象  
  198.   T* get() const { return ptr_; }  
  199.   operator T*() const { return ptr_; }  
  200.   T* operator->() const {  
  201.     assert(ptr_ != NULL);  
  202.     return ptr_;  
  203.   }  
  204.   
  205.   // Release a pointer.  
  206.   // The return value is the current pointer held by this object.  
  207.   // If this object holds a NULL pointer, the return value is NULL.  
  208.   // After this operation, this object will hold a NULL pointer,  
  209.   // and will not own the object any more.  
  210.   // 本智能指针对象不再拥有object对象指针,将它传给其它智能指针对象  
  211.   T* release() WARN_UNUSED_RESULT {  
  212.     T* retVal = ptr_;  
  213.     ptr_ = NULL;  
  214.     return retVal;  
  215.   }  
  216.   //赋值,接受对象的指针,放弃本智能指针原来拥有的对象,致使原对象引用-=1  
  217.   //重新拥有新的对象  
  218.   scoped_refptr<T>& operator=(T* p) {  
  219.     // AddRef first so that self assignment should work  
  220.     if (p)  
  221.       p->AddRef();  
  222.     T* old_ptr = ptr_;  
  223.     ptr_ = p;  
  224.     if (old_ptr)  
  225.       old_ptr->Release();  
  226.     return *this;  
  227.   }  
  228.   //赋值,复制,将r指针所指的内容赋值给本智能指针  
  229.   scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {  
  230.     return *this = r.ptr_;  
  231.   }  
  232.   //赋值,复制,将r指针所指的内容赋值给本智能指针  
  233.   template <typename U>  
  234.   scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {  
  235.     return *this = r.get();  
  236.   }  
  237.   //swap内部函数  
  238.   void swap(T** pp) {  
  239.     T* p = ptr_;  
  240.     ptr_ = *pp;  
  241.     *pp = p;  
  242.   }  
  243.   //交换两个智能指针内容  
  244.   void swap(scoped_refptr<T>& r) {  
  245.     swap(&r.ptr_);  
  246.   }  
  247.   //那个对象,带引用计数的  
  248.  protected:  
  249.   T* ptr_;  
  250. };  
  251.   
  252. // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without  
  253. // having to retype all the template arguments  
  254. // 返回对象指针的智能指针对象  
  255. template <typename T>  
  256. scoped_refptr<T> make_scoped_refptr(T* t) {  
  257.   return scoped_refptr<T>(t);  
  258. }  
  259.   
  260. #endif  // BASE_MEMORY_REF_COUNTED_H_  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值