1. 程式人生 > >Android中同步類Mutex(AutoMutex)與Condition。

Android中同步類Mutex(AutoMutex)與Condition。



在Android中,封裝的同步類主要有MutexAutoMutex)與Condition

這兩個類在android中被大量的使用,這也說明這兩個類是非常重要的。

下面我們就從3個方面來分析他們。

  1. 它們是什麼,他們的實現原理,即what

  2. 為什麼要這麼去實現它,即why

  3. 我們怎麼去用他們,即how

    這樣我們就對它們有個深入的理解,不但知其然,而且知其所以然。

    MutexAutoMutex)與Condition程式碼分析

    1. MutexAutoMutex)程式碼分析

      Mutex是互斥類,用於多執行緒訪問同一個資源的時候,保證一次只有一個執行緒能訪問該資源。在《

      Windows核心程式設計》一書中,對於這種互斥訪問有一個很形象的比喻:想象你在飛機上如廁,這時衛生間的資訊牌上顯示有人,你必須等裡面的人出來後才可進去。這就是互斥的含義。

      它的程式碼實現如下

      /*

      * 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;

      //這種設計師非常優秀的,如果你手動去lockunlock,就有可能

      //忘了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做初始化工作,而其他執行緒,比如執行緒BC必須等到A初始化工作完後才能工作,即執行緒BC在等待一個條件,我們稱BC為等待者。當執行緒A完成初始化工作時,會觸發這個條件,那麼等待者BC就會被喚醒。觸發這個條件的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.

      //執行緒BC等待事件,wait這個名字也很形象

      status_t wait(Mutex& mutex);

      // same with relative timeout

      //執行緒BC的超時等待,BC可以指定等待時間,當超過這個時間,條件卻還不滿足,則退出等待。

      status_t waitRelative(Mutex& mutex,nsecs_t reltime);

      // Signal the condition variable, allowingexactly one thread to continue.

      //觸發者A用來通知條件已經滿足,但是BC只有一個會被喚醒

      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