在Android OS中,提供了线程的同步与互斥机制,它们被封装成Mutex、Condition、Barrier三个类,其中前两个类是基于Linux线程API的封装;后一个类是基于前两个类的封装。我们现在只分析前两个类的封装,后一个在SurfaceFlinger中在做讲述。
Mutex-----互斥类
Mutex是互斥类,用于多线程访问同一个资源的时候,保证一次只有一个线程能访问该资源。
class Condition;
/*
* Simple mutex class. The implementation is system-dependent.
*
* The mutex must be unlocked by the thread that locked it. They are not
* recursive, i.e. the same thread can't lock it multiple times.
*/
class Mutex {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
status_t lock();
void unlock();
// lock if possible; returns 0 on success, error otherwise
status_t tryLock();
// Manages the mutex automatically. It'll be locked when Autolock is
// constructed and released when Autolock goes out of scope.
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;
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
#if defined(HAVE_PTHREADS)
pthread_mutex_t mMutex;
#else
void _init();
void* mState;
#endif
#ifdef _DEBUG_TRACE_MUTEX
const char* mName;
#endif
};
上述为Mutex类的定义,三个构造函数,一个析构函数,三个成员函数,两个成员变量。
关于Mutex的使用,除了初始化外,最重要的是lock和unlock函数的使用,它用于如下的环境:想要独占资源,必须先调用Mutex的lock函数,这样,这个区域就被锁住了。如果这块区域之前已经被别人锁住,lock函数则会等待,直到有人释放这块资源。这样系统保证一次只有一个线程能lok成功。当你对互斥区域的操作完毕,记得调用Mutex的unlock以释放互斥区域,这样,其他人的lock才可以成功返回。
另外Mutex还提供了trylock函数,该函数只是尝试去锁住该互斥区域,使用者需要根据trylock的返回值来判断是否成功锁住了该区域。当返回0时说明“锁住了”互斥区域。
对于这部分,Android为了开发的方便封装了Autolock类,可以说这就是一个“懒人类”。他对于开发者来说不必关心哪时候释放锁,或者说遗忘了调用释放锁操作unlock。Autolock充分利用类对象的生命周期,也就是类的构造函数和析构函数,我们先看Autolock的定义就会明白。
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;
};
可以看出Autolock的构造函数调用了Mutex的lock操作,析构函数调用了unlock操作,也就是在创建Autolock类实例时已经调用lock多互斥区加锁,在Autolock类实例生命周期结束时调用析构函数进而释放锁。这样方便了开发也极大的避免了对互斥区释放锁操作的遗忘。
Condition-----互斥类
多线程同步我们引入如下的一个场景来做说明:
线程A做初始化工作,而其他线程如线程B、C必须等到初始化工作完成后才能工作,即线程B、C在等待一个条件,当线程A完成初始化工作后,会触发这个条件,那么B、C线程就会被唤醒。
class Condition {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Condition();
Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
void signal();
// Signal the condition variable, allowing all threads to continue.
void broadcast();
private:
#if defined(HAVE_PTHREADS)
pthread_cond_t mCond;
#else
void* mState;
#endif
};
上述代码为Condition类的定义:
wait为线程等待操作;
waitRelative为线程定时等待操作;
signal为线程唤醒操作,只能唤醒一个线程;
broadcast为线程唤醒操作,可唤醒所有等待线程。