当前位置:操作系统 > 安卓/Android >>

Android进程线程之同步互斥(一)

1.1.1 Android中的同步与互斥
Android系统也提供了自己的同步互斥机制,不过任何技术的本质都是类似的,更多的是把这些本质的东西应用到符合自己要求的场景。目前Android封装的同步互斥类包括:

·          Mutex

头文件在frameworks/native/include/utils/Mutex.h,因为实现与具体的平台有关,我们只关心如何使用它

·          Condition

头文件在frameworks/native/include/utils/Condition.h,同样我们只是应用它

·          Barrier

frameworks/native/services/su易做图ceflinger/Barrier.h

这是基于Mutex和Condition实现的一个模型,目前只被用于Su易做图ceFlinger中,我们在后续的章节会碰到

1.1.1.1 Mutex
Mutex类中有一个enum定义,如下:

class Mutex {

public:

    enum {

        PRIVATE = 0,

        SHARED = 1

    };

如果是SHARED的话,说明它是适用于跨进程共享的。比如AudioTrack与AudioFlinger就驻留在两个不同的进程,所以它们的mutex就是这种类型的:

/*frameworks/av/media/libmedia/AudioTrack.cpp*/

audio_track_cblk_t::audio_track_cblk_t()

    : lock(Mutex::SHARED), cv(Condition::SHARED), user(0),server(0),

    userBase(0),serverBase(0), buffers(NULL), frameCount(0),

    loopStart(UINT_MAX),loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),

    mSendLevel(0), flags(0)

{

}

Mutex类中有三个重要的成员函数:

    status_t    lock(); //获取资源锁

    void       unlock();//释放资源锁

status_t    tryLock(); /*如果当前资源可用就lock,否则也直接返回,返回值0代表成功。可见它和lock()

                的区别在于不论成功与否都会及时返回,而不是等待*/

它的构造函数有三个:

/*frameworks/native/include/utils/Mutex.h*/

inline Mutex::Mutex() {

   pthread_mutex_init(&mMutex, NULL);

}

inline Mutex::Mutex(const char* name) {

   pthread_mutex_init(&mMutex, NULL);

}

inline Mutex::Mutex(int type, const char* name) {

    if (type == SHARED) {

        pthread_mutexattr_tattr;

       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);

    }

}

可见Mutex实际上也是基于pthread的封装。

1.1.1.2 Condition
Condition表达的意思是“条件”,换句话说,它的核心是“条件是否满足”——满足的话执行某操作,不满足的话则进入等待,直到条件满足有人唤醒它。

有人可能会问,这种情况用Mutex能实现吗?从理论上讲,的确是可以。举个例子来说,假设两个线程A和B共享一个全局变量vari,它们的行为如下:

Thread A: 不断去修改vari,每次改变后的值未知

Thread B: 当vari为0时,它需要做某些动作

也就是说,线程A是想获得vari的访问权,而线程B等待的是vari==0的情况。那么如果用Mutex去完成的话,线程B就只能通过不断地读取vari来判断条件是否满足,有点类似于下面的伪代码:

while(1)

{

     acquire_mutex_lock();//获取对vari的Mutex锁

    if(0 == vari) //条件满足

    {

       release_mutex_lock();//释放锁

       break;

    }

    else

    {

       release_mutex_lock();//释放锁

       sleep();//休眠一段时间

    }

}

那么对于线程B而言,它什么时候达到条件(vari==0)是未知的,这点和其它共享vari的线程(比如线程A)有很大不同,因而采用轮询的方式显然极大的浪费了CPU时间。

再举一个生活中的例子,加深大家的理解。比如有一个公共厕所,假设同时只能供一个人使用。现在想使用这一资源的有两类人:其一当然是正常使用厕所的人;其二就是更换厕纸的人员。如果我们把他们一视同仁的话会发生什么情况呢?那就是工作人员也要排队。等排到他时,他进去看下厕所纸是否用完,有的话就更换,否则就什么也不做直接退出,然后继续排队等待,如此循环往复。换句话说,这位工作人员的效率是相当低的,因为他的时间都浪费在排队上了。

所以我们需要寻找另一种模型来解决这一特殊的场景。解决方法之一就是工作人员不需要排队,而是由其他人通知他厕所缺纸的事件。这样子既减少了排队人员的数量,同时提高了工作人员的效率,一举两得。

Condition就是针对这些场景提出的解决方案。

class Condition {

public:

    enum { //和Mutex一样,它支持跨进程共享

        PRIVATE = 0,

        SHARED = 1

    };

                …

    status_t  wait(Mutex& mutex); //在某个条件上等待

    status_t  waitRelative(Mutex& mutex, nsecs_treltime); //也是在某个条件上等待,增加了超时退出功能

    void signal(); //条件满足时通知相应等待者

    void broadcast(); //条件满足时通知所有等待者

private:

#if defined(HAVE_PTHREADS)

    pthread_cond_t mCond;

#else

    void*   mState;

#endif

};

从Condition提供的几个接口函数中,我们有如下疑问:

·          既然wait()是在等待“条件满足”,那么是什么样的条件呢?

在整个Condition类的描述中,我们都看不到与条件相关的变量或者操作。这是因为,Condition实际上是一个“半成品”,它并不提供具体的“条件”——理由很简单,在不同情况下,用户所需的“条件”形式都是不一样的,Condition想要提供一种“通用的解决方法”,而不是针对某些具体的“条件样式”去设计。比如我们可以说“满足条件”就是某变量A为True,或者是变量A达到值100, 或者是变量A等于B,等等。这是Condition所无法预料的,因而它能做的,就是提供一个“黑盒”,而不管盒子里的是什么

·          为什么需要mutex?

相信大家都注意到了,wait和waitRelative接口都带有一个Mutex&mutex变量,这是很多人感到不解的地方——既然都有Condition这一互斥方法了,为什么还要牵扯一个Mutex呢?

 

由于Condition本身的不完整性,如果直接从理论分析的话估计不好理解,所以我们希望结合下一小节的Barrier来给大家解答上述两个问题。

1.1.1.3 Barrier
Condition表示“条件”,而Barrier表示“栅栏、障碍”。后者是对前者的一个应用,换句话说,Barrier是填充了“具体条件”的Condition,这给我们理解Condition提供了一个很好的实例。

Barrier是定义在Su易做图ceFlinger这一块的,并不是像Condition一样作为常用Utility提供给整个Android系统使用。不过这不影响我们对它的分析。

/*frameworks/native/services/su易做图ceflinger/Barrier.h*/

class Barrier

{

public:

    inline Barrier() :state(CLOSED) { }

    inline ~Barrier() { }

    void open() {

        Mutex::Autolock_l(lock);

        state = OPENED;

        cv.

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,