2 condition & mutex

目录

1、概述

2、Mutex

3、Condition

 

1 概述

互斥量和条件变量在开发多线程应用中经常用到。

Linux提供了pthread_mutex_t pthread_cond_t及对应的操作使得用户可以方便的使用这两种机制(不了解的可以去百度下)。

Mutex和Condition是android代码中对pthread_mutex_t和pthread_cond_t 的封装,可以认为功能是一样的,只是调用方式上有些差别

当然Mutex和Condition具有更好的可操作性

 

2 Mutex

2.1 例子

这里通过一个小的例子,介绍如何利用Mutex方法进行互斥操作

//for mutex test        
public:    
    Mutex mLock;    
    int exit_flag;    
    int read_exit;    
    int write_exit;    
  
    int mutex_test_start();    
    int mutex_test_stop();    
    static int thread_read(void *);    
    static int thread_write(void *);


这里介绍下头文件中定义的相关的变量。exit_flag表示是否退出测试,read_exit表示读取线程成功退出标记  write_exit表示写线程成功退出标志

定义了两个线程函数thread_read thread_write,一个Mutex变量mLock,在线程代码中循环获取mLock,执行某些操作,最后退出

其中mutex_test_start和mutex_test_stop控制测试的开始和结束,下面看下实现

int dtPlayer::mutex_test_start(){    
  exit_flag=0;    
  read_exit=0;    
  write_exit=0;    
  createThread(thread_read,this);      
  createThread(thread_write,this);     
  printf("--thread start ok\n");     
  return 0;    
}

启动线程,并初始化变量

int dtPlayer::mutex_test_stop(){    
  exit_flag=1;    
LOOP:    
  if(read_exit&&write_exit)    
    return 0;    
  sleep(1);    
  goto LOOP;    
}

判断是否都成功退出

int dtPlayer::thread_read(void *user){    
  dtPlayer *player=(dtPlayer *)user;    
  while(player->exit_flag==0)    
  {    
    player->mLock.lock();    
    printf("thread read is running \n");    
    sleep(2);    
    player->mLock.unlock();    
    sleep(1);    
  }    
  printf("--read thread exit ok\n");    
  player->read_exit=1;    
  return 0;    
  
}

读线程,首先通过lock获取锁,获取成功后打印消息"thread read is running" 然后解锁,sleep 1s后重新去获取锁

int dtPlayer::thread_write(void * user){    
  dtPlayer *player=(dtPlayer *)user;    
  while(player->exit_flag==0)    
  {    
    player->mLock.lock();    
    printf("thread write is running \n");    
    sleep(2);    
    player->mLock.unlock();    
    sleep(1);    
  }    
  printf("--write thread exit ok\n");    
  player->write_exit=1;    
  return 0;    
}

写线程与读线程类似,这里主要是为了模拟两个线程竞争同一把锁的情况,以及对Mutex的使用有个直观的认识

extern "C" int dt_mutex_test()    
{    
    ALOGE("--mutex test before \n");    
    dtPlayer *player=new dtPlayer();    
    player->mutex_test_start();    
    sleep(20);    
    player->mutex_test_stop();    
    ALOGE("--mutex test end \n");    
    return 0;    
}

最后是入口函数

2.2 Mutex类介绍

通过上面例子,可以了解Mutex的使用非常简单即如下序列:

Mutex mMux;    
mMux.lock();    
**user ops**    
mMux.unlock();

下面介绍Mutex的定义等

源文件在framework/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_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);   
    }   
}

这里给出了三种构造函数,之前介绍过,Mutex仅仅是对pthread_mutex_t及其操作的封装,因此构造函数是初始化的封装

inline status_t Mutex::lock() {   
    return -pthread_mutex_lock(&mMutex);   
}   
inline void Mutex::unlock() {   
    pthread_mutex_unlock(&mMutex);   
}   
inline status_t Mutex::tryLock() {   
    return -pthread_mutex_trylock(&mMutex);   
}

同理,lock等也比较简单

inline Mutex::~Mutex() {   
    pthread_mutex_destroy(&mMutex);   
}

析构函数

下面介绍Mutex中一个比较方便的扩展:

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

Autolock封装了Mutex相关的操作,其优点在于会在Autolock生命周期到期调用析构函数的时候会调用相应Mutex的unlock方法,这样用户就不用时刻惦记着unlock了

在使用的时候,是要配合一个已经存在的Mutex变量来使用,举例如下

Mutex mutex;    
int dtPlayer::test()    
{    
    Mutex::Autilock lock(mutex);    
    ***user ops***    
    return 0;    
}

使用非常方便。最主要的优点是不用惦记unlock

【说明】例子可从附件获得

3 Condition

3.1 例子

//for condition test  
public:  
    Condition mCondition;  
    Mutex mMuxCon;  
    int resource_count;  
    int inc_exit;  
    int dec_exit;  
    int condition_test_start();  
    int condition_test_stop();  
    static int thread_inc(void *);  
    static int thread_dec(void *);

这里同样主体是两个线程,thread_inc thread_dec,resource_count是资源数量,当数量==0时,thread_dec会进入等待,等待thread_inc增加资源数量

看下实现

int dtPlayer::condition_test_start()  
{  
        resource_count=0;  
        inc_exit=0;  
        dec_exit=0;  
        createThread(thread_dec,this);   
        createThread(thread_inc,this);    
        printf("--thread start ok\n");   
        return 0;  
}  
  
int dtPlayer::condition_test_stop()  
{  
LOOP:  
  if(inc_exit&&dec_exit)  
    return 0;  
  sleep(1);  
  goto LOOP;  
    return 0;  
}


初始化和结束实现,比较简单

int dtPlayer::thread_dec(void *user)  
{  
      dtPlayer *player=(dtPlayer *)user;  
      player->mMuxCon.lock();  
      while(player->resource_count==0)  
      {  
            printf("start wait  \n");    
            player->mCondition.wait(player->mMuxCon);  
      }  
      player->resource_count--;  
      printf("decremen resource count  \n");    
      player->mMuxCon.unlock();  
      player->dec_exit=1;  
      return 0;  
}

资源递减线程,首先获取互斥锁,然后判断资源数量,如果资源数量==0,则调用wait方法,wait参数是互斥锁,如果了解pthread_cond_t操作可以知道,wait会释放互斥锁

然后等待条件变量被激活,当被激活时会重新锁住,然后继续执行。也就是说这里wait会释放player->mMuxCon互斥锁

int dtPlayer::thread_inc(void *user)  
{  
      dtPlayer *player=(dtPlayer *)user;  
      player->mMuxCon.lock();  
      if(player->resource_count==0)  
      {  
            printf("increment resource count  \n");    
            player->mCondition.signal();  
      }  
      player->resource_count++;  
      player->mMuxCon.unlock();  
      player->inc_exit=1;  
      return 0;  
}

资源递增线程同样也是先获取锁,然后判断资源数量,如果发现count==0,则发送信号,此时可能有资源消耗线程等待,同时调用player->resource_count++; 增加资源

这里可以得出结论wait会释放锁,因为如果不释放则当数量==0时,thread_inc将无法得到锁

extern "C" int dt_condition_test()  
{  
    ALOGE("--condition test before \n");  
    dtPlayer *player=new dtPlayer();  
    player->condition_test_start();  
    player->condition_test_stop();  
    ALOGE("--condition test end \n");  
    return 0;  
}

最后是测试入口

【说明】例子在附件中

3.2 Condition类介绍

下面介绍下Condition类

源文件:framework/native/include/utils/Condition.h

Condition();  
    Condition(int type);  
    ~Condition();  
    // Wait on the condition variable.  Lock the mutex before calling.  
    status_t wait(Mutex& mutex);  
    // same with relative timeout  
    status_t waitRelative(Mutex& mutex, nsecs_t reltime);  
    // Signal the condition variable, allowing one thread to continue.  
    void signal();  
    // Signal the condition variable, allowing all threads to continue.  
    void broadcast();  
  
private:  
#if defined(HAVE_PTHREADS)  
    pthread_cond_t mCond;  
#else
    void*   mState;  
#endif

 重要的方法及成员,都是围绕mCond也就是pthread_cond_t展开,看下具体实现

inline Condition::Condition() {  
    pthread_cond_init(&mCond, NULL);  
}  
inline Condition::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 Condition::~Condition() {  
    pthread_cond_destroy(&mCond);  
}

构造函数==初始化

inline status_t Condition::wait(Mutex& mutex) { 
    return -pthread_cond_wait(&mCond, &mutex.mMutex); 
}

wait函数

inline void Condition::signal() { 
    pthread_cond_signal(&mCond); 
} 
inline void Condition::broadcast() { 
    pthread_cond_broadcast(&mCond); 
}

唤醒函数,signal和broadcast的区别是signal只唤醒一个线程,而boradcast将唤醒所有线程

【结束】

你可能感兴趣的:(2 condition & mutex)