在编写多线程程序的时候,经常用到加锁的操作,特别是mutex,必不可少。。为了方便编程和不要忘记解锁,对mutex进行了RAII封装!
RAII可以说是C++的一大利器,至少我是这么觉得的!
/**************************************************
* 该类主要是对mutex进行了RAII封装,以后还会封装condition,
* 目的当然是为了便于编程使用啊
* 用法:
* MutexLock mutex;//定义一个mutex
*
* void foo(){
...
* MutexGuard lock(mutex);
* ...
* do something...
* ...
* }
* lock 只在它的作用域内有效
**************************************************/
#ifndef LOCK_H_
#define LOCK_H_
#include <pthread.h>
/************************************************
* mutex api的简单封装
*************************************************/
class MutexLock{
public:
MutexLock(){
pthread_mutex_init(&mutex_, NULL);
}
~MutexLock(){
pthread_mutex_destroy(&mutex_);
}
void Lock(){
pthread_mutex_lock(&mutex_);
}
void UnLock(){
pthread_mutex_unlock(&mutex_);
}
private:
pthread_mutex_t mutex_;
private:
//禁止copy
MutexLock(const MutexLock &);
MutexLock &operator=(const MutexLock &);
};
/************************************************
* 只是简单的对mutex做RAII封装
* use:
* void foo(){
* MutexGuard lock(mutex);
* ...
* do something...
* ...
* }
*************************************************/
class MutexGuard{
public:
//explicit 防止隐式转换
explicit MutexGuard(MutexLock &mutex):mutex_(mutex){//引用只能用
//mutex_ = mutex;
mutex_.Lock();
}
~MutexGuard(){
mutex_.UnLock();
}
private:
MutexLock &mutex_;//由于mutexLock不允许拷贝,所以用引用
private:
//禁止copy
MutexGuard(const MutexGuard &);
MutexGuard &operator=(const MutexGuard &);
};
// 见陈硕的muduo网络库实现
#define MutexGuard(x) do{\
fprintf(stderr, "Error:line:%d, function:%s(), file:%s\nthis should be used like this:\nMutexGuard lock(your_mutex);\n",\
__LINE__, __FUNCTION__, __FILE__);\
}while(0);
#endif
上面的代码也要几个技巧(和陷阱):
explicit 在构造函数之前,为了防止隐式转换(只用于有且只有一个参数情况):class A{A(int n);}; f(A a); ==> f(2) ,2 被隐式转换成了A的对象。
赋值构造函数和operator=都被声明为private, 禁止copy
因为禁止copy,那么下MutexGuard类中,之类有一个MutexLock 的引用成员mutex_,并且只能在构造函数的初始化列表中初始化(和常量const一样)
见我的上一篇博客http://my.oschina.net/chengshuguang/blog/210666恶补C++基础之成员变量初始化赋值
上面的代码进行了一个简单的封装,用起来也非常的方便,只需要加上如下:
MutexGuard lock(mutex);//只在作用域内有效,超出作用域自动解锁
下面是一个经典多线程测试程序,多线程从100打印到1:
开了4个线程测的,大家也可以调节usleep()参数,和cnt的初始值来更好的验证多线程处理效果
#include <stdio.h>
#include "lock.h"
#include <pthread.h>
#include <unistd.h>
using namespace std;
MutexLock mutex;
int cnt = 100;
void *f(void *arg){
int t_num = (int)arg;
while(true){
MutexGuard lock(mutex);
if(cnt>0){
usleep(1);
printf("%d: %d\n", t_num, cnt--);
}else{
break;
}
}
return NULL;
}
int main(){
pthread_t tid;
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
int ret = pthread_create(&tid, NULL, f,(void*)1);
if(ret == -1){
perror("create error\n");
}
ret = pthread_create(&tid1, NULL, f, (void*)2);
if(ret == -1){
perror("create error\n");
}
ret = pthread_create(&tid2, NULL, f, (void*)3);
if(ret == -1){
perror("create error\n");
}
ret = pthread_create(&tid3, NULL, f, (void*)4);
if(ret == -1){
perror("create error\n");
}
pthread_join(tid, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
return 0;
}