Mutex
Mutex是互斥類,用於多線程訪問同一個資源的時候,保證一次只有一個線程能訪問該資源
Mutex的聲明和實現
//Mutex.h
class Mutex {
48 public:
49 enum {
50 PRIVATE = 0,
51 SHARED = 1
52 };
53
54 Mutex();
55 explicit Mutex(const char* name);
56 explicit Mutex(int type, const char* name = NULL);
57 ~Mutex();
58
59 // lock or unlock the mutex
60 status_t lock();
61 void unlock();
62
63 // lock if possible; returns 0 on success, error otherwise
64 status_t tryLock();
65
66 #if defined(__ANDROID__)
67 // Lock the mutex, but don't wait longer than timeoutNs (relative time).
68 // Returns 0 on success, TIMED_OUT for failure due to timeout expiration.
69 //
70 // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep
71 // capabilities consistent across host OSes, this method is only available
72 // when building Android binaries.
73 //
74 // FIXME?: pthread_mutex_timedlock is based on CLOCK_REALTIME,
75 // which is subject to NTP adjustments, and includes time during suspend,
76 // so a timeout may occur even though no processes could run.
77 // Not holding a partial wakelock may lead to a system suspend.
78 status_t timedLock(nsecs_t timeoutNs);
79 #endif
80
81 // Manages the mutex automatically. It'll be locked when Autolock is
82 // constructed and released when Autolock goes out of scope.
83 class Autolock {
84 public:
85 inline explicit Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
86 inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
87 inline ~Autolock() { mLock.unlock(); }
88 private:
89 Mutex& mLock;
90 };
91
92 private:
93 friend class Condition;
94
95 // A mutex cannot be copied
96 Mutex(const Mutex&);
97 Mutex& operator = (const Mutex&);
98
99 #if !defined(_WIN32)
100 pthread_mutex_t mMutex;
101 #else
102 void _init();
103 void* mState;
104 #endif
105 };
106
107 // ---------------------------------------------------------------------------
108
109 #if !defined(_WIN32)
110
111 inline Mutex::Mutex() {
112 pthread_mutex_init(&mMutex, NULL);
113 }
114 inline Mutex::Mutex(__attribute__((unused)) const char* name) {
115 pthread_mutex_init(&mMutex, NULL);
116 }
117 inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
118 if (type == SHARED) {
119 pthread_mutexattr_t attr;
120 pthread_mutexattr_init(&attr);
121 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
122 pthread_mutex_init(&mMutex, &attr);
123 pthread_mutexattr_destroy(&attr);
124 } else {
125 pthread_mutex_init(&mMutex, NULL);
126 }
127 }
128 inline Mutex::~Mutex() {
129 pthread_mutex_destroy(&mMutex);
130 }
131 inline status_t Mutex::lock() {
132 return -pthread_mutex_lock(&mMutex);
133 }
134 inline void Mutex::unlock() {
135 pthread_mutex_unlock(&mMutex);
136 }
137 inline status_t Mutex::tryLock() {
138 return -pthread_mutex_trylock(&mMutex);
139 }
140 #if defined(__ANDROID__)
141 inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
142 timeoutNs += systemTime(SYSTEM_TIME_REALTIME);
143 const struct timespec ts = {
144 /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
145 /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
146 };
147 return -pthread_mutex_timedlock(&mMutex, &ts);
148 }
149 #endif
150
151 #endif // !defined(_WIN32)
152
153 // ---------------------------------------------------------------------------
154
155 /*
156 * Automatic mutex. Declare one of these at the top of a function.
157 * When the function returns, it will go out of scope, and release the
158 * mutex.
159 */
160
161 typedef Mutex::Autolock AutoMutex;
162
163 // ---------------------------------------------------------------------------
164 }; // namespace android
165 // ---------------------------------------------------------------------------
166
167 #endif // _LIBS_UTILS_MUTEX_H
Mutex最重要的是lock和unlock函數
lock函數:調用後加鎖,如果這塊區域之前已被別人鎖住,lock函數則會等待,直到可以進入這塊區域爲止。系統保證一次只有一個線程能lock成功。
unlock函數:調用Mutex的unlock以釋放互斥區域。這樣,其他的lock纔可以成功返回。
trylock函數:該函數只是嘗試去鎖住該區域,使用者需要根據trylock的返回值來判斷是否成功鎖住了該區域。
AutoLock
AutoLock類是定義在Mutex內部的一個類,利用了C++的構造和析構函數,實現在AutoLock對象生命週期內自動加鎖以及釋放鎖的操作。
class Autolock {
public:
//構造的時候調用lock。
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
//析構的時候調用unlock。
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
當Autolock構造時,主動調用內部成員變量mLock的lock()方法,而在析構時正好相反,調用它的unlock()方法釋放鎖。這樣的話,假如一個Autolock對象是局部變量,則在生命週期結束時就自動的把資源鎖解了。
Condition
主要函數:
wait(Mutex& mutex) 線程B和C等待事件
waitRelative(Mutex& mutex, nsecs_t reltime) 線程B和C的超時等待,B和C可以指定等待時間,當超過這個時間,條件卻還不滿足,則退出等待。
signal() 觸發者A用來通知條件已經滿足,但是B和C只有一個會被喚醒。
broadcast() 觸發者A用來通知條件已經滿足,所有等待者都會被喚醒。(廣播)
Condition需要配合Mutex使用,它是條件,也是一種標誌,一個與線程相互關聯的對象
class Condition {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Condition();
Condition(int type);//如果type是SHARED,表示支持跨進程的條件同步
~Condition();
status_t wait(Mutex& mutex);
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
void signal();
void broadcast();
private:
#if defined(HAVE_PTHREADS)
pthread_cond_t mCond;
#else
void* mState;
#endif
}
比如:
//android/frameworks/av/services/audioflinger/Threads.h
class HenrySenseThread : public Thread {
public:
MaxxSenseThread(const sp<AudioFlinger>& audioFlinger);
void signal();
// Thread virtuals
bool threadLoop();
void exit();
private:
void activeTracksChanged();
status_t getActiveTracksPid(int *pSize, int *pActiveClientPid);
sp<IMediaPlayerService> sMediaPlayerService;
const sp<IMediaPlayerService>& getMediaPlayerService();
status_t GetActivePidsFromMediaPlayerService(int *size, int *pids);
const sp<AudioFlinger> mAudioFlinger;
Condition mWaitWorkCV;
Mutex mLock;
bool mNeedToCheck;
effect_descriptor_t mDescriptor;
};
#endif
在類HenrySenseThread 中聲明瞭Condition 變量 mWaitWorkCV ;
//android/frameworks/av/services/audioflinger/Threads.cpp
void AudioFlinger::HenrySenseThread::signal()
{
ALOGV("signal()");
mLock.lock();
mNeedToCheck = true;
mWaitWorkCV.signal(); //調用喚醒處於等待狀態mWaitWorkCV.wait(mlock)的地方繼續執行
mLock.unlock();
}
bool AudioFlinger::MaxxSenseThread::threadLoop()
{
ALOGV("threadLoop()");
if (exitPending()) {
return false;
}
mLock.lock();
if (!mNeedToCheck) {
mWaitWorkCV.wait(mLock);//當前線程在條件mWaitWorkCV下處於等待狀態,調用 mWaitWorkCV.signal()後將被喚醒
}
mNeedToCheck = false;
mLock.unlock();
if (exitPending()) {
return false;
}
activeTracksChanged();
return true;
}