Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(4)

简介:

 回到外层的if语句中,如果目标对象的生命周期是受弱引用计数控制的,就执行下面语句:

 
 
  1. impl->mBase->onLastWeakRef(id);   
  2. if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {   
  3.     delete impl->mBase;   
  4. }   

   理论上说,如果目标对象的生命周期是受弱引用计数控制的,那么当强引用计数和弱引用计数都为0的时候,这时候就应该delete目标对象了,但是这里还有另外一层控制,我们可以设置目标对象的标志值为OBJECT_LIFETIME_FOREVER,即目标对象的生命周期完全不受强引用计数和弱引用计数控制,在这种情况下,即使目标对象的强引用计数和弱引用计数都同时为0,这里也不能delete这个目标对象,那么,由谁来delete掉呢?当然是谁new出来的,就谁来delete掉了,这时候智能指针就完全退化为普通指针了,这里的智能指针设计的非常强大。

 

        分析到这里,有必要小结一下:

        A. 如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;

        B. 如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;

        C. 如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。

        到了这里,强指针就分析完成了,最后来分析弱指针。

        4. 弱指针

        弱指针所使用的引用计数类与强指针一样,都是RefBase类,因此,这里就不再重复介绍了,我们直接来弱指针的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:

 
 
  1. template <typename T>   
  2. class wp   
  3. {   
  4. public:   
  5.     typedef typename RefBase::weakref_type weakref_type;   
  6.    
  7.     inline wp() : m_ptr(0) { }   
  8.    
  9.     wp(T* other);   
  10.     wp(const wp<T>& other);   
  11.     wp(const sp<T>& other);   
  12.     template<typename U> wp(U* other);   
  13.     template<typename U> wp(const sp<U>& other);   
  14.     template<typename U> wp(const wp<U>& other);   
  15.    
  16.     ~wp();   
  17.    
  18.     // Assignment   
  19.    
  20.     wp& operator = (T* other);   
  21.     wp& operator = (const wp<T>& other);   
  22.     wp& operator = (const sp<T>& other);   
  23.    
  24.     template<typename U> wp& operator = (U* other);   
  25.     template<typename U> wp& operator = (const wp<U>& other);   
  26.     template<typename U> wp& operator = (const sp<U>& other);   
  27.    
  28.     void set_object_and_refs(T* other, weakref_type* refs);   
  29.    
  30.     // promotion to sp   
  31.    
  32.     sp<T> promote() const;   
  33.    
  34.     // Reset   
  35.    
  36.     void clear();   
  37.    
  38.     // Accessors   
  39.    
  40.     inline  weakref_type* get_refs() const { return m_refs; }   
  41.    
  42.     inline  T* unsafe_get() const { return m_ptr; }   
  43.    
  44.     // Operators   
  45.    
  46.     COMPARE_WEAK(==)   
  47.         COMPARE_WEAK(!=)   
  48.         COMPARE_WEAK(>)   
  49.         COMPARE_WEAK(<)   
  50.         COMPARE_WEAK(<=)   
  51.         COMPARE_WEAK(>=)   
  52.    
  53.         inline bool operator == (const wp<T>& o) const {   
  54.             return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);   
  55.     }   
  56.     template<typename U>   
  57.     inline bool operator == (const wp<U>& o) const {   
  58.         return m_ptr == o.m_ptr;   
  59.     }   
  60.    
  61.     inline bool operator > (const wp<T>& o) const {   
  62.         return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);   
  63.     }   
  64.     template<typename U>   
  65.     inline bool operator > (const wp<U>& o) const {   
  66.         return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);   
  67.     }   
  68.    
  69.     inline bool operator < (const wp<T>& o) const {   
  70.         return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);   
  71.     }   
  72.     template<typename U>   
  73.     inline bool operator < (const wp<U>& o) const {   
  74.         return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);   
  75.     }   
  76.     inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }   
  77.     template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }   
  78.     inline bool operator <= (const wp<T>& o) const { return !operator > (o); }   
  79.     template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }   
  80.     inline bool operator >= (const wp<T>& o) const { return !operator < (o); }   
  81.     template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }   
  82.    
  83. private:   
  84.     template<typename Y> friend class sp;   
  85.     template<typename Y> friend class wp;   
  86.    
  87.     T*              m_ptr;   
  88.     weakref_type*   m_refs;   
  89. };   

 与强指针类相比,它们都有一个成员变量m_ptr指向目标对象,但是弱指针还有一个额外的成员变量m_refs,它的类型是weakref_type指针,下面我们分析弱指针的构造函数时再看看它是如果初始化的。这里我们需要关注的仍然是弱指针的构造函数和析构函数。

        先来看构造函数:

 
 
  1. template<typename T>   
  2. wp<T>::wp(T* other)   
  3.     : m_ptr(other)   
  4. {   
  5.     if (other) m_refs = other->createWeak(this);   
  6. }   

  这里的参数other一定是继承了RefBase类,因此,这里调用了RefBase类的createWeak函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:

 
 
  1. RefBase::weakref_type* RefBase::createWeak(const void* id) const   
  2. {   
  3.     mRefs->incWeak(id);   
  4.     return mRefs;   
  5. }   

  这里的成员变量mRefs的类型为weakref_impl指针,weakref_impl类的incWeak函数我们在前面已经看过了,它的作用就是增加对象的弱引用计数。函数最后返回mRefs,于是,弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。

        再来看析构函数:

 
 
  1. template<typename T>   
  2. wp<T>::~wp()   
  3. {   
  4.     if (m_ptr) m_refs->decWeak(this);   
  5. }   

  这里,弱指针在析构的时候,与强指针析构不一样,它直接就调用目标对象的weakref_impl对象的decWeak函数来减少弱引用计数了,当弱引用计数为0的时候,就会根据在目标对象的标志位(0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER)来决定是否要delete目标对象,前面我们已经介绍过了,这里就不再介绍了。

 

        分析到这里,弱指针还没介绍完,它最重要的特性我们还没有分析到。前面我们说过,弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了:

 
 
  1. template<typename T>   
  2. sp<T> wp<T>::promote() const   
  3. {   
  4.     return sp<T>(m_ptr, m_refs);   
  5. }   

     升级的方式就使用成员变量m_ptr和m_refs来构造一个强指针sp,这里的m_ptr为指目标对象的一个指针,而m_refs则是指向目标对象里面的weakref_impl对象。

        我们再来看看这个强指针的构造过程:

 
 
  1. template<typename T>   
  2. sp<T>::sp(T* p, weakref_type* refs)   
  3.     : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)   
  4. {   
  5. }   

   主要就是初始化指向目标对象的成员变量m_ptr了,如果目标对象还存在,这个m_ptr就指向目标对象,如果目标对象已经不存在,m_ptr就为NULL,升级成功与否就要看refs->attemptIncStrong函数的返回结果了:

 
 
  1. bool RefBase::weakref_type::attemptIncStrong(const void* id)   
  2. {   
  3.     incWeak(id);   
  4.    
  5.     weakref_impl* const impl = static_cast<weakref_impl*>(this);   
  6.    
  7.     int32_t curCount = impl->mStrong;   
  8.     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",   
  9.         this);   
  10.     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {   
  11.         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {   
  12.             break;   
  13.         }   
  14.         curCount = impl->mStrong;   
  15.     }   
  16.    
  17.     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {   
  18.         bool allow;   
  19.         if (curCount == INITIAL_STRONG_VALUE) {   
  20.             // Attempting to acquire first strong reference...  this is allowed   
  21.             // if the object does NOT have a longer lifetime (meaning the   
  22.             // implementation doesn't need to see this), or if the implementation   
  23.             // allows it to happen.   
  24.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK   
  25.                 || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);   
  26.         } else {   
  27.             // Attempting to revive the object...  this is allowed   
  28.             // if the object DOES have a longer lifetime (so we can safely   
  29.             // call the object with only a weak ref) and the implementation   
  30.             // allows it to happen.   
  31.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK   
  32.                 && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);   
  33.         }   
  34.         if (!allow) {   
  35.             decWeak(id);   
  36.             return false;   
  37.         }   
  38.         curCount = android_atomic_inc(&impl->mStrong);   
  39.    
  40.         // If the strong reference count has already been incremented by   
  41.         // someone else, the implementor of onIncStrongAttempted() is holding   
  42.         // an unneeded reference.  So call onLastStrongRef() here to remove it.   
  43.         // (No, this is not pretty.)  Note that we MUST NOT do this if we   
  44.         // are in fact acquiring the first reference.   
  45.         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {   
  46.             impl->mBase->onLastStrongRef(id);   
  47.         }   
  48.     }   
  49.    
  50.     impl->addWeakRef(id);   
  51.     impl->addStrongRef(id);   
  52.    
  53. #if PRINT_REFS   
  54.     LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);   
  55. #endif   
  56.    
  57.     if (curCount == INITIAL_STRONG_VALUE) {   
  58.         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);   
  59.         impl->mBase->onFirstRef();   
  60.     }   
  61.    
  62.     return true;   
  63. }   

   这个函数的作用是试图增加目标对象的强引用计数,但是有可能会失败,失败的原因可能是因为目标对象已经被delete掉了,或者是其它的原因,下面会分析到。前面我们在讨论强指针的时候说到,增加目标对象的强引用计数的同时,也会增加目标对象的弱引用计数,因此,函数在开始的地方首先就是调用incWeak函数来先增加目标对象的引用计数,如果后面试图增加目标对象的强引用计数失败时,会调用decWeak函数来回滚前面的incWeak操作。

        这里试图增加目标对象的强引用计数时,分两种情况讨论,一种情况是此时目标对象正在被其它强指针引用,即它的强引用计数大于0,并且不等于INITIAL_STRONG_VALUE,另一种情况是此时目标对象没有被任何强指针引用,即它的强引用计数小于等于0,或者等于INITIAL_STRONG_VALUE。

        第一种情况比较简单,因为这时候说明目标对象一定存在,因此,是可以将这个弱指针提升为强指针的,在这种情况下,只要简单地增加目标对象的强引用计数值就行了:

 
 
  1.    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {   
  2. if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {   
  3.     break;   
  4. }   
  5. curCount = impl->mStrong;   
  6.    }   

 当我们在这里对目标对象的强引用计数执行加1操作时,要保证原子性,因为其它地方也有可能正在对这个目标对象的强引用计数执行加1的操作,前面我们一般是调用android_atomic_inc函数来完成,但是这里是通过调用android_atomic_cmpxchg函数来完成,android_atomic_cmpxchg函数是体系结构相关的函数,在提供了一些特殊的指令的体系结构上,调用android_atomic_cmpxchg函数来执行加1操作的效率会比调用android_atomic_inc函数更高一些。函数android_atomic_cmpxchg是在system/core/include/cutils/atomic.h文件中定义的一个宏:

 
 
  1. int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,   
  2.         volatile int32_t* addr);   
  3.    
  4. #define android_atomic_cmpxchg android_atomic_release_cas   

    它实际执行的函数是android_atomic_release_cas,这个函数的工作原理大概是这样的:如果它发现*addr == oldvalue,就会执行*addr = newvalue的操作,然后返回0,否则什么也不做,返回1。在我们讨论的这个场景中,oldvalue等于curCount,而newvalue等于curCount + 1,于是,在*addr == oldvalue的条件下,就相当于是对目标对象的强引用计数值增加了1。什么情况下*addr != oldvalue呢?在调用android_atomic_release_cas函数之前,oldvalue和值就是从地址addr读出来的,如果在执行android_atomic_release_cas函数的时候,有其它地方也对地址addr进行操作,那么就会有可能出现*addr != oldvalue的情况,这时候就说明其它地方也在操作目标对象的强引用计数了,因此,这里就不能执行增加目标对象的强引用计数的操作了,它必须要等到其它地方操作完目标对象的强引用计数之后再重新执行,这就是为什么要通过一个while循环来执行了。

 

        第二种情况比较复杂一点,因为这时候目标对象可能还存在,也可能不存了,这要根据实际情况来判断。如果此时目标对象的强引用计数值等于INITIAL_STRONG_VALUE,说明此目标对象还从未被强指针引用过,这时候弱指针能够被提升为强指针的条件就为:

  1. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK  
  2.     || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  

 





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966569,如需转载请自行联系原作者

目录
相关文章
|
21天前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
18 1
|
1月前
|
安全 程序员 编译器
C++中的RAII(资源获取即初始化)与智能指针
C++中的RAII(资源获取即初始化)与智能指针
20 0
|
1月前
|
安全 程序员 C++
C++中的智能指针:从原始指针到现代内存管理
C++中的智能指针:从原始指针到现代内存管理
18 0
|
2月前
|
搜索推荐 Android开发 iOS开发
探析安卓与iOS系统的优劣
【2月更文挑战第7天】安卓与iOS是当今手机市场上最主流的两款操作系统,各有优劣。本文将从用户体验、开放程度、生态系统等方面对两者进行深入探析,以期帮助读者更好地了解它们的特点。
|
2月前
|
Android开发 数据安全/隐私保护 iOS开发
安卓与iOS系统的发展趋势与比较分析
【2月更文挑战第6天】 在移动互联网时代,安卓和iOS系统作为两大主流移动操作系统,各自呈现出不同的发展趋势。本文将从技术角度出发,对安卓和iOS系统的发展方向、特点及未来趋势进行比较分析,以期为读者提供更深入的了解和思考。
33 4
|
1月前
|
安全 C++ 容器
C++中的智能指针:自动内存管理的利器
C++中的智能指针:自动内存管理的利器
20 0
|
15天前
|
机器学习/深度学习 人工智能 搜索推荐
探索安卓应用中的新趋势:人工智能驱动的智能推荐系统
传统的应用推荐系统已经无法满足用户日益增长的个性化需求。本文将探讨如何通过引入人工智能技术,构建智能推荐系统,为用户提供更加精准、个性化的应用推荐体验,进而提升应用的用户满意度和留存率。
14 0
|
22天前
|
存储 安全 数据库连接
【C++智能指针】深入探究C++智能指针:自定义删除器的设计与选择
【C++智能指针】深入探究C++智能指针:自定义删除器的设计与选择
82 0
|
22天前
|
安全 算法 程序员
【C++智能指针 空指针判断】深入探索C++智能指针:nullptr与empty的微妙差异
【C++智能指针 空指针判断】深入探索C++智能指针:nullptr与empty的微妙差异
26 1
|
22天前
|
安全 算法 程序员
【C++ 智能指针】进一步了解C++智能指针
【C++ 智能指针】进一步了解C++智能指针
37 1