Android应用开发android 中c/c++层用到的同步机制有哪些?
白羽 2019-04-15 来源 :网络 阅读 413 评论 0

摘要:本文将带你了解Android应用开发android 中c/c++层用到的同步机制有哪些?,希望本文对大家学Android有所帮助。

    本文将带你了解Android应用开发android 中c/c++层用到的同步机制有哪些?,希望本文对大家学Android有所帮助。


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



    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频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程