鍍金池/ 教程/ Android/ 第5章 深入理解常見(jiàn)類(lèi)
第4章 ?深入理解 Zygote
第10章 深入理解MediaScanner
第3章 ?深入理解init
第8章 ?深入理解Surface系統(tǒng)
第5章 深入理解常見(jiàn)類(lèi)
第7章 ?深入理解Audio系統(tǒng)
第一章 ?閱讀前的準(zhǔn)備工作
<span>第6章 深入理解Binder</span>
第9章 ?深入理解Vold和Rild
第2章? 深入理解JNI

第5章 深入理解常見(jiàn)類(lèi)

本章主要內(nèi)容

·? 分析RefBase、sp,wp和LightRefBase類(lèi)。

·? 分析Native的Thread類(lèi)和常用同步類(lèi)。

·? 分析Java層的Handler、Looper,以及HandlerThread類(lèi)。

本章涉及的源代碼文件名稱(chēng)及位置

下面是我們本章分析的源碼文件名和它的位置。

·? RefBase.h

framework/base/include/utils/RefBase.h

·? RefBase.cpp

framework/base/libs/utils/RefBase.cpp

·? Thread.cpp

framework/base/libs/utils/Thread.cpp

·? Thread.h

framework/base/include/utils/Thread.h

·? Atomic.h

system/core/include/cutils/Atomic.h

·? AndroidRuntime.cpp

framework/base/core/jni/AndroidRuntime.cpp

·? Looper.java

framework/base/core/Java/Android/os/Looper.java

·? Handler.java

framework/base/core/Java/Android/os/Handler.java

·? HandlerThread.java

framework/base/core/Java/Android/os/HandlerThread.java

5.1 ?綜述

初次接觸Android源碼,最多見(jiàn)到的一定是sp和wp。如果你只是沉迷于Java世界,那么Looper和Handler也是避不開(kāi)的。本章的目的,就是把經(jīng)常碰見(jiàn)的這些內(nèi)容中的“攔路虎”一網(wǎng)打盡,將它們徹底搞懂。至于弄明白它們有什么好處,就是仁者見(jiàn)仁,智者見(jiàn)智了。我個(gè)人覺(jué)得,可能Looper和Handler會(huì)相對(duì)更實(shí)用一些。

5.2 ?以“三板斧”揭秘RefBase、sp和wp

RefBase是Android中所有對(duì)象的始祖,類(lèi)似MFC中的CObject及Java中的Object對(duì)象。在Android中,RefBase結(jié)合sp和wp,實(shí)現(xiàn)了一套通過(guò)引用計(jì)數(shù)的方法來(lái)控制對(duì)象生命周期的機(jī)制。就如我們想像的那樣,這三者的關(guān)系非常曖昧。初次接觸Android源碼的人往往會(huì)被那個(gè)隨處可見(jiàn)的sp和wp搞暈了頭。

什么是sp和wp呢?其實(shí),sp并不是我開(kāi)始所想的smart pointer(C++語(yǔ)言中有這個(gè)東西),它真實(shí)的意思應(yīng)該是strong pointer,而wp是weak pointer的意思。我認(rèn)為,Android推出這一套機(jī)制可能是模仿Java,因?yàn)镴ava世界中有所謂weak reference之類(lèi)的東西。sp和wp的目的,就是為了幫助健忘的程序員回收new出來(lái)的內(nèi)存。

我還是喜歡赤裸裸地管理內(nèi)存的分配和釋放。不過(guò),目前sp和wp的使用已經(jīng)深入到Android系統(tǒng)的各個(gè)角落,想把它去掉真是不太可能了。

這三者的關(guān)系比較復(fù)雜,都說(shuō)程咬金的“三板斧”很厲害,那么我們就借用這三板斧,揭密其相互間的曖昧關(guān)系。

5.2.1 ?第一板斧——初識(shí)影子對(duì)象

我們的“三板斧”,其實(shí)就是三個(gè)例子。相信這三板斧劈下去,你會(huì)很容易理解它們。

[-->例子1]

//類(lèi)A從RefBase派生,RefBase是萬(wàn)物的始祖

class A:public RefBase

{

?//A沒(méi)有任何自己的功能

}

int main()

{

? A* pA =new A;

? {

? ?//注意我們的sp,wp對(duì)象是在{}中創(chuàng)建的,下面的代碼先創(chuàng)建sp,然后創(chuàng)建wp

?? sp<A>spA(A);

?? wp<A>wpA(spA);

??? //大括號(hào)結(jié)束前,先析構(gòu)wp,再析構(gòu)sp

?? }

}

例子夠簡(jiǎn)單吧?但也需一步一步分析這斧子是怎么劈下去的。

1. RefBase和它的影子

類(lèi)A從RefBase中派生。使用的是RefBase構(gòu)造函數(shù)。代碼如下所示:

[-->RefBase.cpp]

RefBase::RefBase()

??? :mRefs(new weakref_impl(this))//注意這句話

{

? //mRefs是RefBase的成員變量,類(lèi)型是weakref_impl,我們暫且叫它影子對(duì)象

? //所以A有一個(gè)影子對(duì)象

}

mRefs是引用計(jì)數(shù)管理的關(guān)鍵類(lèi),需要進(jìn)去觀察。它是從RefBase的內(nèi)部類(lèi)weakref_type中派生出來(lái)的。

先看看它的聲明:

class RefBase::weakref_impl : public RefBase::weakref_type

//從RefBase的內(nèi)部類(lèi)weakref_type派生

由于Android頻繁使用C++內(nèi)部類(lèi)的方法,所以初次閱讀Android代碼時(shí)可能會(huì)有點(diǎn)不太習(xí)慣,C++的內(nèi)部類(lèi)和Java內(nèi)部類(lèi)相似,但不同的是,它需要一個(gè)顯示的成員指向外部類(lèi)對(duì)象,而Java內(nèi)部類(lèi)對(duì)象就有一個(gè)隱式的成員指向外部類(lèi)對(duì)象。

說(shuō)明:內(nèi)部類(lèi)在C++中的學(xué)名叫nested class(內(nèi)嵌類(lèi))。

[-->RefBase.cpp::weakref_imple構(gòu)造]

weakref_impl(RefBase* base)

??????? :mStrong(INITIAL_STRONG_VALUE) //強(qiáng)引用計(jì)數(shù),初始值為0x1000000

??????? ,mWeak(0) //弱引用計(jì)數(shù),初始值為0

??????? ,mBase(base)//該影子對(duì)象所指向的實(shí)際對(duì)象

??????? ,mFlags(0)

??????? ,mStrongRefs(NULL)

??????? ,mWeakRefs(NULL)

??????? ,mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)

??????? ,mRetain(false)

??? {

???? }

如你所見(jiàn),new了一個(gè)A對(duì)象后,其實(shí)還new了一個(gè)weakref_impl對(duì)象,這里稱(chēng)它為影子對(duì)象,另外我們稱(chēng)A為實(shí)際對(duì)象。

這里有一個(gè)問(wèn)題:影子對(duì)象有什么用?

可以仔細(xì)想一下,是不是發(fā)現(xiàn)影子對(duì)象成員中有兩個(gè)引用計(jì)數(shù)?一個(gè)強(qiáng)引用,一個(gè)弱引用。如果知道引用計(jì)數(shù)和對(duì)象生死有些許關(guān)聯(lián)的話,就容易想到影子對(duì)象的作用了。

按上面的分析,在構(gòu)造一個(gè)實(shí)際對(duì)象的同時(shí),還會(huì)悄悄地構(gòu)造一個(gè)影子對(duì)象,在嵌入式設(shè)備的內(nèi)存不是很緊俏的今天,這個(gè)影子對(duì)象的內(nèi)存占用已不成問(wèn)題了。

2. sp上場(chǎng)

程序繼續(xù)運(yùn)行,現(xiàn)在到了

sp<A> spA(A);

請(qǐng)看sp的構(gòu)造函數(shù),它的代碼如下所示:(注意,sp是一個(gè)模板類(lèi),對(duì)此不熟悉的讀者可以去翻翻書(shū),或者干脆把所有出現(xiàn)的T都換成A。)

[-->RefBase.h::sp(T*other)]

template<typename T>

sp<T>::sp(T* other) //這里的other就是剛才創(chuàng)建的pA

??? :m_ptr(other)// sp保存了pA的指針

{

??? if(other) other->incStrong(this);//調(diào)用pA的incStrong

}

OK,戰(zhàn)場(chǎng)轉(zhuǎn)到RefBase的incStrong中。它的代碼如下所示:

[-->RefBase.cpp]

void RefBase::incStrong(const void* id) const

{

?//mRefs就是剛才RefBase構(gòu)造函數(shù)中new出來(lái)的影子對(duì)象

?weakref_impl*const refs = mRefs;

?

//操作影子對(duì)象,先增加弱引用計(jì)數(shù)

?refs->addWeakRef(id);

?refs->incWeak(id);

?......

先來(lái)看看影子對(duì)象的這兩個(gè)weak函數(shù)都干了些什么。??

(1)眼見(jiàn)而心不煩

先來(lái)看第一個(gè)函數(shù)addWeakRef,代碼如下所示:

[-->RefBase.cpp]

void addWeakRef(const void* /*id*/) { }

呵呵,addWeakRef啥都沒(méi)做,因?yàn)檫@是release版走的分支。調(diào)試版的代碼我們就不討論了,它是給創(chuàng)造RefBase、 sp,以及wp的人調(diào)試用的。

調(diào)試版分支的代碼很多,看來(lái)創(chuàng)造它們的人,也為不理解它們之間的曖昧關(guān)系痛苦不已。

總之,一共有這么幾個(gè)不用考慮的函數(shù),我們都已列出來(lái)了。以后再碰見(jiàn)它們,干脆就直接跳過(guò)的是:

void addStrongRef(const void* /*id*/) { }

void removeStrongRef(const void* /*id*/) { }

void addWeakRef(const void* /*id*/) { }

void removeWeakRef(const void* /*id*/) { }

void printRefs() const { }

void trackMe(bool, bool) { }

繼續(xù)我們的征程。再看incWeak函數(shù),代碼如下所示:

[-->RefBase.cpp]

void RefBase::weakref_type::incWeak(const void*id)

{

???weakref_impl* const impl = static_cast<weakref_impl*>(this);

???impl->addWeakRef(id);? //上面說(shuō)了,非調(diào)試版什么都不干

?? const int32_tc = android_atomic_inc(&impl->mWeak);

? //原子操作,影子對(duì)象的弱引用計(jì)數(shù)加1

? //千萬(wàn)記住影子對(duì)象的強(qiáng)弱引用計(jì)數(shù)的值,這是徹底理解sp和wp的關(guān)鍵

}

好,我們?cè)倩氐絠ncStrong,繼續(xù)看代碼:

[-->RefBase.cpp]

?? ......

? //剛才增加了弱引用計(jì)數(shù)

? //再增加強(qiáng)引用計(jì)數(shù)

? refs->addStrongRef(id);//非調(diào)試版這里什么都不干

? //下面函數(shù)為原子加1操作,并返回舊值。所以c=0x1000000,而mStrong變?yōu)?x1000001

? ?const int32_t c =android_atomic_inc(&refs->mStrong);

?? if (c!= INITIAL_STRONG_VALUE)? {

????? //如果c不是初始值,則表明這個(gè)對(duì)象已經(jīng)被強(qiáng)引用過(guò)一次了

???????return;

??? }

? //下面這個(gè)是原子加操作,相當(dāng)于執(zhí)行refs->mStrong +(-0x1000000),最終mStrong=1

? android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong);

?/*

?? 如果是第一次引用,則調(diào)用onFirstRef,這個(gè)函數(shù)很重要,派生類(lèi)可以重載這個(gè)函數(shù),完成一些

?? 初始化工作。

?*/

?const_cast<RefBase*>(this)->onFirstRef();

}

?

說(shuō)明:android_atomic_xxx是Android平臺(tái)提供的原子操作函數(shù),原子操作函數(shù)是多線程編程中的常見(jiàn)函數(shù),讀者可以學(xué)習(xí)原子操作函數(shù)知識(shí),本章后面將對(duì)其做介紹。

(2)sp構(gòu)造的影響

sp構(gòu)造完后,它給這個(gè)世界帶來(lái)了什么?

·? 那就是RefBase中影子對(duì)象的強(qiáng)引用計(jì)數(shù)變?yōu)?,弱引用計(jì)數(shù)也變?yōu)?。

更準(zhǔn)確的說(shuō)法是,sp的出生導(dǎo)致影子對(duì)象的強(qiáng)引用計(jì)數(shù)加1,弱引用計(jì)數(shù)加1。

(3)wp構(gòu)造的影響

繼續(xù)看wp,例子中的調(diào)用方式如下:

wp<A> wpA(spA)

wp有好幾個(gè)構(gòu)造函數(shù),原理都一樣。來(lái)看這個(gè)最常見(jiàn)的:

[-->RefBase.h::wp(constsp<T>& other)]

template<typename T>

wp<T>::wp(const sp<T>& other)

??? :m_ptr(other.m_ptr) //wp的成員變量m_ptr指向?qū)嶋H對(duì)象

{

??? if(m_ptr) {

?????? //調(diào)用pA的createWeak,并且保存返回值到成員變量m_refs中

???????m_refs = m_ptr->createWeak(this);

??? }

}

[-->RefBase.cpp]

RefBase::weakref_type* RefBase::createWeak(constvoid* id) const

{

//調(diào)用影子對(duì)象的incWeak,這個(gè)我們剛才講過(guò)了,將導(dǎo)致影子對(duì)象的弱引用計(jì)數(shù)增加1

?mRefs->incWeak(id);

?returnmRefs;? //返回影子對(duì)象本身

}

我們可以看到,wp化后,影子對(duì)象的弱引用計(jì)數(shù)將增加1,所以現(xiàn)在弱引用計(jì)數(shù)為2,而強(qiáng)引用計(jì)數(shù)仍為1。另外,wp中有兩個(gè)成員變量,一個(gè)保存實(shí)際對(duì)象,另一個(gè)保存影子對(duì)象。sp只有一個(gè)成員變量用來(lái)保存實(shí)際對(duì)象,但這個(gè)實(shí)際對(duì)象內(nèi)部已包含了對(duì)應(yīng)的影子對(duì)象。

OK,wp創(chuàng)建完了,現(xiàn)在開(kāi)始進(jìn)入wp的析構(gòu)。

(4)wp析構(gòu)的影響

wp進(jìn)入析構(gòu)函數(shù),這表明它快要離世了。

[-->RefBase.h]

template<typename T>

wp<T>::~wp()

{

??? if(m_ptr) m_refs->decWeak(this); //調(diào)用影子對(duì)象的decWeak,由影子對(duì)象的基類(lèi)實(shí)現(xiàn)

}

[-->RefBase.cpp]

void RefBase::weakref_type::decWeak(const void*id)

{

? //把基類(lèi)指針轉(zhuǎn)換成子類(lèi)(影子對(duì)象)的類(lèi)型,這種做法有些違背面向?qū)ο缶幊痰乃枷?/p>

? weakref_impl*const impl = static_cast<weakref_impl*>(this);

? impl->removeWeakRef(id);//非調(diào)試版不做任何事情

?

? //原子減1,返回舊值,c=2,而弱引用計(jì)數(shù)從2變?yōu)?

? constint32_t c = android_atomic_dec(&impl->mWeak);

? if (c !=1) return; //c=2,直接返回

??

? //如果c為1,則弱引用計(jì)數(shù)為0,這說(shuō)明沒(méi)用弱引用指向?qū)嶋H對(duì)象,需要考慮是否釋放內(nèi)存

? // OBJECT_LIFETIME_XXX和生命周期有關(guān)系,我們后面再說(shuō)。

??? if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

??????? if(impl->mStrong == INITIAL_STRONG_VALUE)

???????????delete impl->mBase;

???????else {

???????????delete impl;

??????? }

??? } else{

??????? impl->mBase->onLastWeakRef(id);

??????? if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

???????????delete impl->mBase;

??????? }

??? }

}

OK,在例1中,wp析構(gòu)后,弱引用計(jì)數(shù)減1。但由于此時(shí)強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)仍為1,所以沒(méi)有對(duì)象被干掉,即沒(méi)有釋放實(shí)際對(duì)象和影子對(duì)象占據(jù)的內(nèi)存。

(5)sp析構(gòu)的影響

下面進(jìn)入sp的析構(gòu)。

[-->RefBase.h]

template<typename T>

sp<T>::~sp()

{

??? if(m_ptr) m_ptr->decStrong(this); //調(diào)用實(shí)際對(duì)象的decStrong。由RefBase實(shí)現(xiàn)

}

[-->RefBase.cpp]

void RefBase::decStrong(const void* id) const

{

???weakref_impl* const refs = mRefs;

??? refs->removeStrongRef(id);//調(diào)用影子對(duì)象的removeStrongRef,啥都不干

??? //注意,此時(shí)強(qiáng)弱引用計(jì)數(shù)都是1,下面函數(shù)調(diào)用的結(jié)果是c=1,強(qiáng)引用計(jì)數(shù)為0

??? constint32_t c = android_atomic_dec(&refs->mStrong);

??? if (c== 1) { //對(duì)于我們的例子, c為1

??????? //調(diào)用onLastStrongRef,表明強(qiáng)引用計(jì)數(shù)減為0,對(duì)象有可能被delete

???????const_cast<RefBase*>(this)->onLastStrongRef(id);

???? ??//mFlags為0,所以會(huì)通過(guò)delete this把自己干掉

????? //注意,此時(shí)弱引用計(jì)數(shù)仍為1

??????? if((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

???????????delete this;

??????? }

?? ......

}

先看delete this的處理,它會(huì)導(dǎo)致A的析構(gòu)函數(shù)被調(diào)用;再看A的析構(gòu)函數(shù),代碼如下所示:

[-->例子1::~A()]

//A的析構(gòu)直接導(dǎo)致進(jìn)入RefBase的析構(gòu)。

RefBase::~RefBase()

{

?? if(mRefs->mWeak == 0) { //弱引用計(jì)數(shù)不為0,而是1

??????delete mRefs;??

??? }

}

RefBase的delete this自殺行為沒(méi)有把影子對(duì)象干掉,但我們還在decStrong中,可接著從delete this往下看:

[-->RefBase.cpp]

???? ....//接前面的delete this

?? if ((refs->mFlags&OBJECT_LIFETIME_WEAK)!= OBJECT_LIFETIME_WEAK) {

???????????delete this;

??????? }

? //注意,實(shí)際數(shù)據(jù)對(duì)象已經(jīng)被干掉了,所以mRefs也沒(méi)有用了,但是decStrong剛進(jìn)來(lái)

? //的時(shí)候就保存mRefs到refs了,所以這里的refs指向影子對(duì)象

???refs->removeWeakRef(id);

???refs->decWeak(id);//調(diào)用影子對(duì)象decWeak

}

[-->RefBase.cpp]

void RefBase::weakref_type::decWeak(const void*id)

{

? weakref_impl*const impl = static_cast<weakref_impl*>(this);

? impl->removeWeakRef(id);//非調(diào)試版不做任何事情

?

??? //調(diào)用前影子對(duì)象的弱引用計(jì)數(shù)為1,強(qiáng)引用計(jì)數(shù)為0,調(diào)用結(jié)束后c=1,弱引用計(jì)數(shù)為0

??? constint32_t c = android_atomic_dec(&impl->mWeak);

??? if (c!= 1) return;

???

??? //這次弱引用計(jì)數(shù)終于變?yōu)?,并且mFlags為0, mStrong也為0。

??? if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

??????? if(impl->mStrong == INITIAL_STRONG_VALUE)

???????????delete impl->mBase;

???????else {

???????????delete impl; //impl就是this,把影子對(duì)象自己干掉

??????? }

??? } else{

???????impl->mBase->onLastWeakRef(id);

??????? if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

???????????delete impl->mBase;

??????? }

??? }

}

好,第一板斧劈下去了!來(lái)看看它的結(jié)果是什么。

3. 第一板斧的結(jié)果

第一板斧過(guò)后,來(lái)總結(jié)一下剛才所學(xué)的知識(shí):

·? RefBase中有一個(gè)隱含的影子對(duì)象,該影子對(duì)象內(nèi)部有強(qiáng)弱引用計(jì)數(shù)。

·? sp化后,強(qiáng)弱引用計(jì)數(shù)各增加1,sp析構(gòu)后,強(qiáng)弱引用計(jì)數(shù)各減1。

·? wp化后,弱引用計(jì)數(shù)增加1,wp析構(gòu)后,弱引用計(jì)數(shù)減1。

完全徹底地消滅RefBase對(duì)象,包括讓實(shí)際對(duì)象和影子對(duì)象滅亡,這些都是由強(qiáng)弱引用計(jì)數(shù)控制的,另外還要考慮flag的取值情況。當(dāng)flag為0時(shí),可得出如下結(jié)論:

·? 強(qiáng)引用為0將導(dǎo)致實(shí)際對(duì)象被delete。

·? 弱引用為0將導(dǎo)致影子對(duì)象被delete。

?

5.2.2 ?第二板斧——由弱生強(qiáng)

再看第二個(gè)例子,代碼如下所示:

[-->例子2]

int main()

{

?? A *pA =new A();

??wp<A> wpA(A);

??sp<A> spA = wpA.promote();//通過(guò)promote函數(shù),得到一個(gè)sp。

}

對(duì)A的wp化,不再做分析了。按照前面所學(xué)的知識(shí),wp化后僅會(huì)使弱引用計(jì)數(shù)加1,所以此處wp化的結(jié)果是:

·? 影子對(duì)象的弱引用計(jì)數(shù)為1,強(qiáng)引用計(jì)數(shù)仍然是初始值0x1000000。

wpA的promote函數(shù)是從一個(gè)弱對(duì)象產(chǎn)生一個(gè)強(qiáng)對(duì)象的重要函數(shù),試看:

1. 由弱生強(qiáng)的方法

代碼如下所示:

[-->RefBase.h]

template<typename T>

sp<T> wp<T>::promote() const

{

??? returnsp<T>(m_ptr, m_refs);? //調(diào)用sp的構(gòu)造函數(shù)。

}

[-->RefBase.h]

template<typename T>

sp<T>::sp(T* p, weakref_type* refs)

??? :m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)//有點(diǎn)看不清楚

{

//上面那行代碼夠簡(jiǎn)潔,但是不方便閱讀,我們寫(xiě)成下面這樣:

/*

? T* pTemp= NULL;

? //關(guān)鍵函數(shù)attemptIncStrong

? if(p !=NULL && refs->attemptIncStrong(this) == true)

?? ???pTemp = p;

?

? m_ptr =pTemp;

*/

}

2. 成敗在此一舉

由弱生強(qiáng)的關(guān)鍵函數(shù)是attemptIncStrong,它的代碼如下所示:

[-->RefBase.cpp]

boolRefBase::weakref_type::attemptIncStrong(const void* id)

{

???? incWeak(id);//增加弱引用計(jì)數(shù),此時(shí)弱引用計(jì)數(shù)變?yōu)?

????weakref_impl* const impl = static_cast<weakref_impl*>(this);

??? ??int32_t curCount = impl->mStrong; //這個(gè)仍是初始值

???? //下面這個(gè)循環(huán),在多線程操作同一個(gè)對(duì)象時(shí)可能會(huì)循環(huán)多次。這里可以不去管它,

??? ?//它的目的就是使強(qiáng)引用計(jì)數(shù)增加1

??? while(curCount > 0 && curCount != INITIAL_STRONG_VALUE) {

??????? if(android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {

???????????break;

??????? }

???????curCount = impl->mStrong;

??? }

???

??? if(curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {

??????? ?bool allow;

? /*

? ?下面這個(gè)allow的判斷極為精妙。impl的mBase對(duì)象就是實(shí)際對(duì)象,有可能已經(jīng)被delete了。

?? curCount為0,表示強(qiáng)引用計(jì)數(shù)肯定經(jīng)歷了INITIAL_STRONG_VALUE->1->...->0的過(guò)程。

?? mFlags就是根據(jù)標(biāo)志來(lái)決定是否繼續(xù)進(jìn)行||或&&后的判斷,因?yàn)檫@些判斷都使用了mBase,

?? 如不做這些判斷,一旦mBase指向已經(jīng)回收的地址,你就等著segment fault吧!

?? 其實(shí),咱們大可不必理會(huì)這些東西,因?yàn)樗挥绊懳覀兊姆治龊屠斫狻?/p>

? */

??????? if(curCount == INITIAL_STRONG_VALUE) {

???????????? allow =(impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK

?????????????????|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

??????? }else {

???????????allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) ==OBJECT_LIFETIME_WEAK

?????????????????&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG,id);

??????? }

??????? if(!allow) {

??????? //allow為false,表示不允許由弱生強(qiáng),弱引用計(jì)數(shù)要減去1,這是因?yàn)樵蹅冞M(jìn)來(lái)時(shí)加過(guò)一次

???? ???????decWeak(id);

???????????return false; //由弱生強(qiáng)失敗

??????? }

?

???? //允許由弱生強(qiáng),則強(qiáng)引用計(jì)數(shù)要增加1,而弱引用計(jì)數(shù)已經(jīng)增加過(guò)了

???????curCount = android_atomic_inc(&impl->mStrong);

??????? if(curCount > 0 && curCount < INITIAL_STRONG_VALUE) {

???????????impl->mBase->onLastStrongRef(id);

??????? }

??? }

???impl->addWeakRef(id);

???impl->addStrongRef(id);//兩個(gè)函數(shù)調(diào)用沒(méi)有作用

???? if(curCount == INITIAL_STRONG_VALUE) {

?? ??????//強(qiáng)引用計(jì)數(shù)變?yōu)?

???????android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);

????? ??//調(diào)用onFirstRef,通知該對(duì)象第一次被強(qiáng)引用

???????impl->mBase->onFirstRef();

??? }

??? returntrue; //由弱生強(qiáng)成功

}

3. 第二板斧的結(jié)果

promote完成后,相當(dāng)于增加了一個(gè)強(qiáng)引用。根據(jù)上面所學(xué)的知識(shí)可知:

·? 由弱生強(qiáng)成功后,強(qiáng)弱引用計(jì)數(shù)均增加1。所以現(xiàn)在影子對(duì)象的強(qiáng)引用計(jì)數(shù)為1,弱引用計(jì)數(shù)為2。

5.2.3 ?第三板斧——破解生死魔咒

1. 延長(zhǎng)生命的魔咒

RefBase為我們提供了一個(gè)這樣的函數(shù):

extendObjectLifetime(int32_t mode)

另外還定義了一個(gè)枚舉:

enum {

???????OBJECT_LIFETIME_WEAK??? = ?0x0001,

???????OBJECT_LIFETIME_FOREVER = 0x0003

};

注意:FOREVER的值是3,二進(jìn)制表示是B11,而WEAK的二進(jìn)制是B01,也就是說(shuō)FOREVER包括了WEAK的情況。

上面這兩個(gè)枚舉值,是破除強(qiáng)弱引用計(jì)數(shù)作用的魔咒。先觀察flags為OBJECT_LIFETIME_WEAK的情況,見(jiàn)下面的例子。

[-->例子3]

class A:public RefBase

{

?? publicA()

?? {

????? extendObjectLifetime(OBJECT_LIFETIME_WEAK);//在構(gòu)造函數(shù)中調(diào)用

?? }

}

int main()

{

?? A *pA =new A();

???wp<A> wpA(A);//弱引用計(jì)數(shù)加1

? {

????? sp<A>spA(pA) //sp后,結(jié)果是強(qiáng)引用計(jì)數(shù)為1,弱引用計(jì)數(shù)為2

?? }

....

}

?

sp的析構(gòu)將直接調(diào)用RefBase的decStrong,它的代碼如下所示:

[-->RefBase.cpp]

void RefBase::decStrong(const void* id) const

{

???weakref_impl* const refs = mRefs;

???refs->removeStrongRef(id);

??? constint32_t c = android_atomic_dec(&refs->mStrong);

??? if (c== 1) { //上面原子操作后,強(qiáng)引用計(jì)數(shù)為0

???????const_cast<RefBase*>(this)->onLastStrongRef(id);、

??????? //注意這句話。如果flags不是WEAK或FOREVER的話,將delete數(shù)據(jù)對(duì)象

?????? //現(xiàn)在我們的flags是WEAK,所以不會(huì)delete 它

????? ??if((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

?? ?????????delete this;

??????? }

? }

? ??refs->removeWeakRef(id);

???refs->decWeak(id);//調(diào)用前弱引用計(jì)數(shù)是2。

}

然后調(diào)用影子對(duì)象的decWeak。再來(lái)看它的處理,代碼如下所示:

[-->RefBase.cpp::weakref_type的decWeak()函數(shù)]

void RefBase::weakref_type::decWeak(const void*id)

{

???weakref_impl* const impl = static_cast<weakref_impl*>(this);

???impl->removeWeakRef(id);

??? constint32_t c = android_atomic_dec(&impl->mWeak);

??? if (c!= 1) return;? //c為2,弱引用計(jì)數(shù)為1,直接返回。

?? /*

???? 假設(shè)我們現(xiàn)在到了例子中的wp析構(gòu)之處,這時(shí)也會(huì)調(diào)用decWeak,調(diào)用上邊的原子減操作后

???? c=1,弱引用計(jì)數(shù)變?yōu)?,此時(shí)會(huì)繼續(xù)往下運(yùn)行。由于mFlags為WEAK ,所以不滿(mǎn)足if的條件

?? */

??? if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

??????? if(impl->mStrong == INITIAL_STRONG_VALUE)

???????????delete impl->mBase;

???????else {

???????????delete impl;

??????? }

??? } else{//flag為WEAK,滿(mǎn)足else分支的條件

???????impl->mBase->onLastWeakRef(id);

?????? /*

??????? 由于flags值滿(mǎn)足下面這個(gè)條件,所以實(shí)際對(duì)象會(huì)被delete,根據(jù)前面的分析, 實(shí)際對(duì)象的delete會(huì)檢查影子對(duì)象的弱引用計(jì)數(shù),如果它為0,則會(huì)把影子對(duì)象也delete掉。

??????? 由于影子對(duì)象的弱引用計(jì)數(shù)此時(shí)已經(jīng)為0,所以影子對(duì)象也會(huì)被delete。

????? */

??????? if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

???????????delete impl->mBase;

??????? }

??? }

}

2. LIFETIME_WEAK的魔力

看完上面的例子,我們發(fā)現(xiàn)什么了?

·? 在LIFETIME_WEAK的魔法下,強(qiáng)引用計(jì)數(shù)為0,而弱引用計(jì)數(shù)不為0的時(shí)候,實(shí)際對(duì)象沒(méi)有被delete!只有當(dāng)強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)同時(shí)為0時(shí),實(shí)際對(duì)象和影子對(duì)象才會(huì)被delete。

3. 魔咒大揭秘

至于LIFETIME_FOREVER的破解,就不用再來(lái)一斧子了,我直接的答案是:

·? flags為0,強(qiáng)引用計(jì)數(shù)控制實(shí)際對(duì)象的生命周期,弱引用計(jì)數(shù)控制影子對(duì)象的生命周期。強(qiáng)引用計(jì)數(shù)為0后,實(shí)際對(duì)象被delete。所以對(duì)于這種情況,應(yīng)記住的是,使用wp時(shí)要由弱生強(qiáng),以免收到segment fault信號(hào)。

·? flags為L(zhǎng)IFETIME_WEAK,強(qiáng)引用計(jì)數(shù)為0,弱引用計(jì)數(shù)不為0時(shí),實(shí)際對(duì)象不會(huì)被delete。當(dāng)弱引用計(jì)數(shù)減為0時(shí),實(shí)際對(duì)象和影子對(duì)象會(huì)同時(shí)被delete。這是功德圓滿(mǎn)的情況。

·? flags為L(zhǎng)IFETIME_FOREVER,對(duì)象將長(zhǎng)生不老,徹底擺脫強(qiáng)弱引用計(jì)數(shù)的控制。所以你要在適當(dāng)?shù)臅r(shí)候殺死這些老妖精,免得她禍害“人間”。

5.2.4 ?輕量級(jí)的引用計(jì)數(shù)控制LightRefBase

上面介紹的RefBase,是一個(gè)重量級(jí)的引用計(jì)數(shù)控制類(lèi)。那么,究竟有沒(méi)有一個(gè)簡(jiǎn)單些的引用計(jì)數(shù)控制類(lèi)呢?Android為我們提供了一個(gè)輕量級(jí)的LightRefBase。這個(gè)類(lèi)非常簡(jiǎn)單,我們不妨一起來(lái)看看。

[-->RefBase.h]

template <class T>

class LightRefBase

{

public:

??? inlineLightRefBase() : mCount(0) { }

inline void incStrong(const void* id) const {

?? ???//LightRefBase只有一個(gè)引用計(jì)數(shù)控制量mCount。incStrong的時(shí)候使它增加1

???????android_atomic_inc(&mCount);

??? }

inline void decStrong(const void* id) const {

?? ????//decStrong的時(shí)候減1,當(dāng)引用計(jì)數(shù)變?yōu)榱愕臅r(shí)候,delete掉自己

??????? if(android_atomic_dec(&mCount) == 1) {

???????????delete static_cast<const T*>(this);

??????? }

??? }

??? inlineint32_t getStrongCount() const {

???????return mCount;

??? }

???

protected:

??? inline~LightRefBase() { }

???

private:

mutable volatile int32_t mCount;//引用計(jì)數(shù)控制變量

};

LightRefBase類(lèi)夠簡(jiǎn)單吧?不過(guò)它是一個(gè)模板類(lèi),我們?cè)撛趺从盟??下面給出一個(gè)例子,其中類(lèi)A是從LightRefBase派生的,寫(xiě)法如下:

class A:public LightRefBase<A> //注意派生的時(shí)候要指明是LightRefBase<A>

{

public:

A(){};

~A(){};

};

另外,我們從LightRefBase的定義中可以知道,它支持sp的控制,因?yàn)樗挥衖ncStrong和decStrong函數(shù)。

5.2.5 ?題外話——三板斧的來(lái)歷

從代碼量上看,RefBase、sp和wp的代碼量并不多,但里邊的關(guān)系,尤其是flags的引入,曾一度讓我眼花繚亂。當(dāng)時(shí),我確實(shí)很希望能自己調(diào)試一下這些例子,但在設(shè)備上調(diào)試native代碼,需要花費(fèi)很大的精力,即使是通過(guò)輸出log的方式也需要很多時(shí)間。該怎么解決這一難題?

既然它的代碼不多而且簡(jiǎn)單,那何不把它移植到臺(tái)式機(jī)的開(kāi)發(fā)環(huán)境下,整一個(gè)類(lèi)似的RefBase呢?由于有了這樣的構(gòu)想,我便用上了Visual Studio。至于那些原子操作,Windows平臺(tái)上有很直接的InterlockedExchangeXXX與之對(duì)應(yīng),真的是踏破鐵鞋無(wú)覓處,得來(lái)全不費(fèi)功夫?。ㄔ贚inux平臺(tái)上,不考慮多線程的話,將原子操作換成普通的非原子操作不是也可以嗎?如果更細(xì)心更負(fù)責(zé)任的話,你可以自己用匯編來(lái)實(shí)現(xiàn)常用的原子操作,內(nèi)核代碼中有現(xiàn)成的函數(shù),一看就會(huì)明白。)

如果把破解代碼看成是攻城略地的話,我們必須學(xué)會(huì)靈活多變,而且應(yīng)力求破解方法日臻極致!

?

5.3 ?Thread類(lèi)以及常用同步類(lèi)的分析

Thread類(lèi)是Android為線程操作而做的一個(gè)封裝。代碼在Thread.cpp中,其中還封裝了一些與線程同步相關(guān)(既然是封裝,要掌握它,最重要的當(dāng)然是與Pthread相關(guān)的知識(shí))的類(lèi)。我們擬先行分析Threa類(lèi),進(jìn)而再介紹與常用同步類(lèi)相關(guān)的知識(shí)。

5.3.1 ?一個(gè)變量引發(fā)的思考

Thread類(lèi)雖說(shuō)挺簡(jiǎn)單,但它構(gòu)造函數(shù)中的那個(gè)canCallJava卻一度使我感到費(fèi)解。因?yàn)槲乙恢笔褂玫氖亲约悍庋b的Pthread類(lèi)。當(dāng)發(fā)現(xiàn)Thread構(gòu)造函數(shù)中竟然存在這樣一個(gè)東西時(shí),很擔(dān)心自己封裝的Pthread類(lèi)會(huì)不會(huì)有什么重大問(wèn)題,因?yàn)楫?dāng)時(shí)我還從來(lái)沒(méi)考慮過(guò)Java方面的問(wèn)題。

// canCallJava表示這個(gè)線程是否會(huì)使用JNI函數(shù)。為什么需要一個(gè)這樣的參數(shù)呢?

Thread(bool canCallJava = true)。

我們必須得了解它實(shí)際創(chuàng)建的線程函數(shù)是什么。Thread類(lèi)真實(shí)的線程是創(chuàng)建在run函數(shù)中的。

1. 一個(gè)變量,兩種處理

先來(lái)看一段代碼:

[-->Thread.cpp]

status_t Thread::run(const char* name, int32_tpriority, size_t stack)

{

?? Mutex::Autolock_l(mLock);

??? ....

?? //如果mCanCallJava為真,則調(diào)用createThreadEtc函數(shù),線程函數(shù)是_threadLoop。

?//_threadLoop是Thread.cpp中定義的一個(gè)函數(shù)。

?? if(mCanCallJava) {

???????res = createThreadEtc(_threadLoop,this, name, priority,

?????????????????????????????????? stack,&mThread);

??? } else{

???????res = androidCreateRawThreadEtc(_threadLoop, this, name, priority,

?????????????????????????????????? stack,&mThread);

??? }

上面的mCanCallJava將線程創(chuàng)建函數(shù)的邏輯分為兩個(gè)分支,雖傳入的參數(shù)都有_threadLoop,但調(diào)用的函數(shù)卻不同。先直接看mCanCallJava為true的這個(gè)分支,代碼如下所示:

[-->Thread.h::createThreadEtc()函數(shù)]

inline bool createThreadEtc(thread_func_tentryFunction,

??????????????????????????? void *userData,

??????????????????????????? const char*threadName = "android:unnamed_thread",

??????????????????????????? int32_tthreadPriority = PRIORITY_DEFAULT,

??????????????????????????? size_tthreadStackSize = 0,

??????????????????????????? thread_id_t*threadId = 0)

{

??? returnandroidCreateThreadEtc(entryFunction, userData, threadName,

??????? ???????????threadPriority, threadStackSize,threadId) ? true : false;

}

它調(diào)用的是androidCreateThreadEtc函數(shù),相關(guān)代碼如下所示:

// gCreateThreadFn是函數(shù)指針,初始化時(shí)和mCanCallJava為false時(shí)使用的是同一個(gè)

//線程創(chuàng)建函數(shù)。那么有地方會(huì)修改它嗎?

static android_create_thread_fn gCreateThreadFn= androidCreateRawThreadEtc;

int androidCreateThreadEtc(android_thread_func_tentryFunction,

??????????????????????????? void*userData,const char* threadName,

??????????????????????????? int32_tthreadPriority,size_t threadStackSize,

??????????????????????????? android_thread_id_t*threadId)

{

??? returngCreateThreadFn(entryFunction, userData, threadName,

??????? ???????????????????????threadPriority,threadStackSize, threadId);

}

如果沒(méi)有人修改這個(gè)函數(shù)指針,那么mCanCallJava就是虛晃一槍?zhuān)o(wú)什么作用,很可惜,代碼中有的地方是會(huì)修改這個(gè)函數(shù)指針的指向的,請(qǐng)看:

2. zygote偷梁換柱

在第四章4.2.1的第2小節(jié)AndroidRuntime調(diào)用startReg的地方,就有可能修改這個(gè)函數(shù)指針,其代碼如下所示:

[-->AndroidRuntime.cpp]

/*static*/ int AndroidRuntime::startReg(JNIEnv*env)

{

?? //這里會(huì)修改函數(shù)指針為javaCreateThreadEtc

? androidSetCreateThreadFunc((android_create_thread_fn)javaCreateThreadEtc);

? return0;

}

所以,如果mCanCallJava為true,則將調(diào)用javaCreateThreadEtc。那么,這個(gè)函數(shù)有什么特殊之處呢?來(lái)看其代碼,如下所示:

[-->AndroidRuntime.cpp]

int AndroidRuntime::javaCreateThreadEtc(

???????????????????????????????android_thread_func_tentryFunction,

??????????????????????????????? void* userData,

??????????????????????????????? const char*threadName,

??????????????????????????????? int32_tthreadPriority,

??????????????????????????????? size_t threadStackSize,

???????????????????????????????android_thread_id_t* threadId)

{

??? void**args = (void**) malloc(3 * sizeof(void*));??

??? intresult;

???args[0] = (void*) entryFunction;

???args[1] = userData;

???args[2] = (void*) strdup(threadName);

??? //調(diào)用的還是androidCreateRawThreadEtc,但線程函數(shù)卻換成了javaThreadShell。

??? result= androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,

??????? ?????????????????threadName, threadPriority,threadStackSize, threadId);

??? returnresult;

}

[-->AndroidRuntime.cpp]

int AndroidRuntime::javaThreadShell(void* args){

??? ??......

???? intresult;

??? //把這個(gè)線程attach到JNI環(huán)境中,這樣這個(gè)線程就可以調(diào)用JNI的函數(shù)了

??? if(javaAttachThread(name, &env) != JNI_OK)

???????return -1;

???? //調(diào)用實(shí)際的線程函數(shù)干活

?? ??result = (*(android_thread_func_t)start)(userData);

?? //從JNI環(huán)境中detach出來(lái)。

???javaDetachThread();

???free(name);

??? returnresult;

}

3. 費(fèi)力而討好

你明白mCanCallJava為true的目的了嗎?它創(chuàng)建的新線程將:

·? 在調(diào)用你的線程函數(shù)之前會(huì)attach到 JNI環(huán)境中,這樣,你的線程函數(shù)就可以無(wú)憂(yōu)無(wú)慮地使用JNI函數(shù)了。

·? 線程函數(shù)退出后,它會(huì)從JNI環(huán)境中detach,釋放一些資源。

第二點(diǎn)尤其重要,因?yàn)檫M(jìn)程退出前,dalvik虛擬機(jī)會(huì)檢查是否有attach了,但是最后未detach的線程如果有,則會(huì)直接abort(這不是一件好事)。如果你關(guān)閉JNI check選項(xiàng),就不會(huì)做這個(gè)檢查,但我覺(jué)得,這個(gè)檢查和資源釋放有關(guān)系。建議還是重視JNIcheck。如果直接使用POSIX的線程創(chuàng)建函數(shù),那么凡是使用過(guò)attach的,最后就都需要detach!

Android為了dalvik的健康真是費(fèi)盡心機(jī)呀。

4. 線程函數(shù)_threadLoop介紹

不論一分為二是如何處理的,最終的線程函數(shù)_threadLoop都會(huì)被調(diào)用,為什么不直接調(diào)用用戶(hù)傳入的線程函數(shù)呢?莫非_threadLoop會(huì)有什么暗箱操作嗎?下面,我們來(lái)看:

[-->Thread.cpp]

int Thread::_threadLoop(void* user)

{

???Thread* const self = static_cast<Thread*>(user);

???sp<Thread> strong(self->mHoldSelf);

???wp<Thread> weak(strong);

???self->mHoldSelf.clear();

?

#if HAVE_ANDROID_OS

???self->mTid = gettid();

#endif

?

??? boolfirst = true;

?

??? do {

???????bool result;

??????? if(first) {

???????????first = false;

??????????//self代表繼承Thread類(lèi)的對(duì)象,第一次進(jìn)來(lái)將調(diào)用readyToRun,看看是否準(zhǔn)備好

???????? ?self->mStatus = self->readyToRun();

???????????result = (self->mStatus == NO_ERROR);

?

???????????if (result && !self->mExitPending) {

????????????????result = self->threadLoop();

???????????}

??????? }else {

??????????/*

調(diào)用子類(lèi)實(shí)現(xiàn)的threadLoop函數(shù),注意這段代碼運(yùn)行在一個(gè)do-while循環(huán)中。

???????????? 這表示即使我們的threadLoop返回了,線程也不一定會(huì)退出。

?????????*/

???????????result = self->threadLoop();

??????? }

?? /*

線程退出的條件:

?? ?1)result 為false。這表明,如果子類(lèi)在threadLoop中返回false,線程就可以

??? 退出。這屬于主動(dòng)退出的情況,是threadLoop自己不想繼續(xù)干活了,所以返回false。

讀者在自己的代碼中千萬(wàn)別寫(xiě)錯(cuò)threadLoop的返回值。

??? 2)mExitPending為true,這個(gè)變量可由Thread類(lèi)的requestExit函數(shù)設(shè)置,這種

??? 情況屬于被動(dòng)退出,因?yàn)橛赏饨鐝?qiáng)制設(shè)置了退出條件。

?? */

??????? if(result == false || self->mExitPending) {

???????????self->mExitPending = true;

???????????self->mLock.lock();

???????????self->mRunning = false;

???????????self->mThreadExitedCondition.broadcast();

???????????self->mLock.unlock();

???????????break;

??????? }

???????strong.clear();

???????strong = weak.promote();

??? }while(strong != 0);

???

??? return0;

}

關(guān)于_threadLoop,我們就介紹到這里。請(qǐng)讀者務(wù)必注意下面一點(diǎn):

·? threadLoop運(yùn)行在一個(gè)循環(huán)中,它的返回值可以決定是否退出線程。

5.3.2 ?常用同步類(lèi)

同步,是多線程編程中不可回避的話題,同時(shí)也是一個(gè)非常復(fù)雜的問(wèn)題。這里,只簡(jiǎn)單介紹一下Android提供的同步類(lèi)。這些類(lèi),只對(duì)系統(tǒng)提供的多線程同步函數(shù)(這種函數(shù)我們也稱(chēng)之為Raw API)進(jìn)行了面向?qū)ο蟮姆庋b,讀者必須先理解Raw API,然后才能真正掌握其具體用法。

了解Windows下的多線程編程,有很多參考資料,但我以為,現(xiàn)在先學(xué)習(xí)MSDN就可以了。有關(guān)Linux下完整系統(tǒng)闡述多線程編程的書(shū)籍目前較少,這里推薦一本含金量較高的著作《Programmingwith POSIX Thread》(本書(shū)只有英文版的,由Addison-Wesley出版)。

Android提供了兩個(gè)封裝好的同步類(lèi),它們是Mutex和Condition。這是重量級(jí)的同步技術(shù),一般內(nèi)核會(huì)有對(duì)應(yīng)的支持。另外,OS還提供了簡(jiǎn)單的原子操作,這些也算是同步技術(shù)的一種。下面分別來(lái)介紹這三種東西。

1. 互斥類(lèi)——Mutex

Mutex是互斥類(lèi),用于多線程訪問(wèn)同一個(gè)資源的時(shí)候,保證一次只能有一個(gè)線程能訪問(wèn)該資源。在《Windows核心編程》一書(shū)中,對(duì)于這種互斥訪問(wèn)有一個(gè)很形象的比喻:想象你在飛機(jī)上如廁,這時(shí)衛(wèi)生間的信息牌上顯示“有人”,你必須等里邊的人出來(lái)后才可進(jìn)去。這就是互斥的含義。

下面來(lái)看Mutex的實(shí)現(xiàn)方式,它們都很簡(jiǎn)單。

(1)Mutex介紹

其代碼如下所示:

[-->Thread.h::Mutex的聲明和實(shí)現(xiàn)]

inline Mutex::Mutex(int type, const char* name){

??? if(type == SHARED) {

??????//type如果是SHARED,則表明這個(gè)Mutex支持跨進(jìn)程的線程同步

????? //以后我們?cè)贏udio系統(tǒng)和Surface系統(tǒng)中會(huì)經(jīng)常見(jiàn)到這種用法

???????pthread_mutexattr_t attr;

???????pthread_mutexattr_init(&attr);

???????pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);

???????pthread_mutex_init(&mMutex, &attr);

???????pthread_mutexattr_destroy(&attr);

? ??} else {

???????pthread_mutex_init(&mMutex, NULL);

??? }

}

inline Mutex::~Mutex() {

???pthread_mutex_destroy(&mMutex);

}

inline status_t Mutex::lock() {

??? return-pthread_mutex_lock(&mMutex);

}

inline void Mutex::unlock() {

???pthread_mutex_unlock(&mMutex);

}

inline status_t Mutex::tryLock() {

??? return-pthread_mutex_trylock(&mMutex);

}

關(guān)于Mutex的使用,除了初始化外,最重要的是lock和unlock函數(shù)的使用,它們的用法如下:

·? 要想獨(dú)占衛(wèi)生間,必須先調(diào)用Mutex的lock函數(shù)。這樣,這個(gè)區(qū)域就被鎖住了。如果這塊區(qū)域之前已被別人鎖住,lock函數(shù)則會(huì)等待,直到可以進(jìn)入這塊區(qū)域?yàn)橹?。系統(tǒng)保證一次只有一個(gè)線程能lock成功。

·? 當(dāng)你“方便”完畢,記得調(diào)用Mutex的unlock以釋放互斥區(qū)域。這樣,其他人的lock才可以成功返回。

·? 另外,Mutex還提供了一個(gè)trylock函數(shù),該函數(shù)只是嘗試去鎖住該區(qū)域,使用者需要根據(jù)trylock的返回值判斷是否成功鎖住了該區(qū)域。

注意,以上這些內(nèi)容都和Raw API有關(guān),不了解它的讀者可自行學(xué)習(xí)與它相關(guān)的知識(shí)。在Android系統(tǒng)中,多線程也是常見(jiàn)和重要的編程手段,務(wù)請(qǐng)大家重視。

Mutex類(lèi)確實(shí)比Raw API方便好用,不過(guò)還是稍顯麻煩。來(lái)看下一節(jié)。

(2)AutoLock介紹

AutoLock類(lèi)是定義在Mutex內(nèi)部的一個(gè)類(lèi),它其實(shí)是一幫“懶人”搞出來(lái)的,為什么這么說(shuō)呢?先來(lái)看看使用Mutex夠多麻煩:

·? 顯示調(diào)用Mutex的lock。

·? 在某個(gè)時(shí)候要記住調(diào)用該Mutex的unlock。

以上這些操作都必須一一對(duì)應(yīng),否則會(huì)出現(xiàn)“死鎖”!有些代碼中,在判斷分支特別多的情況下,unlock這句代碼被寫(xiě)得比比皆是,如稍有不慎,在某處就會(huì)忘寫(xiě)了它。有什么好辦法能解決這個(gè)問(wèn)題嗎?終于有人想出來(lái)一個(gè)好辦法,就是充分利用了C++的構(gòu)造和析構(gòu)函數(shù),只需一看AutoLock的定義就會(huì)明白。代碼如下所示:

[-->Thread.h Mutex::Autolock聲明和實(shí)現(xiàn)]

??? classAutolock {

???public:

??????? //構(gòu)造的時(shí)候調(diào)用lock

???????inline Autolock(Mutex& mutex) : mLock(mutex)? { mLock.lock(); }

???????inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }

??????? //析構(gòu)的時(shí)候調(diào)用unlock

???????inline ~Autolock() { mLock.unlock(); }

???private:

???????Mutex& mLock;

??? };

AutoLock的用法很簡(jiǎn)單:

·? 先定義一個(gè)Mutex,如 Mutex xlock;

·? 在使用xlock的地方,定義一個(gè)AutoLock,如 AutoLock autoLock(xlock)。

由于C++對(duì)