[TOC]

概述

Android C++中的线程同步主要就是对pthread的mutex和condition的封装。

Mutex

Android Mutex的实现源码位于/system/core/libutils/include/utils/Mutex.h,我们先来看一下Mutex类的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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();

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:
pthread_mutex_t mMutex;
};

从头文件中,我们发现Mutex类private变量mMutex是我们熟悉的phread_mutex_t类型,pthread_mutex_lock和pthread_mutex_unlock函数通过通过此变量保证一系列操作的原子性。

接下来,我们看一下Mutex类构造函数、析构函数、lock、unlock和tryLock的具体实现(在看源码之前,我们应该能猜到你们就是对pthread _mutex_xxx函数的简单封装):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
inline Mutex::Mutex() {
// 构造函数,初始化mMutex变量
pthread_mutex_init(&mMutex, nullptr);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, nullptr);
}
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, nullptr);
}
}
inline Mutex::~Mutex() {
// 析构函数,就是销毁mMutex变量
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);
}
#if defined(__ANDROID__)
inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
timeoutNs += systemTime(SYSTEM_TIME_REALTIME);
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

我们在Android源码中大量的看到类似于:

1
AutoMutex _l(gProcessMutex);

这样的写法,并没有看到Mutex::lock()和Mutex::unlock()的显示调用。所以,接下来,我们继续学习AutoMutex基于Mutex类的实现。

AutoMutex

AutoMutex仅仅是typedef的重命名,源码如下:

1
typedef Mutex::Autolock AutoMutex;

而Mutex::Autolock是Mutex类的内部类,实现源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class SCOPED_CAPABILITY Autolock {
public:
// Autolock嵌套 Mutex
inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex) { mLock.lock(); }
inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() RELEASE() { mLock.unlock(); }

private:
Mutex& mLock;
// Cannot be copied or moved - declarations only
Autolock(const Autolock&);
Autolock& operator=(const Autolock&);
};

可以看到,Autolock内部类在构造函数中调用了Mutex类的lock方法,在析构函数中调用了Mutex类的unlock方法。所以当我们在一个函数块中调用AutoMutex的时候:

1
2
3
4
5
6
Mutex gProcessMutex;
void testAutoMutex() {
AutoMutex _l(gProcessMutex);
// 下面是需要同步的代码内容
// ...
}

我们定义了一个AutoMutex的变量_l,并把Mutex类型的变量gProcessMutex赋值给_l进行构造函数初始化,自然也实现了调用gProcessMutex的lock方法,实现了线程锁机制。

当函数执行完毕后,AutoMutex的析构函数被调用,从而调用了gProcessMutex的unlock方法,释放了线程锁机制。

其实,AutoMutex的机制有点类似于智能指针,都是很好的运用了类的构造函数和析构函数进行一些特定的操作。