2 condition & mutex

来源:互联网 发布:淘宝联盟导出excel 编辑:程序博客网 时间:2024/06/10 02:35

目录

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将唤醒所有线程

【结束】

原创粉丝点击