摘要:本文将带你了解Android应用开发android 中c/c++层用到的同步机制有哪些?,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发android 中c/c++层用到的同步机制有哪些?,希望本文对大家学Android有所帮助。
android 中c/c++层用到的同步机制有哪些?Android 中的同步机制。
什么是同步,什么是互斥?
如果多个(包括两个)进程间存在时序关系,需要协同工作以完成一项任务,就叫同步。
如果他们之间并不满足协同的条件,而只是因为共享具有排他性的资源时所产生的关系,就叫互斥。
C/C++层用到的同步机制。
一,Mutex
进程间的同步Mutex,Mutual Exclusion的缩写,翻译为互斥体。是对pthread提供的api的封装,Pthread作为操作系统的线程,所以导入了# include ,也可以直接使用pthread的api,比如:
pthread_mutex_t mMutex;
pthread_mutex_lock(&mMutex);
pthread_mutex_unlock(&mMutex);
下面看下Mutex的源码,这是android7.1中的源码。
System/core/include/utils/Mutex.h
class Mutex {
从这个枚举定义看出,mutex可以处理进程内同步的情况,也可以处理进程间同步的情况。下面有一个使用SHARED的地方(1),用于处理在应用跟多媒体进程间的一块共享内存区域。
enum {
PRIVATE =0,
SHARED = 1
};
Mutex中包含了一个AutoLock嵌套类,利用了对象生命周期的特点,创建对象时在构造函数中调用lock方法,析构函数时调用unlock方法。Android很多地方是用的这个autolock,方便,避免了使用Mutex可能出现的lock和unlock的不成对的问题。
内部类Autolock,使用AutoLock,先声明一个Mutex对象,并且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;
};
status_tlock();
voidunlock();
status_t tryLock();
status_t timedLock(nsecs_t timeoutNs);//android环境下特有的函数。
Mutex提供的构造函数:
Mutex();
Mutex(constchar* name);
Mutex(inttype, const char* name = NULL);
注意,它的拷贝构造函数,拷贝赋值运算符都是private的,在外部是不能用的,这说明mutex对象是不能复制的。
Private:
Mutex(constMutex&);
Mutex& operator = (const Mutex&);
pthread_mutex_tmMutex;
}
函数的实现:
构造函数只贴出了默认构造函数,带有type类型的构造函数。
inlineMutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inlineMutex::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);
}
}
inlineMutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
//获取资源锁,如果此时资源可用,函数马上返回,否则就会进入阻塞等待,直到有人释放了资源并唤醒它。
inlinestatus_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inlinevoid Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
//trylock只是尝试去获取资源锁是否可用,如果可用就成功返回(返回值0),但是如果不可用,也立即返回,不会进入等待,只是返回值不为0。
inlinestatus_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
//这个宏定义说明,只有android环境下才有timedLock函数,pthread中没有pthread_mutex_timedlock这个api,所以它只在android下可用,同样是去获取一个资源锁,但是超过timeoutNs就放弃了,返回TIMED_OUT表示失败,否则这个时间内获取到就返回0,表示成功。
#ifdefined(__ANDROID__)
inlinestatus_t Mutex::timedLock(nsecs_t timeoutNs) {
timeoutNs +=systemTime(SYSTEM_TIME_REALTIME);
const struct timespec ts = {
/* .tv_sec = */static_cast(timeoutNs / 1000000000),
/* .tv_nsec = */static_cast(timeoutNs % 1000000000),
};
return -pthread_mutex_timedlock(&mMutex,&ts);
}
#endif
(1)这是一个跨进程互斥锁的例子。
AudioEffectShared.h
// Sharedmemory area used to exchange parameters between application and mediaserver process.
struct effect_param_cblk_t{
Mutex lock;
effect_param_cblk_t()::lock(Mutex::SHARED){}
}
如果指定了type是SHARED,在调用Mutex的构造函数时,会调用pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);来设置这个互斥体的PTHREAD_PROCESS_SHARED属性,
(2)使用AutoLock的例子
AudioFlinger.h
Mutex mLock;
AudioFlinger.cpp
…
{ 互斥锁有效的代码段
Mutex::Autolock _l(mLock); //_l是一个局部变量。
对互斥资源的操作
}
…
二,Condition 条件判断
核心思想是判断“条件是否已经满足”,满足的话就马上返回,继续执行未完成的动作;否则就进入休眠等待,直到条件满足时有人唤醒它。
这种情况,用mutex也是可以实现的。比如两个线程A、B共享一个全局变量temp,他们的行为如下。
Thread A:不断去修改这个变量temp,改完后的值未知;
ThreadB:当这个变量temp为0时,需要做些操作。
显然,A、B都要访问这个共享资源temp,这属于mutex的问题范畴。但是具体的细节有差异:线程A的需求,只是获得temp的访问权;而线程B的情况,其真正等待的条件是temp等于0。
如果用mutex来完成,线程B只能通过不断的读取temp的值来判断条件是否满足,代码类似:
While(1){
Acquire_mutex_lock(temp);//获取锁,
If(0== temp){ //条件满足,释放锁,做特定操作,然后退出。
Release_mutex_lock(temp);
Break;
}else{//条件不满足,释放锁,睡眠一段时间
Release_mutex_lock(temp);
Sleep();
}
}
相对于线程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方法。
Condition.h
class Condition{
public:
enum {//也支持跨进程共享
PRIVATE = 0,
SHARED = 1
};
//唤醒时,可以指定唤醒一个,也可以唤醒所有等待在这个条件的线程。
enum WakeUpType {
WAKE_UP_ONE = 0,
WAKE_UP_ALL = 1
};
}
inlineCondition::Condition() {
pthread_cond_init(&mCond, NULL);
}
inlineCondition::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 status_tCondition::wait(Mutex& mutex) {
return -pthread_cond_wait(&mCond,&mutex.mMutex);
}
//有等待超时的wait。
inline status_t Condition::waitRelative(Mutex& mutex,nsecs_t reltime) {
structtimespec ts;
ts.tv_sec = reltime/1000000000;
ts.tv_nsec= reltime%1000000000;
return-pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
}
//只唤醒一个线程,当有多个线程等待在这个条件变量上,并不指定唤醒哪一个。
inline void Condition::signal() {
pthread_cond_signal(&mCond);
}
void signal(WakeUpType type) {
if (type == WAKE_UP_ONE) {
signal();
} else {
broadcast();
}
}
//唤醒所有线程。
inlinevoid Condition::broadcast() {
pthread_cond_broadcast(&mCond);
}
三,Barrier 栅栏、障碍
Barrier是对condition的一个应用,是填充了“具体条件”的condition,这里的“具体条件”是state == CLOSED或者OPENED 。
Barrier的源码:
Barrier.h
class Barrier
{
public:
inline Barrier() : state(CLOSED) { }
inline ~Barrier() { }
//释放所有等待在这个barrier上的线程。
void open() {
Mutex::Autolock _l(lock);
state = OPENED;
cv.broadcast();
}
//重置栅栏,wait方法被阻塞,直到open方法被调用。
void close() {
Mutex::Autolock _l(lock);
state = CLOSED;
}
//进入等待,直到barrier是open。首先调用了mutex锁,然后才调用condition对象cv,因为接下来的操作涉及了对互斥资源state的访问,所以要用mutex来保证对这个共享资源的使用。
void wait() const {
Mutex::Autolock _l(lock);
while (state == CLOSED) {
cv.wait(lock);
}
}
private:
enum { OPENED, CLOSED };
mutable Mutex lock;
mutable Condition cv;
volatile int state;
};
由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变量。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号