【C++】Android中的同步機制
在涉及多執行緒、多程序程式設計時,同步問題是不可避免的。在不同的作業系統或者專案中,都有自獨特的同步手法,不過同步原理基本相同。在Android系統中,封裝了幾個同步類,下面來看一下這些同步類的原始碼是如何實現的。
1、Mutex
Mutex是個互斥鎖,即MUTual EXclusion,對pthread的mutex進行了簡單的封裝,內部還有個巢狀類AutoLock,從名字上就可以看出這個類的功能是自動加鎖解鎖,使用原理正是基於變數的生命週期,物件建立時加鎖,銷燬時解鎖。
Android中Mutex的原始碼路徑為:
system/core/include/utils/Mutex.h
下面分析一下Mutex的原始碼實現。
// Mutex.h
// 巨集定義慣例
#ifndef _LIBS_UTILS_MUTEX_H
#define _LIBS_UTILS_MUTEX_H
// C99引入的標準C庫的標頭檔案
// 定義了幾種擴充套件的整數型別和巨集
#include <stdint.h>
// 基本系統資料型別
#include <sys/types.h>
// 日期和時間相關函式
#include <time.h>
// 平臺相關
// pthread即POSIX執行緒
// 定義了一系列執行緒及同步相關的介面
#if !defined(_WIN32)
# include <pthread.h>
#endif
// Android自定義了errno
#include <utils/Errors.h>
// Android自定義了時間格式轉換函式
#include <utils/Timers.h>
// android名字空間
namespace android {
// Condition類前置宣告
// 作為Mutex類的友元
class Condition;
class Mutex {
public:
// PRIVATE限於同一程序內的多執行緒同步
// SHARED支援程序間同步
// 從下面的Mutex建構函式可以看出兩者的區別
enum {
PRIVATE = 0 ,
SHARED = 1
};
// 幾個構造/解構函式
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
~Mutex();
// 類似於pthread的lock/unlock/trylock
status_t lock();
void unlock();
status_t tryLock();
// 平臺相關
// timedLock獲取鎖時限制了等待時間
#if defined(__ANDROID__)
status_t timedLock(nsecs_t timeoutMilliseconds);
#endif
// 自動加鎖解鎖
class Autolock {
public:
// 構造物件時加鎖
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
// 銷燬物件時解鎖
inline ~Autolock() { mLock.unlock(); }
private:
// 物件型別為引用時只能通過初始化列表進行初始化
Mutex& mLock;
};
private:
// 友元宣告
friend class Condition;
// 拷貝建構函式和賦值操作符私有宣告而不定義
// Mutex不能被拷貝
Mutex(const Mutex&);
Mutex& operator=(const Mutex&);
// 平臺相關
// 非_WIN32時對pthread的mutex進行封裝
#if !defined(_WIN32)
pthread_mutex_t mMutex;
#else
void _init();
void* mState;
#endif
};
// ---------------------------------------------------------------------------
#if !defined(_WIN32)
// 建構函式呼叫pthread_mutex_init初始化mutex
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
// 建構函式呼叫pthread_mutex_init初始化mutex
// __attribute__是GCC的一個特性
// unused表示其後的實參name沒有被使用
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
// 指定mutex型別的建構函式
// 當type為SHARED時
// 通過pthread_mutexattr_t設定其屬性為PTHREAD_PROCESS_SHARED
// 表示mutex支援多程序
inline Mutex::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);
}
}
// 解構函式呼叫pthread_mutex_destroy銷燬mutex物件
inline Mutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
// lock加鎖時呼叫了pthread_mutex_lock
// 鎖被佔用時會阻塞
// 成功時返回0
// 失敗時返回一個errno
// 這些errno和status_t型別在utils/Errors.h中定義
inline status_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
// unlock解鎖時呼叫了pthread_mutex_unlock
inline void Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
// trylock加鎖時呼叫了pthread_mutex_trylock
// 鎖被佔用時會直接返回二不會等待
inline status_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
// 特有的timedLock
// 加鎖阻塞時限制了等待的時間
// nsecs_t在utils/Timers.h中定義
// timespec結構體的兩個成員是秒和納秒
#if defined(__ANDROID__)
inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
const struct timespec ts = {
/* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
/* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
};
return -pthread_mutex_timedlock(&mMutex, &ts);
}
#endif
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
// AutoMutex慣用法:
// 在函式中需要加鎖時先宣告一個AutoMutex區域性變數
// AutoMutex區域性變數自動銷燬時便會解鎖
typedef Mutex::Autolock AutoMutex;
}; // namespace android
#endif // _LIBS_UTILS_MUTEX_H
2、Condition
Condition條件變數同樣是對pthread的條件變數進行了封裝,不過具體實現還使用了Mutex。當條件滿足時直接返回,繼續執行未完成的操作,否則就會等待,直到條件滿足而被喚醒。
Android中Condition的原始碼路徑為:
system/core/include/utils/Condition.h
下面分析一下Condition的原始碼實現。
// Condition.h
#ifndef _LIBS_UTILS_CONDITION_H
#define _LIBS_UTILS_CONDITION_H
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
#if !defined(_WIN32)
# include <pthread.h>
#endif
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/Timers.h>
namespace android {
// 條件變數實際上是對互斥鎖的一種擴充套件
// 條件變數允許執行緒阻塞並等待其它的執行緒發訊號將其喚醒
class Condition {
public:
// PRIVATE和SHARED的含義同Mutex中的用法
enum {
PRIVATE = 0,
SHARED = 1
};
// 喚醒等待者
// 喚醒一個還是全部
// 對應於signal和broadcast
enum WakeUpType {
WAKE_UP_ONE = 0,
WAKE_UP_ALL = 1
};
Condition();
Condition(int type);
~Condition();
// 阻塞式等待條件變數或者設定延時等待時間
status_t wait(Mutex& mutex);
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// 喚醒單個等待者或者所有等待者
void signal();
void signal(WakeUpType type) {
if (type == WAKE_UP_ONE) {
signal();
} else {
broadcast();
}
}
void broadcast();
private:
// 封裝了pthread_cond_t條件變數
#if !defined(_WIN32)
pthread_cond_t mCond;
#else
void* mState;
#endif
};
// ---------------------------------------------------------------------------
#if !defined(_WIN32)
// 建構函式呼叫pthread_cond_init初始化條件變數
inline Condition::Condition() {
pthread_cond_init(&mCond, NULL);
}
// 原理同Mutex
// 當型別為SHARED時
// 通過pthread_condattr_t設定其屬性為PTHREAD_PROCESS_SHARED
// 以支援程序間的同步
inline Condition::Condition(int type) {
if (type == SHARED) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&mCond, &attr);
pthread_condattr_destroy(&attr);
} else {
pthread_cond_init(&mCond, NULL);
}
}
// 解構函式呼叫pthread_cond_destroy銷燬條件變數
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
}
// 呼叫pthread_cond_wait等待條件變數
// 這個wait機制比較有意思
// wait前首先要給mutex加鎖
// wait內部會先給mutex解鎖然後等待
// 直到條件滿足時再給mutex加鎖並返回
// 這些操作是一個原子操作
inline status_t Condition::wait(Mutex& mutex) {
return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
// timedWait設定了延時等待時間
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
struct timespec ts;
ts.tv_sec = reltime / 1000000000;
ts.tv_nsec = reltime % 1000000000;
return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
struct timespec ts;
#if defined(__linux__)
clock_gettime(CLOCK_REALTIME, &ts);
#else // __APPLE__
struct timeval t;
gettimeofday(&t, NULL);
ts.tv_sec = t.tv_sec;
ts.tv_nsec= t.tv_usec * 1000;
#endif
ts.tv_sec += reltime / 1000000000;
ts.tv_nsec += reltime % 1000000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec += 1;
}
return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
}
// 呼叫pthread_cond_signal喚醒某個等待者
inline void Condition::signal() {
pthread_cond_signal(&mCond);
}
// 呼叫pthread_cond_broadcast喚醒所有等待者
inline void Condition::broadcast() {
pthread_cond_broadcast(&mCond);
}
#endif // !defined(_WIN32)
}; // namespace android
#endif // _LIBS_UTILS_CONDITON_H
3、RWLock
RWLock即讀寫鎖,同樣是對pthread的rwlock進行了封裝,基本原理是可以多個執行緒佔用讀鎖,但是隻能一個執行緒佔用寫鎖。
Android中RWLock的原始碼路徑為:
system/core/include/utils/RWLock.h
下面分析一下RWLock的原始碼實現,程式碼結構與Mutex的很相似。
// RWLock.h
#ifndef _LIBS_UTILS_RWLOCK_H
#define _LIBS_UTILS_RWLOCK_H
#include <stdint.h>
#include <sys/types.h>
#if !defined(_WIN32)
# include <pthread.h>
#endif
#include <utils/Errors.h>
// 定義了執行緒相關的資料型別和優先順序
#include <utils/ThreadDefs.h>
namespace android {
#if !defined(_WIN32)
// RWLock讀寫鎖的特點是:
// 當讀寫鎖處於寫模式時
// 其後的讀鎖/寫鎖都會阻塞
// 當讀寫鎖處於讀模式時
// 其後的讀鎖仍可以獲得控制權
// 但寫鎖將被阻塞以及這個寫鎖之後的讀鎖也會被阻塞
class RWLock {
public:
// 同樣用法的enum
enum {
PRIVATE = 0,
SHARED = 1
};
// 類似於Mutex的構造/解構函式
RWLock();
RWLock(const char* name);
RWLock(int type, const char* name = NULL);
~RWLock();
// 幾個讀鎖/寫鎖及解鎖函式
status_t readLock();
status_t tryReadLock();
status_t writeLock();
status_t tryWriteLock();
void unlock();
// 類似於Mutex的自動讀鎖
class AutoRLock {
public:
inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
inline ~AutoRLock() { mLock.unlock(); }
private:
RWLock& mLock;
};
// 類似於Mutex的自動寫鎖
class AutoWLock {
public:
inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
inline ~AutoWLock() { mLock.unlock(); }
private:
RWLock& mLock;
};
private:
// 類似於Mutex的用法
// 禁止RWLock拷貝
RWLock(const RWLock&);
RWLock& operator=(const RWLock&);
// 對pthread_rwlock_t進行了封裝
pthread_rwlock_t mRWLock;
};
// 建構函式呼叫pthread_rwlock_init對讀寫鎖進行初始化
inline RWLock::RWLock() {
pthread_rwlock_init(&mRWLock, NULL);
}
// 建構函式呼叫pthread_rwlock_init對讀寫鎖進行初始化
// unused的name沒有實際用處
// 猜想大概是個備用引數
inline RWLock::RWLock(__attribute__((unused)) const char* name) {
pthread_rwlock_init(&mRWLock, NULL);
}
// 當type為SHARED時
// 通過對應的pthread_rwlockattr_t設定其屬性為PTHREAD_PROCESS_SHARED
// 以支援跨程序的同步
inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_rwlock_init(&mRWLock, &attr);
pthread_rwlockattr_destroy(&attr);
} else {
pthread_rwlock_init(&mRWLock, NULL);
}
}
// 解構函式呼叫pthread_rwlock_destroy銷燬讀寫鎖
inline RWLock::~RWLock() {
pthread_rwlock_destroy(&mRWLock);
}
// 呼叫pthread_rwlock_rdlock以獲取讀鎖
inline status_t RWLock::readLock() {
return -pthread_rwlock_rdlock(&mRWLock);
}
// 呼叫pthread_rwlock_tryrdlock以獲取讀鎖並不會阻塞
inline status_t RWLock::tryReadLock() {
return -pthread_rwlock_tryrdlock(&mRWLock);
}
// 呼叫pthread_rwlock_wrlock以獲取寫鎖
inline status_t RWLock::writeLock() {
return -pthread_rwlock_wrlock(&mRWLock);
}
// 呼叫pthread_rwlock_trywrlock以獲取寫鎖並不會阻塞
inline status_t RWLock::tryWriteLock() {
return -pthread_rwlock_trywrlock(&mRWLock);
}
// 呼叫pthread_rwlock_unlock以解鎖
inline void RWLock::unlock() {
pthread_rwlock_unlock(&mRWLock);
}
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
}; // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_RWLOCK_H
4、Barrier
Barrier是基於Mutex和Condition實現的一個模型,專門為SurfaceFlinger設計,用起來更加簡單,而不是像Mutex和Condition那樣作為一個通用的Utility。
Android中Barrier的原始碼路徑為:
framework/native/services/surfaceflinger/Barrier.h
下面分析一下Barrier 的原始碼實現。
// Barrier.h
#ifndef ANDROID_BARRIER_H
#define ANDROID_BARRIER_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
namespace android {
// Barrier集合了Mutex和Condition
// 所謂的條件變數通過enum值OPENED和CLOSED實現
// 提供了3個函式open/close/wait
// 這3個函式都對state進行了讀/寫
// 所以需要加鎖保護
// 否則會造成死鎖等意想不到的現象
class Barrier
{
public:
// 初始狀態為CLOSED
inline Barrier() : state(CLOSED) { }
inline ~Barrier() { }
// open函式設定state為OPENED
// 呼叫broadcast函式解除wait函式的阻塞狀態
void open() {
Mutex::Autolock _l(lock);
state = OPENED;
cv.broadcast();
}
// close函式重置state為CLOSED
// 這時將阻塞wait函式
void close() {
Mutex::Autolock _l(lock);
state = CLOSED;
}
// 當state為OPEND時
// wait被喚醒
// 從而退出wait
void wait() const {
Mutex::Autolock _l(lock);
while (state == CLOSED) {
cv.wait(lock);
}
}
private:
enum { OPENED, CLOSED };
mutable Mutex lock;
mutable Condition cv;
volatile int state;
};
}; // namespace android
#endif // ANDROID_BARRIER_H
相關推薦
【C++】Android中的同步機制
在涉及多執行緒、多程序程式設計時,同步問題是不可避免的。在不同的作業系統或者專案中,都有自獨特的同步手法,不過同步原理基本相同。在Android系統中,封裝了幾個同步類,下面來看一下這些同步類的原始碼是如何實現的。 1、Mutex Mutex是個互斥鎖,
android開發學習 ------- 【轉】 android中的單例模式 (詳解)
lan post tail -- and 使用 href details android開發 https://blog.csdn.net/u011418943/article/details/60139644 這篇文章 前因後果 都說出來了 ,值得學習。 htt
【C++】類中靜態成員的宣告、初始化
【C++】類中靜態成員的宣告、初始化 類中靜態成員的宣告 初始化 靜態資料成員值的改變 完整例子 有參考大佬 零點零一 的文章: https://blog.csdn.net/thanklife/article/details/784
【轉】Android中保持Service的存活
這幾天一直在準備考試,總算有個半天時間可以休息下,寫寫部落格。 如何讓Service keep alive是一個很常見的問題。 在APP開發過程中,需要Service持續提供服務的應用場景太多了,比如鬧鐘需要作出及時提醒,那麼比如得有一個Service不斷去比較當前時間和設定時間;QQ要能流暢的聊天,必然
【C++】工作中遇到的難點
一,explicit C++ explicit關鍵字用來修飾類的建構函式,表明該建構函式是顯式的。 建構函式有顯示和隱式之分。建構函式預設的式隱式的,如下: 1. class MyClass 2. { 3. public: 4. MyClass( int num );
【C++】類中成員函式聲明後面接 const
const 表示對類中成員函式屬性的宣告; 表示不會修改類中的資料成員; 在編寫const成員函式時,若不慎修改了資料成員,或者呼叫了其他非const成員函式,編譯器將指出錯誤; 以下程式中,類stack的成員函式GetCount僅用於計數,從邏輯上講GetCount應
【C++】陣列中連續子陣列的最大和
題意:Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the
【轉】Android中的http請求 URLEncode
原地址:http://blog.csdn.net/a102111/article/details/40978541 最近在搞http相關的處理,碰到一個URLEncode的問題,簡單記錄下,供後期查詢。 傳送給服務端的請求中的引數值,如果含有特殊符號,需要是做U
【C#】wpf中的xmlns名稱空間為什麼是一個網址,代表了什麼意思
新建一個wpf的專案,我們先來看下它預設的名稱空間都是哪些? 可以看到xmlns有的是網址,有的是clr-namespace開頭的一串字母。clr開頭的比較好理解,就是執行時的名稱空間,就像C#程式
【達內課程】Android中的GC垃圾回收機制與記憶體洩漏
當main()方法執行完,main()方法中的區域性變數都會彈棧,從棧當中銷燬 當左側棧中的e2和e銷燬後,右側中的兩個物件就是垃圾 java底層有一種GC垃圾回收機制,在java程式執行時,GC執行緒會不斷找尋垃圾,是的話會清除掉 當我們點選模擬機的返回鍵時,發生了什麼 當G
【Android 開發】: Android 訊息處理機制之三: Handler 中 sendMessage() 原始碼剖析
閱讀此文,請先閱讀以下相關連線: sendMessage()的幾種過載方法的使用方式的不同以及它們的原始碼的剖析. 通過前面幾講的內容,我們知道Android不但可以使用非同步任務處理多執行
【09.03.30】Android中使用C++程式讀寫Parcel的簡單例子
Android中的Parcel類困惑了我好一段時間(當然現在也沒把Parcel完全弄明白),查了一些資料也不知道它裡面是以一種什麼格式儲存資料的。因為它對外提供的讀寫函式都沒有提到具體一個讀寫函式到底是讀寫Parcel中的哪一塊地址裡的資料。比如網上有這麼兩段程式碼:
【轉】VS2010中 C++創建DLL圖解
-a rar cls ret ria endif -s pan 項目 標簽: dllc++2010threadlibraryc 本文章已收錄於: .embody { padding: 10px 10px 10px; margin: 0 -20px; b
【Android安全】Android中的“SpyLocker”惡意軟件 - 您需要知道的內容
編譯參數 agen 詳細 通過 來源 永遠 鎖屏 mob shtml SpyLocker惡意軟件是對Android安全應用的最新威脅,幾維安全詳細介紹了您需要了解的信息,以幫助您保護設備。此外,如果您的設備受到感染,幾維安全最新的應用程序將幫助您掃描,檢測和刪除SpyLoc
【C#】淺析C#中的日期處理
see var time tostring 靈活性 ide format tin 介紹 1.字符串轉化為日期 1.1第一種方式 使用 Convert.toDateTime 方法,該方法有很多重載方法,這裏筆者就介紹兩個常用的重載方法。 第一種: 使用: Con
【Android-3】Android中的任務棧(Task)
集合 情況下 清除 bsp 生命周期方法 任務棧 保存 sin 也會 一、Android任務棧 概述:Android中的任務棧其實就是Activity的集合,在Android中退出程序的時候必須把任務棧中的所有Activity清除出棧,此時才能安全的完全的退出程序, 任務棧
【C++】判斷元素是否在vector中,對vector去重,兩個vector求交集、並集
bool iostream space col 求交集 uniq AI void print #include <iostream> #include <vector> #include <algorithm> //sort函數、交並補
【c++】c++中重載輸出操作符,為什麽要返回引用
不返回 定義 類型 AS 標準 操作符 連續 新的 輸出 針對:ostream & operator <<(ostream & os, const ClassType &object) 說明幾點: 1.第一個形參為對ostream對象的引
【達內課程】Android中的Notification
什麼是通知 通知是Android中Service與使用者互動的一種方式(主要是Service) 一個傳送通知的栗子: private static final int NOTIFICATION_ID = 1001; private void sendNotificati
【速查】Android中EditText的inputType屬性
1.文字型別,多為大寫、小寫和數字符號。 android:inputType=”none” android:inputType=”text” android:inputType=”textCapCharacters” 字母大寫 android:inputType=”textCapWo