Android智能指针 (二)

强弱指针分析
  回顾上一篇智能指针的分析中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变量里。
7compare的实现  下面是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;
}

2.C++11 智能指针

对比android中提供的指针方式,auto_ptr、unique_ptr、share_ptr的实现,auto_ptr的实现就是一个不安全的存在,设计的最初是进行独占,虽然有显示的构造函数,但是也避免不了在所有权被转移的时候,存在潜在的威胁。因为release的调用会将原来的指针指针的delete操作将为被置为0,那么继续对原auto_ptr访问对象的变量的时候就会导致程序crash,那么uniqueu_ptr就严格限制了这种操作,编译的时候就会报错。 并且auto_ptr还不能作为函数的非引用参数,否则将会导致对象的转移,必须确保const reference的传递底线;unique_ptr实现了move语义,虽然也存在对象转移后的潜在威胁,但是使用move语义以后就能提醒该对象所有权已经发生了转移。
发布了38 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/zhiyanzhai563/article/details/104028698