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

    xiaoxiao2024-02-20  132

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

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

    6.2.1 互斥体Mutex和自动锁AutolockMutex和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”系列函数进行了简单的封装。

    最新回复(0)