RAII手法封装相互排斥锁

Posted claireyuancy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RAII手法封装相互排斥锁相关的知识,希望对你有一定的参考价值。

CriticalSectionWrapper是一个接口类

class CriticalSectionWrapper {
 public:
  // Factory method, constructor disabled
  static CriticalSectionWrapper* CreateCriticalSection();

  virtual ~CriticalSectionWrapper() {}

  // Tries to grab lock, beginning of a critical section. Will wait for the
  // lock to become available if the grab failed.
  virtual void Enter() = 0;

  // Returns a grabbed lock, end of critical section.
  virtual void Leave() = 0;
};


返回父类的静态指针,方便于其它模块直接调用,接口父类是为了多态性,由于这儿支持跨平台

CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() {
#ifdef _WIN32
  return new CriticalSectionWindows();
#else
  return new CriticalSectionPosix();
#endif
}



// RAII extension of the critical section. Prevents Enter/Leave mismatches and
// provides more compact critical section syntax.
class CriticalSectionScoped 
{
public:
	explicit CriticalSectionScoped(CriticalSectionWrapper* critsec): ptr_crit_sec_(critsec) 
	{
    		ptr_crit_sec_->Enter();
  	}

  	~CriticalSectionScoped() 
	{
    		if (ptr_crit_sec_)
		{
      			Leave();
    		}
  	}

private:
  	void Leave() 
	{
    		ptr_crit_sec_->Leave();
    		ptr_crit_sec_ = NULL;
  	}

 	CriticalSectionWrapper* ptr_crit_sec_;
};


CriticalSectionPosix类继承CriticalSectionWrapper类,实现了全部的方法

class CriticalSectionPosix : public CriticalSectionWrapper 
{
public:
	CriticalSectionPosix();
  	virtual ~CriticalSectionPosix();
	
  	virtual void Enter() OVERRIDE;
  	virtual void Leave() OVERRIDE;

private:
  	pthread_mutex_t mutex_;
};


CriticalSectionPosix类的实现

CriticalSectionPosix::CriticalSectionPosix()
{
 	pthread_mutexattr_t attr;
  	(void) pthread_mutexattr_init(&attr);
  	(void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  	(void) pthread_mutex_init(&mutex_, &attr);
}

CriticalSectionPosix::~CriticalSectionPosix() 
{
 	(void) pthread_mutex_destroy(&mutex_);
}

void CriticalSectionPosix::Enter() 
{
  	(void) pthread_mutex_lock(&mutex_);
}

void CriticalSectionPosix::Leave() 
{
  	(void) pthread_mutex_unlock(&mutex_);
}

CriticalSectionWrapper* acm_crit_sect_ = CriticalSectionWrapper::CreateCriticalSection();


当对临界数据进行操作时,创建CriticalSectionScoped的对象。參数调用CriticalSectionWrapper的工厂方法

  {

  CriticalSectionScoped lock(acm_crit_sect_);

}

离开作用域后自己主动释放锁。不用再去解锁,避免了非常多异常情况。这是一种RAII编程,Resource acquisition is initialization,直译为“资源获取就是初始化”

这儿锁的资源须要去释放,这由含有acm_crit_sect_成员的类的析构函数去释放。

避免内存泄露


谈下几个接口:

线程和线程的同步对象(相互排斥量,读写锁,条件变量)都具有属性。在改动属性前都须要对该结构进行初始化。

使用后要把该结构回收。我们用pthread_ mutexattr_init函数对pthread_mutexattr结构进行初始化,用pthread_mutexattr_destroy函数对该结构进行回收。

 

名称::

pthread_mutexattr_init/pthread_mutexattr_destroy

功能:

初始化/回收pthread_mutexattr_t结构

头文件:

#include <pthread.h>

函数原形:

int pthread_mutexattrattr_init(pthread_mutexattr_t *attr);

int pthread_mutexattrattr_destroy( pthread_mutexattr_t *attr );

參数:

attr    pthread_mutexattr_t结构变量

返回值:

若成功返回0,若失败返回错误编号。

      

 

 

      






 pthread_mutexattr_init将属性对象的值初始化为缺省值。并分配属性对象占用的内存空间。

attr中pshared属性表示用这个属性对象创建的相互排斥锁的作用域。它的取值能够是PTHREAD_PROCESS_PRIVATE(缺省值。表示由这个属性对象创建的相互排斥锁仅仅能在进程内使用)或PTHREAD_PROCESS_SHARED。

 

相互排斥量属性分为共享相互排斥量属性和类型相互排斥量属性。

两种属性分别由不同的函数得到并由不同的函数进行改动。pthread_mutexattr_getpshared和pthread_mutexattr_setpshared函数能够获得和改动共享相互排斥量属性。pthread_mutexattr_gettype和pthread_mutexattr_settype函数能够获得和改动类型相互排斥量属性。以下我们分别介绍。

 

名称::

pthread_mutexattr_getpshared/pthread_mutexattr_setpshared

功能:

获得/改动共享相互排斥量属性

头文件:

#include <pthread.h>

函数原形:

int pthread_mutexattrattr_ getpshared ( const pthread_attr_t *restrict attr,int*restrict pshared);

int pthread_mutexattrattr_ setpshared (  const pthread_attr_t *restrict attr,int pshared);

參数:

 

返回值:

若成功返回0,若失败返回错误编号。

 

 

 

 

 

 





共享相互排斥量属性用于规定相互排斥锁的作用域。相互排斥锁的域能够是进程内的也能够是进程间的。pthread_mutexattrattr_ getpshared能够返回属性对象的相互排斥锁作用域属性。能够是下面值:PTHREAD_PROCESS_SHARED。PTHREAD_PROCESS_PRIVATE。假设相互排斥锁属性对象的pshared属性被置PTHREAD_PROCESS_SHARED。

那么由这个属性对象创建的相互排斥锁将被保存在共享内存中,能够被多个进程中的线程共享。假设pshared属性被置为PTHREAD_PROCESS_PRIVATE,那么仅仅有和创建这个相互排斥锁的线程在同一个进程中的线程才干訪问这个相互排斥锁。

 

名称::

pthread_mutexattr_gettype/pthread_mutexattr_settype

功能:

获得/改动类型相互排斥量属性

头文件:

#include <pthread.h>

函数原形:

int pthread_mutexattrattr_ getpshared ( const pthread_attr_t *restrict attr,int*restrict pshared);

int pthread_mutexattrattr_ setpshared (  const pthread_attr_t *restrict attr,int pshared);

參数:

 

返回值:

若成功返回0,若失败返回错误编号。

 

 

 

 

 

 

 

 

 

 

 

pthread_mutexattr_gettype函数能够获得相互排斥锁类型属性。

缺省的相互排斥锁类型属性是PTHREAD_MUTEX_DEFAULT。

合法的类型属性值有:

PTHREAD_MUTEX_NORMAL;

PTHREAD_MUTEX_ERRORCHECK;

PTHREAD_MUTEX_RECURSIVE

PTHREAD_MUTEX_DEFAULT。

类型说明:

PTHREAD_MUTEX_NORMAL

这样的类型的相互排斥锁不会自己主动检測死锁。假设一个线程试图对一个相互排斥锁反复锁定,将会引起这个线程的死锁。假设试图解锁一个由别的线程锁定的相互排斥锁会引发不可预料的结果。假设一个线程试图解锁已经被解锁的相互排斥锁也会引发不可预料的结果。

 

PTHREAD_MUTEX_ERRORCHECK

这样的类型的相互排斥锁会自己主动检測死锁。

假设一个线程试图对一个相互排斥锁反复锁定。将会返回一个错误代码。假设试图解锁一个由别的线程锁定的相互排斥锁将会返回一个错误代码。假设一个线程试图解锁已经被解锁的相互排斥锁也将会返回一个错误代码。

 

PTHREAD_MUTEX_RECURSIVE

假设一个线程对这样的类型的相互排斥锁反复上锁,不会引起死锁。一个线程对这类相互排斥锁的多次反复上锁必须由这个线程来反复同样数量的解锁,这样才干解开这个相互排斥锁。别的线程才干得到这个相互排斥锁。

假设试图解锁一个由别的线程锁定的相互排斥锁将会返回一个错误代码。

假设一个线程试图解锁已经被解锁的相互排斥锁也将会返回一个错误代码。

这样的类型的相互排斥锁仅仅能是进程私有的(作用域属性为PTHREAD_PROCESS_PRIVATE)。

 

PTHREAD_MUTEX_DEFAULT

这样的类型的相互排斥锁不会自己主动检測死锁。假设一个线程试图对一个相互排斥锁反复锁定。将会引起不可预料的结果。假设试图解锁一个由别的线程锁定的相互排斥锁会引发不可预料的结果。假设一个线程试图解锁已经被解锁的相互排斥锁也会引发不可预料的结果。POSIX标准规定,对于某一详细的实现。能够把这样的类型的相互排斥锁定义为其它类型的相互排斥锁。


以上是关于RAII手法封装相互排斥锁的主要内容,如果未能解决你的问题,请参考以下文章

C++基于RAII对锁进行封装

Linux多线程同步之相互排斥量和条件变量

POSIX 线程具体解释(3-相互排斥量:"固定加锁层次"/“试加锁-回退”)

C++基于RAII对锁进行封装

Linux 同步方法剖析--内核原子,自旋锁和相互排斥锁

C++封装互斥锁和基于RAII机制能自动解锁的互斥锁