Android中同步類Mutex(AutoMutex)與Condition。
在Android中,封裝的同步類主要有Mutex(AutoMutex)與Condition。
這兩個類在android中被大量的使用,這也說明這兩個類是非常重要的。
下面我們就從3個方面來分析他們。
-
它們是什麼,他們的實現原理,即what
-
為什麼要這麼去實現它,即why
-
我們怎麼去用他們,即how
這樣我們就對它們有個深入的理解,不但知其然,而且知其所以然。
一 Mutex(AutoMutex)與Condition程式碼分析
-
Mutex(AutoMutex)程式碼分析
Mutex是互斥類,用於多執行緒訪問同一個資源的時候,保證一次只有一個執行緒能訪問該資源。在《
它的程式碼實現如下
/*
* Copyright (C) 2007 The Android Open SourceProject
*
* Licensed under the Apache License, Version2.0 (the "License");
* you may not use this file except incompliance with the License.
* You may obtain a copy of the License at
*
*http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreedto in writing, software
* distributed under the License is distributedon an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied.
* See the License for the specific languagegoverning permissions and
* limitations under the License.
*/
#ifndef_LIBS_UTILS_MUTEX_H
#define_LIBS_UTILS_MUTEX_H
//ifndef/define/endif 主要目的是防止標頭檔案的重複包含和編譯
//如果有兩個地方都包含這個標頭檔案,就不會出現兩次包含的情況,良好的程式設計習慣。
#include<stdint.h>// 引用標準庫的標頭檔案
#include<sys/types.h>
#include<time.h>
#ifdefined(HAVE_PTHREADS)
# include<pthread.h>
#endif
#include<utils/Errors.h>
//---------------------------------------------------------------------------
namespaceandroid { //android的名稱空間,使用的時候用“using namespace android;”
//跟C++裡的“using namespace std;”一樣。
//---------------------------------------------------------------------------
class Condition;
/*
* Simple mutex class.The implementation is system-dependent.
*
* The mutex must be unlocked by the threadthat locked it.They are not
* recursive, i.e. the same thread can't lockit multiple times.
*/
class Mutex {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
//兩種型別:PRIVATE是程序內部使用的;SHARED是適用於跨程序共享的。
//如不指定,預設是PRIVATE的型別。
Mutex();//建構函式
Mutex(const char* name);//建構函式
Mutex(int type, const char*name = NULL);//建構函式,type就是上面的那兩種型別
~Mutex();//析構
// lock or unlock the mutex
status_tlock(); //獲取鎖。如果獲取就返回,否則掛起等待
voidunlock();//釋放鎖
// lock if possible; returns 0 on success,error otherwise
status_ttryLock();
//如果當前鎖可被獲取(未被別的執行緒獲取)就lock,否則就直接返回。
//返回值:0代表成功;其它值失敗。
//與lock()的區別在於不論成功與否都會及時返回,而不是掛起等待。
// Manages the mutex automatically. It'llbe locked when Autolock is
// constructed and released when Autolockgoes out of scope.
//Autolock是為了簡化Mutex的使用而定義的,並且充分利用了c++的構造與析構機制
//可以看出,在建構函式中 mLock.lock() 加鎖,在解構函式中 mLock.unlock() 解鎖。
//所以,對一個需要加鎖的函式來說,我們只需要在函式開始處,宣告這樣 (Mutex::Autolock autolock(mLock);),一個變數,它就會加鎖,
//等函式退出時,這樣一個臨時變數就會析構,就會解鎖。
////android系統裡幾乎到處都是這種使用,或者AutoMutex _l(mLock)這種使用
//這兩種使用是一樣的效果的,因為下面有這樣一行程式碼typedefMutex::Autolock AutoMutex;
//這種設計師非常優秀的,如果你手動去lock,unlock,就有可能
//忘了unlock,這樣的會很容易死鎖,死鎖在android系統裡後果是非常嚴重,大多數情況都會系統重啟
//大家都知道C++的建構函式解構函式是成對出現的,用了建構函式中 mLock.lock() 加鎖,
//在解構函式中 mLock.unlock() 解鎖這種設計之後,就不會出現忘了unlock的情況了
class Autolock {
public:
inline Autolock(Mutex& mutex) :mLock(mutex){ mLock.lock(); }
//其實這裡不加inline也是沒有關係的,在C++裡編譯器會自動去檢查這個函式體
//如果函式體邏輯足夠簡單,會自動把他當成inline函式,為了養成良好的程式碼習慣,還是要加上
inline Autolock(Mutex* mutex) :mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
private:
friend class Condition; //友元類Condition
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex&operator = (const Mutex&);
#ifdefined(HAVE_PTHREADS)
pthread_mutex_t mMutex;
#else
void_init();
void*mState;
#endif
};
//---------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
inlineMutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inlineMutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
inlineMutex::Mutex(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
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);
}
}
inlineMutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
inlinestatus_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inline voidMutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
inlinestatus_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
#endif //HAVE_PTHREADS
//---------------------------------------------------------------------------
/*
* Automatic mutex.Declare one of these at the top of afunction.
* When the function returns, it will go out ofscope, and release the
* mutex.
*/
typedefMutex::Autolock AutoMutex;
//---------------------------------------------------------------------------
}; //namespace android
// ---------------------------------------------------------------------------
#endif //_LIBS_UTILS_MUTEX_H
1.2Condition程式碼分析
Condition條件類,在多執行緒同步中,主要是下面這種使用場景使用到condition。
執行緒A做初始化工作,而其他執行緒,比如執行緒B、C必須等到A初始化工作完後才能工作,即執行緒B、C在等待一個條件,我們稱B、C為等待者。當執行緒A完成初始化工作時,會觸發這個條件,那麼等待者B、C就會被喚醒。觸發這個條件的A就是觸發者。上面的使用場景非常形象,而且條件類提供的函式也非常形象,它的程式碼如下所示:
/*
* Copyright (C) 2007 The Android Open SourceProject
*
* Licensed under the Apache License, Version2.0 (the "License");
* you may not use this file except incompliance with the License.
* You may obtain a copy of the License at
*
*http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreedto in writing, software
* distributed under the License is distributedon an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied.
* See the License for the specific languagegoverning permissions and
* limitations under the License.
*/
#ifndef_LIBS_UTILS_CONDITION_H
#define_LIBS_UTILS_CONDITION_H
#include<stdint.h>
#include<sys/types.h>
#include<time.h>
#if defined(HAVE_PTHREADS)
# include<pthread.h>
#endif
#include<utils/Errors.h>
#include<utils/Mutex.h>
#include<utils/Timers.h>
//---------------------------------------------------------------------------
namespace android {
//---------------------------------------------------------------------------
/*
* Condition variable class.The implementation is system-dependent.
*
* Condition variables are paired up withmutexes.Lock the mutex,
* call wait(), then either re-wait() if thingsaren't quite what you want,
* or unlock the mutex and continue.All threads calling wait() must
* use the same mutex for a given Condition.
*/
class Condition {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
//兩種型別:PRIVATE是程序內部使用的;SHARED是適用於跨程序共享的。
//如不指定,預設是PRIVATE的型別。
enum WakeUpType {
WAKE_UP_ONE = 0,
WAKE_UP_ALL = 1
};
Condition(); ////建構函式
Condition(int type);//建構函式,type就是上面的那兩種型別
~Condition();//析構
// Wait on the condition variable.Lock the mutex before calling.
//執行緒B和C等待事件,wait這個名字也很形象
status_t wait(Mutex& mutex);
// same with relative timeout
//執行緒B和C的超時等待,B和C可以指定等待時間,當超過這個時間,條件卻還不滿足,則退出等待。
status_t waitRelative(Mutex& mutex,nsecs_t reltime);
// Signal the condition variable, allowingexactly one thread to continue.
//觸發者A用來通知條件已經滿足,但是B和C只有一個會被喚醒
void signal();
// Signal the condition variable, allowingone or all threads to continue.
void signal(WakeUpType type) {
if (type == WAKE_UP_ONE) {
signal();
} else {
broadcast();
}
}
// Signal the condition variable, allowingall threads to continue.
//觸發者A用來通知條件已經滿足,所有等待者都會被喚醒。
void broadcast();
private:
#ifdefined(HAVE_PTHREADS)
pthread_cond_t mCond;
#else
void*mState;
#endif
-