1)认识Mutex,Autolock
Mutex其实是对linux 线程互斥锁做了一层封装,由下面的类定义中可以发现pthread_mutex_t mMutex,这一点充分说明这一点。而在Mutex之上又做了一层封装,就出现了自动锁。自动锁在面向对象编程时,更能有效的释放锁,防止程序猿忘了释放锁,导致花时间调试。
class Mutex {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
status_t lock();
void unlock();
// lock if possible; returns 0 on success, error otherwise
status_t tryLock();
// Manages the mutex automatically. It'll be locked when Autolock is
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); } //自动锁就是就是在构造函数中调用lock,析构函数中调用unlock,没什么大不了的。
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
private:
friend class Condition; //友元是Condition,
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
#if defined(HAVE_PTHREADS)
pthread_mutex_t mMutex;
#else
void _init();
void* mState;
#endif
};
上面可以看到Mutex类中定义的方法和linux 标注API基本保持一致,例如我们来看看Mutex构造函数,确实只是在外面又套了一层。^_^
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
我们重点关注的是LOCK和UNLOCK过程
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和UNLOCK的过程一定要成对出现。既然是对linux标准api的封装,linux互斥锁的介绍我们可以参考
博文,里面介绍的很详细。
2)mutex实例
针对博文里面的例子,我把android源码中的Mutex类拿出来了,可以在地址中下载到源码。
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#define status_t int //这里由于在mutex类中有status_t类型,所以这里就加了个宏定义。
#define HAVE_PTHREADS 1
#include "Mutex.h"
pid_t gettid()
{
return syscall(SYS_gettid);
}
Mutex s_mutex;
void *print_msg(void *arg){
int i=0;
s_mutex.lock();
for(i=0;i<5;i++){
printf("Thread:%d->output : %d\n",gettid(),i);
sleep(1);
}
s_mutex.unlock();
}
int main(int argc,char** argv){
pthread_t id1;
pthread_t id2;
pthread_create(&id1,NULL,print_msg,NULL);
pthread_create(&id2,NULL,print_msg,NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 1;
}
打印log1(有锁保护的):打印结果看,只要线程拿到了这个资源的锁,就对当前资源独有控制权,其它线程不能访问该资源了。log中看,当前线程打印的结果是连续的
public@SH-NB-0022:/shared/test$ g++ mutex.cpp -o thread -lpthread //编译命令
public@SH-NB-0022:/shared/test$ ./thread
Thread:2393->output : 0
Thread:2393->output : 1
Thread:2393->output : 2
Thread:2393->output : 3
Thread:2393->output : 4
Thread:2394->output : 0
Thread:2394->output : 1
Thread:2394->output : 2
Thread:2394->output : 3
Thread:2394->output : 4
打印log2(无锁保护的):将s_mutex.logck(),s_mutex.unlock()去掉的话,就会出现两个线程能同时访问共享资源的情况。这样是很危险的。在没有锁保护的情况下,线程1,线程2共享资源,线程1前一时刻拿到的数据,后一秒就会被线程2修改,导致异常的发生。所以在进行共享资源访问的时候,一定要加锁保护,防止意外事故发生。
public@SH-NB-0022:/shared/test$ g++ mutex.cpp -o thread -lpthread //编译命令
public@SH-NB-0022:/shared/test$ ./thread
Thread:2760->output : 0
Thread:2761->output : 0
Thread:2760->output : 1
Thread:2761->output : 1
Thread:2761->output : 2
Thread:2760->output : 2
Thread:2761->output : 3
Thread:2760->output : 3
Thread:2761->output : 4
Thread:2760->output : 4
3)autolock实例
自动锁更加简单,只需要在访问共享资源入口出加一个自动锁就行了,如下代码所示。打印结果和上面的log1是一样的。
Mutex s_mutex;
void *print_msg(void *arg){
int i=0;
Mutex::Autolock autoLock(s_mutex);
for(i=0;i<5;i++){
printf("Thread:%d->output : %d\n",gettid(),i);
sleep(1);
}
}
总结:Mutex还是相当简单的,用好了Mutex会让程序更安全稳定。如果单纯只是使用的话,你可以不去研究android mutex类(其实也没多少东西),会用就行了。我一般都习惯性的把类拿出来,在PC机上验证一下。总之就是在互斥资源的入口和出口分别加上lock()和unlock(),就行了。