对mutex进行RAII封装

    在编写多线程程序的时候,经常用到加锁的操作,特别是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

上面的代码也要几个技巧(和陷阱):

    1.  explicit 在构造函数之前,为了防止隐式转换(只用于有且只有一个参数情况):class A{A(int n);};    f(A a); ==> f(2) ,2 被隐式转换成了A的对象。

    2. 赋值构造函数和operator=都被声明为private, 禁止copy

    3. 因为禁止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;
}

你可能感兴趣的:(mutex,C\C++)