频道栏目
首页 > 资讯 > Android > 正文

android 中c/c++层用到的同步机制有哪些?

17-09-26        来源:[db:作者]  
收藏   我要投稿

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变量。

相关TAG标签
上一篇:android布局技巧_ 如何将布局添加到this所在的自定义的布局中
下一篇:Myeclipse修改文件的默认打开方式教程
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站