《深入解析Android 5.0系统》——第6章,第6.2节Android native层的同步方法

本节书摘来自异步社区《深入解析Android 5.0系统》一书中的第6章,第6.2节Android native层的同步方法,作者 刘超,更多章节内容可以访问云栖社区“异步社区”公众号查看

6.2 Android native层的同步方法
深入解析Android 5.0系统
Android在Linux提供的线程同步函数的基础上进行了二次封装,让实现线程同步更加简单方便。这些同步类和函数在native层的代码中出现的非常频繁。

6.2.1 互斥体Mutex和自动锁Autolock
Mutex和Autolock是Android native层最常见的一种临界区保护手段,Autolock只是提供了一种更简便的使用Mutex的方法。

Mutex是一个C++的类,它的接口如下所示:

class Mutex {
    enum { PRIVATE = 0,  SHARED = 1 };    
    Mutex();
    Mutex(const char* name);
    Mutex(int type, const char* name = NULL);
    ~Mutex();
    status_t  lock();
    void  unlock();
    status_t  tryLock();
};

Mutex类有3个构造函数,最简单的函数不带任何参数。最复杂的有一个类型参数和一个名字参数,这个构造函数主要用于进程间的线程同步,这时第一个参数为“SHARED”。

Mutex的lock()和unlock()函数必须成对使用,在进入需要保护的区域前调用lock()函数,离开要保护的区域则需要调用unlock()函数。

此外,Mutex还提供了一个trylock()函数,这个函数将尝试去获取锁,如果成功则返回0,失败则返回非0值,通常是1。无论成功失败,trylock()函数都不会导致调用线程阻塞。

下面是使用Mutex来保护全局变量的一个简单例子。

Mutex g_mutex;
int g_count = 0;
void  ThreadFuncA()
{
    g_mutex.lock();
    g_count++;
    g_mutex.unlock();
}
void ThreadFuncB()
{
    g_mutex.lock();
    gCount--;
    if(gCount >= 0) {
         ......
    }
    g_mutex.unlock();
}

使用Mutex注意不要忘记调用unlock(),否则可能会造成死锁。如果一段受保护的代码有好几个出口,每处都调用unlock()会让代码看上去不简洁,也容易因为遗忘造成错误。因此,Android封装了一个Autolock类,使用时只需要在保护代码前构造一个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的原理很简单,就是在构造函数中加锁,在析构函数中解锁,因此,Autolock经常用在函数中来保护整个函数体。但是,Autolock使用不当也容易造成死锁。看看下面一个简单的例子:

Mutex g_lock;
void FooA()
{
    AutoLock(g_lock);
    .......
}
void FooB()
{
    AutoLock(g_lock);
    .......
    FooA()
}

上面的例子中函数FooA()和FooB()都使用了AutoLock(g_lock)来进行保护,而且FooB()函数调用了FooA()。当调用FooB()函数时,就会发生死锁。当然实际的情况会更复杂,可能不是直接调用,中间会经过另外一些函数中转,这样就更不容易发现问题了。因此,不管是使用Mutex还是Autlolock都要十分小心。

下面看看Mutex类是如何实现的:

代码清单6.1 C++类Mute的实现代码

inline Mutex::Mutex() {
    pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
    pthread_mutex_init(&mMutex, NULL);
}
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);
    }
}
inline Mutex::~Mutex() {
    pthread_mutex_destroy(&mMutex);
}
inline status_t Mutex::lock() {
    return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
    pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
    return -pthread_mutex_trylock(&mMutex);
}

从上面的代码不难看出。Mutex类的实现只是对Linux的“pthreadmutex”系列函数进行了简单的封装而已。Linux的线程系列函数已经很完善了,没有太多需要补充的地方,只是使用稍微繁琐一点。

6.2.2 解决线程同步——条件类Condition
条件类Condition用来解决类似“生产者-消费者”类型的线程同步问题。“生产者”生产产品前先使用Mutex上锁,“消费者”则等待,“生产者”结束后,唤醒“消费者”消费产品。这类问题在多线程编程中很常见。

条件类Condition的接口如下:

class Condition {
public:
    enum { PRIVATE = 0, SHARED = 1 };
    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);

    void broadcast();
};

条件类需要配合Mutex来使用。Condition的构造函数和Mutex类似,也可以使用参数“SHARED”,这种情况主要用于进程间线程的同步。

Condition的wait()函数有两个,不带时间参数的函数表示无限等待;带有时间参数的wait()函数,时间超时wait()函数就会返回,不会一直等待。如果wait等待的mutex的锁释放了,所有在该mutex上等待的wait()都将返回。在mutex解锁前,还有一种方法来终止等待,那就是调用signal()函数。

signal()函数也有两个,不带参数的siganl()调用只会唤醒一个等待的线程;带参数的singal()调用可以通过参数WAKE_UP_ONE只唤醒一个等待的线程,也可通过参数WAKE_UP_ALL唤醒所有等待的线程。

broadcast()函数用来唤醒所有等待的线程。

下面是Condition类的实现代码:

代码清单6.2 C++类Condition的实现代码

inline Condition::Condition() {
    pthread_cond_init(&mCond, NULL);
}
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);
    }
}
inline Condition::~Condition() {
    pthread_cond_destroy(&mCond);
}
inline status_t Condition::wait(Mutex& mutex) {
    return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
inline void Condition::signal() {
    pthread_cond_signal(&mCond);
}
inline void Condition::broadcast() {
    pthread_cond_broadcast(&mCond);
}

和Mutex类类似,Condition类的实现也只是对Linux的“pthreadcond”系列函数进行了简单的封装。

上一篇:《Android平板电脑开发秘籍》——3.3节技巧:理解ActionBar组件


下一篇:saltstack state模块-状态管理