Android 中的同步机制。

       什么是同步,什么是互斥?

       如果多个(包括两个)进程间存在时序关系,需要协同工作以完成一项任务,就叫同步。

       如果他们之间并不满足协同的条件,而只是因为共享具有排他性的资源时所产生的关系,就叫互斥。

       C/C++层用到的同步机制。

一,Mutex

进程间的同步Mutex,Mutual Exclusion的缩写,翻译为互斥体。是对pthread提供的api的封装,Pthread作为操作系统的线程,所以导入了# include <pthread.h>,也可以直接使用pthread的api,比如:

 

下面看下Mutex的源码,这是android7.1中的源码。

从这个枚举定义看出,mutex可以处理进程内同步的情况,也可以处理进程间同步的情况。下面有一个使用SHARED的地方(1),用于处理在应用跟多媒体进程间的一块共享内存区域。

Mutex中包含了一个AutoLock嵌套类,利用了对象生命周期的特点,创建对象时在构造函数中调用lock方法,析构函数时调用unlock方法。Android很多地方是用的这个autolock,方便,避免了使用Mutex可能出现的lock和unlock的不成对的问题。

内部类Autolock,使用AutoLock,先声明一个Mutex对象,并且AutoLock的对象通常是一个局部变量。

       注意,它的拷贝构造函数,拷贝赋值运算符都是private的,在外部是不能用的,这说明mutex对象是不能复制的。

          

函数的实现:

构造函数只贴出了默认构造函数,带有type类型的构造函数。

如果指定了type是SHARED,在调用Mutex的构造函数时,会调用pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);来设置这个互斥体的PTHREAD_PROCESS_SHARED属性,

 

(2)使用AutoLock的例子

       …

 

二,Condition 条件判断

核心思想是判断“条件是否已经满足”,满足的话就马上返回,继续执行未完成的动作;否则就进入休眠等待,直到条件满足时有人唤醒它。

 

这种情况,用mutex也是可以实现的。比如两个线程A、B共享一个全局变量temp,他们的行为如下。

Thread A:不断去修改这个变量temp,改完后的值未知;

ThreadB:当这个变量temp为0时,需要做些操作。

显然,A、B都要访问这个共享资源temp,这属于mutex的问题范畴。但是具体的细节有差异:线程A的需求,只是获得temp的访问权;而线程B的情况,其真正等待的条件是temp等于0。

       如果用mutex来完成,线程B只能通过不断的读取temp的值来判断条件是否满足,代码类似:

  

相对于线程A只是访问temp不同的是,对线程B来说,什么时间满足条件temp==0是未知的,所以总是循环的访问temp显然是浪费cpu时间的。

更好的方式,是线程B不需要总是循环访问temp,检查是否满足条件,而是在条件满足时主动通知到线程B。

Condition就是这样一个思路。Condition条件变量类,它的实现是依赖系统的。

条件变量是跟mutex互斥体配对的,在wait方法中就带有mutex变量,既然都有condition这一互斥方法了,为什么还要牵扯到Mutex呢?原因是condition并不是一个完整的互斥体,比如condition中并没有看到跟条件相关的变量或操作,也就是说condition并不理会具体的“条件”是什么样的,因为用户所设定的“条件”形式,在不同的情况下,可能不同。Condition提供的是一种通用的解决方案,而不是针对具体的“条件样式”,在具体的对condition的应用中,会填充“具体条件”。那么这个具体条件就是那个共享资源,而对这个共享资源的访问是需要一个互斥锁的保护的,所以在wait中才有mutex。

所有调用wait的线程,必须使用给定条件上相同的mutex。

 

Condition的源码,也是调用了pthread的api方法。

 

三,Barrier 栅栏、障碍

Barrier是对condition的一个应用,是填充了“具体条件”的condition,这里的“具体条件”是state == CLOSED或者OPENED 。

 

Barrier的源码:

由condition的定义可以知道,condition.wait()的实现:pthread_cond_wait (&mCond,&mutex.mMutex); pthread_cond_wait的逻辑语义是:

先释放mutex,然后休眠等待,最后唤醒后在获取mutex锁。也就是经历了先释放,在获取锁的过程,为什么是这样呢?由于wait即将进入休眠等待,加入它不先释放mutex锁,那么open()/close()就不能访问条件变量state,这会让程序陷入互相等待的死锁状态,所以它要先释放锁,在进入睡眠,之后因为open()操作完会释放锁,wait也有机会再次获得mutex锁。

       而且这里的open()/close()/wait()在函数结尾都会自动释放mutex锁,因为他是一个autolock变量。