强弱指针分析
回顾上一篇智能指针的分析中refbase对象对外提供的接口函数,以及影子对象的内部提供的强弱引用计数的基本功能。
下面分析sp,wp的模板类是如何调用refbase对象提供给对外的接口的。需要注明一下的是 extendObjectLifetime也是该对象提供给对外的接口,用来修改生命周期的模式。
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
1.智能指针sp、wp模板类
template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (U* other);
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
// Reset
void clear();
// Accessors
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
// Operators
COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
// Optimization for wp::promote().
sp(T* p, weakref_type* refs);
T* m_ptr;
};
下面贴出构造和析构对应的代码逻辑,其中比较重要的逻辑就是incStrong了,作为sp的构造过程中会将sp对象对应的指针作为指针id记录到影子对象的ref中保存到对应的entry中。
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);
}
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) m_ptr->incStrong(this);
}
分析incStrong中实现了弱引用计数加1以及强引用计数加1,除此之外还判断了当前是否是第一次添加强引用,如果是,将影子对象中的强计数从1<<28转换成1,并且调用外部类对象的onFirstRef接口函数。
decStrong中首先会从影子对象强引用计数链表中删除this指针的id,用到的影子对象的removeStrongRef函数,将强引用计数减掉1,然后就是根据是否为最后一个强引用的析构,如果是那么原始对象refbase就会被析构掉。
1.1原子操作的基本实现 GNU c汇编
其中原子操作使用了compare swap对应的lock free实现
int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
int xchg;
asm volatile
(
" lock; cmpxchg %%ecx, (%%edx);"
" setne %%al;"
" andl $1, %%eax"
: "=a" (xchg)
: "a" (oldvalue), "c" (newvalue), "d" (addr)
);
return xchg;
}
android_atomic_cmpxchg是使用GNU C嵌入汇编实现,使用X86提供的对CAS的原子支持的指令。
oldvalue放在eax寄存器中,newvalue放在ecx中,addr(pointer)放在edx中。cmpxchg指令首先比较addr指向的内存与oldvalue(eax),如果二者相等,将newvalue(ecx)放到addr所指向的内存中,同时设置Z标志1。setne与andl 指令的操作的结果很简单:如果Z标志被设置,则eax为0,否则为1。程序执行最终eax放到xchg变量里。
下面是android_atomic_dec的实现:循环判断是否内存值和oldvalue值保持一致,一致就返回原来的值内存的值,循环过程中不断的用内存进行赋值oldvalue值,那么返回的值就是最新修改值的前一个值。
int32_t android_atomic_dec(volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
return oldValue;
}