面向对象锁框架的设计与实现
本文描述了一种简单的跨平台锁框架的设计与实现,该框架小巧实用、易于扩展,它的特点如下:
● 实现了线程间互斥锁
● 实现优化了单线程环境中的空锁和空级别锁
● 支持编译时或运行时选择锁
● 支持对象和类级别的锁粒度
● 支持错误或异常处理
框架结构
由锁抽象、锁适配器、锁守卫、线程互斥锁和锁级别5个基本组件构成,对应类的关系如下图。
基本组件
锁抽象
提供锁语义的抽象,一般有5种操作:创建或初始化、阻塞加锁、非阻塞加锁、解锁和销毁,实现为lock_base类。
构造对应创建或初始化操作,析构对应销毁操作,lock对应阻塞加锁,trylock对应非阻塞加锁,unlock对应解锁。
锁适配器
支持运行时动态绑定某个具体锁,实现为lock_adapter类模板,继承lock_base。
提供2个构造函数,支持引用外部锁和构造内部锁,并将方法实现委托给对应的锁实例。
线程互斥锁
一种支持线程间同步的具体锁,支持windows和linux平台,实现为thread_mutex类。
lock、trylock和unlock返回0表示成;-1表示失败,errno指示错误码; 当仅用于单线程环境时,加解锁没有意义,提供一个空锁,实现为null_mutex类。
锁守卫
用于自动获取和释放锁,保证当异常发生时能自动解锁,实现为lock_guard类模板,T表示锁类型,只要这个类型提供lock、trylock和unlock三种语义。
构造函数形参block为true表示阻塞加锁,否则非阻塞加锁。当T为null_mutex时,为了避免调用lock和unlock的开销,特化如下。
锁级别
提供类级别和对象级别2种锁粒度:类级别是指所有对象共享同一个锁,实现为class_level_lock类模板;对象级别是指每个对象持有自己的锁, 实现为object_level_lock类模板。
level_lock_base是为遵循DRY SPOT原则而衍生的基类,使用CRTP模式,T是继承它的级别子类类型;它避免了每个子类都要编写lock、trylock和unlock的冗余,并使用const T定义了锁守卫类型别名,这是为了支持子类的const方法。class_level_lock和object_level_lock中的T是宿主类类型,L是锁类型,当L为null_mutex时,为避免调用lock(或trylock)和unlock的开销,提供了一个空级别,实现为null_level_lock类模板,继承level_lock_base,并且必须要以它特化锁守卫,这样在实际使用时就不会引起"lock_不是null_level_lock<T,L>的成员"编译错误。
应用示例
编译时选择锁类型与级别
stl_sequence是以stl中的vector、list和deque三种序列容器为基础进行共性抽象的包装容器,为了使它灵活支持各种锁与级别,就需要将锁和级别定义为模板参数,并提供一个默认的类型。
从上可见,增加、删除、修改和查找操作都是通过首先调用lock_guard_type guard(*this)仅一行代码来支持线程同步,下面来看看它的使用。
● 使用空级别锁:seq1和seq2都没有锁,即使seq2使用了thread_mutex。
● 使用对象级别锁:seq3和seq4具有各自的锁。
● 使用类级别锁:seq5和seq6共享同一个锁。
● 使用空锁:seq7、seq8和seq9都没有锁,但seq7效率稍高。
综上可知,在单线程环境中,使用空级别空锁就够了;而在多线程环境中,可依据需求灵活选择对象级别或类级别锁。
运行时绑定具体锁
● 实现了线程间互斥锁
● 实现优化了单线程环境中的空锁和空级别锁
● 支持编译时或运行时选择锁
● 支持对象和类级别的锁粒度
● 支持错误或异常处理
框架结构
由锁抽象、锁适配器、锁守卫、线程互斥锁和锁级别5个基本组件构成,对应类的关系如下图。

锁抽象
提供锁语义的抽象,一般有5种操作:创建或初始化、阻塞加锁、非阻塞加锁、解锁和销毁,实现为lock_base类。
1
class lock_base
2
{
3
public:
4
lock_base(){}
5
virtual ~lock_base(){}
6
7
virtual int lock() = 0;
8
virtual int trylock() = 0;
9
virtual int unlock() = 0;
10
};
class lock_base2
{3
public:4
lock_base(){}5
virtual ~lock_base(){}6
7
virtual int lock() = 0;8
virtual int trylock() = 0;9
virtual int unlock() = 0;10
};锁适配器
支持运行时动态绑定某个具体锁,实现为lock_adapter类模板,继承lock_base。
1 template<class T>
2 class lock_adapter : public lock_base
3
{
4
public:
5
lock_adapter(T &lock)
6
:lock_(&lock)
7
,del_(false)
8
{}
9
10
lock_adapter()
11
:del_(true)
12
{ lock_ = new T(); }
13
14
~lock_adapter()
15
{ if(del_) delete lock_; }
16
17
virtual int lock()
18
{ return lock_->lock(); }
19
20
virtual int trylock()
21
{ return lock_->trylock(); }
22
23
virtual int unlock()
24
{ return lock->unlock(); }
25
26
private:
27
T *lock_;
28
bool del_;
29
};
2 class lock_adapter : public lock_base
3
{4
public:5
lock_adapter(T &lock)6
:lock_(&lock)7
,del_(false)8
{}9
10
lock_adapter()11
:del_(true)12
{ lock_ = new T(); }13
14
~lock_adapter()15
{ if(del_) delete lock_; }16
17
virtual int lock()18
{ return lock_->lock(); }19
20
virtual int trylock()21
{ return lock_->trylock(); }22
23
virtual int unlock()24
{ return lock->unlock(); }25
26
private:27
T *lock_;28
bool del_;29
};线程互斥锁
一种支持线程间同步的具体锁,支持windows和linux平台,实现为thread_mutex类。
1
thread_mutex::thread_mutex()
2
{
3
#ifdef _WIN32
4
//because use SEH
to handle API exception, so instead of using one free function to initialize the critical section
5
init_critical_section(&m_);
6
#else
7
int ret;
8
if(ret=pthread_mutex_init(&m_,NULL))
9
throw lock_error("pthread_mutex_init",ret);
10
#endif
11
}
12![]()
13
thread_mutex::~thread_mutex()
14
{
15
#ifdef _WIN32
16
DeleteCriticalSection(&m_);
17
#else
18
pthread_mutex_destroy(&m_);
19
#endif
20
}
21![]()
22
int thread_mutex::lock()
23
{
24
#ifdef _WIN32
25
EnterCriticalSection(&m_);
26
return 0;
27
#else
28
int ret;
29
if(ret=pthread_mutex_lock(&m_)){
30
errno = ret;
31
return -1;
32
}
33
return 0;
34
#endif
35
}
36![]()
37
int thread_mutex::trylock()
38
{
39
#ifdef _WIN32
40
#if (defined _WIN32_WINNT) && _WIN32_WINNT >= 0x0400
41
if(!TryEnterCriticalSection(&m_)){
42
errno = EBUSY;
43
return -1;
44
}
45
return 0;
46
#endif
47
errno = ENOSYS;
48
return -1;
49
#else
50
int ret;
51
if(ret=pthread_mutex_trylock(&m_)){
52
errno = ret;
53
return -1;
54
}
55
return 0;
56
#endif
57
}
58![]()
59
int thread_mutex::unlock()
60
{
61
#ifdef _WIN32
62
LeaveCriticalSection(&m_);
63
return 0;
64
#else
65
int ret;
66
if(ret = pthread_mutex_unlock(&m_)){
67
errno = ret;
68
return -1;
69
}
70
return 0;
71
#endif
72
}
thread_mutex::thread_mutex()2
{3
#ifdef _WIN324
//because use SEH
to handle API exception, so instead of using one free function to initialize the critical section 5
init_critical_section(&m_); 6
#else7
int ret;8
if(ret=pthread_mutex_init(&m_,NULL))9
throw lock_error("pthread_mutex_init",ret);10
#endif11
}12

13
thread_mutex::~thread_mutex()14
{15
#ifdef _WIN3216
DeleteCriticalSection(&m_);17
#else18
pthread_mutex_destroy(&m_);19
#endif20
}21

22
int thread_mutex::lock() 23
{ 24
#ifdef _WIN3225
EnterCriticalSection(&m_);26
return 0;27
#else28
int ret;29
if(ret=pthread_mutex_lock(&m_)){30
errno = ret;31
return -1;32
}33
return 0;34
#endif35
}36

37
int thread_mutex::trylock() 38
{ 39
#ifdef _WIN3240
#if (defined _WIN32_WINNT) && _WIN32_WINNT >= 0x040041
if(!TryEnterCriticalSection(&m_)){42
errno = EBUSY;43
return -1;44
}45
return 0;46
#endif 47
errno = ENOSYS;48
return -1;49
#else50
int ret;51
if(ret=pthread_mutex_trylock(&m_)){52
errno = ret;53
return -1;54
}55
return 0;56
#endif57
}58

59
int thread_mutex::unlock()60
{ 61
#ifdef _WIN3262
LeaveCriticalSection(&m_); 63
return 0;64
#else65
int ret;66
if(ret = pthread_mutex_unlock(&m_)){67
errno = ret;68
return -1;69
}70
return 0; 71
#endif72
}1
class null_mutex
2
{
3
public:
4
int lock() { return 0;}
5
int trylock() { return 0;}
6
int unlock() { return 0; }
7
};
class null_mutex2
{3
public:4
int lock() { return 0;}5
int trylock() { return 0;}6
int unlock() { return 0; }7
};锁守卫
用于自动获取和释放锁,保证当异常发生时能自动解锁,实现为lock_guard类模板,T表示锁类型,只要这个类型提供lock、trylock和unlock三种语义。
1
template<class T>
2 class lock_guard : noncopyable
3
{
4
public:
5
explicit lock_guard(T &lock, bool block=true)
6
: lock_(&lock)
7
{
8
owner_ = (block ? lock_->lock() : lock_->trylock());
9
}
10
11
~lock_guard()
12
{
13
if(0==owner_) lock_->unlock();
14
}
15
16
int locked() const
17
{ return owner_; }
18
19
private:
20
T *lock_;
21
int owner_;
22
};
template<class T>2 class lock_guard : noncopyable
3
{4
public:5
explicit lock_guard(T &lock, bool block=true)6
: lock_(&lock)7
{8
owner_ = (block ? lock_->lock() : lock_->trylock());9
}10
11
~lock_guard()12
{13
if(0==owner_) lock_->unlock();14
}15
16
int locked() const17
{ return owner_; }18
19
private:20
T *lock_;21
int owner_; 22
};1
template<>
2
class lock_guard<null_mutex>
3
{
4
public:
5
explicit lock_guard(null_mutex&){}
6
~lock_guard() {}
7
};
template<>2
class lock_guard<null_mutex>3
{4
public:5
explicit lock_guard(null_mutex&){}6
~lock_guard() {}7
};锁级别
提供类级别和对象级别2种锁粒度:类级别是指所有对象共享同一个锁,实现为class_level_lock类模板;对象级别是指每个对象持有自己的锁, 实现为object_level_lock类模板。
1
template<class T>
2
class level_lock_base : noncopyable
3
{
4
public:
5
typedef lock_guard<const T> lock_guard_type;
6
7
int lock() const
8
{ return static_cast<const T*>(this)->lock_.lock(); }
9
10
int trylock() const
11
{ return static_cast<const T*>(this)->lock_.trylock();}
12
13
int unlock() const
14
{ return static_cast<const T*>(this)->lock_.unlock(); }
15
16
protected:
17
~level_lock_base(){}
18
};
19
20 template<class T,class L>
21 class class_level_lock : public level_lock_base<class_level_lock<T,L> >
22
{
23
template<class U>
24
friend class level_lock_base;
25
26
protected:
27
~class_level_lock(){}
28
29
private:
30
static L lock_;
31
};
32
33 template<class T,class L>
34 L class_level_lock<T,L>::lock_;
35
36 template<class T,class L>
37 class object_level_lock : public level_lock_base<object_level_lock<T,L> >
38
{
39
template<class U>
40
friend class level_lock_base;
41
42
protected:
43
~object_level_lock(){}
44
45
private:
46
mutable L lock_;
47
};
template<class T>2
class level_lock_base : noncopyable3
{4
public:5
typedef lock_guard<const T> lock_guard_type;6
7
int lock() const8
{ return static_cast<const T*>(this)->lock_.lock(); }9
10
int trylock() const11
{ return static_cast<const T*>(this)->lock_.trylock();}12
13
int unlock() const14
{ return static_cast<const T*>(this)->lock_.unlock(); }15
16
protected:17
~level_lock_base(){}18
};19
20 template<class T,class L>
21 class class_level_lock : public level_lock_base<class_level_lock<T,L> >
22
{23
template<class U> 24
friend class level_lock_base;25
26
protected:27
~class_level_lock(){}28
29
private:30
static L lock_; 31
};32
33 template<class T,class L>
34 L class_level_lock<T,L>::lock_;
35
36 template<class T,class L>
37 class object_level_lock : public level_lock_base<object_level_lock<T,L> >
38
{39
template<class U> 40
friend class level_lock_base;41
42
protected:43
~object_level_lock(){}44
45
private:46
mutable L lock_; 47
}; 1 template<class T,class L>
2 class null_level_lock : public level_lock_base<null_level_lock<T,L> >
3
{
4
protected:
5
~null_level_lock(){}
6
};
7
8 template<class T,class L>
9 class lock_guard<const null_level_lock<T,L> >
10
{
11
public:
12
explicit lock_guard(const null_level_lock<T,L>&){}
13
~lock_guard(){}
14
};
2 class null_level_lock : public level_lock_base<null_level_lock<T,L> >
3
{4
protected:5
~null_level_lock(){}6
};7
8 template<class T,class L>
9 class lock_guard<const null_level_lock<T,L> >
10
{11
public:12
explicit lock_guard(const null_level_lock<T,L>&){}13
~lock_guard(){}14
};应用示例
编译时选择锁类型与级别
stl_sequence是以stl中的vector、list和deque三种序列容器为基础进行共性抽象的包装容器,为了使它灵活支持各种锁与级别,就需要将锁和级别定义为模板参数,并提供一个默认的类型。
1
template<typename T,
2
class L = null_mutex, //lock type
3
template<class T,class L> class E = null_level_lock, //lock level
4
template<class T,class U> class C = std::vector,
5
template <class T> class U = std::allocator
6
>
7
class stl_sequence : private E<stl_sequence<T,L,E,C,U>,L>
8
{
9
typedef U<T> Allocator;
10
typedef C<T,Allocator> cont_type;
11
typedef stl_sequence<T,L,E,C,U> self_type;
12
typedef E<self_type,L> base_type;
13
typedef typename base_type::lock_guard_type lock_guard_type;
14
15
public:
16
![]()
17
void add(const T &t,bool append = true)
18
{
19
lock_guard_type guard(*this);
20
//do add thing
21
}
22![]()
23
void insert(size_t idx,const T &t)
24
{
25
lock_guard_type guard(*this);
26
//do insert thing
27
}
28![]()
29
void erase(size_t idx)
30
{
31
lock_guard_type guard(*this);
32
//do erase thing
33
}
34![]()
35
T* get(size_t idx)
36
{
37
lock_guard_type guard(*this);
38
//do get thing
39
}
40
![]()
41
};
template<typename T,2
class L = null_mutex, //lock type3
template<class T,class L> class E = null_level_lock, //lock level4
template<class T,class U> class C = std::vector,5
template <class T> class U = std::allocator6
>7
class stl_sequence : private E<stl_sequence<T,L,E,C,U>,L>8
{9
typedef U<T> Allocator;10
typedef C<T,Allocator> cont_type;11
typedef stl_sequence<T,L,E,C,U> self_type;12
typedef E<self_type,L> base_type;13
typedef typename base_type::lock_guard_type lock_guard_type;14
15
public:16

17
void add(const T &t,bool append = true)18
{19
lock_guard_type guard(*this);20
//do add thing21
}22

23
void insert(size_t idx,const T &t)24
{25
lock_guard_type guard(*this);26
//do insert thing27
}28

29
void erase(size_t idx)30
{31
lock_guard_type guard(*this);32
//do erase thing33
}34

35
T* get(size_t idx) 36
{37
lock_guard_type guard(*this);38
//do get thing39
}40

41
};● 使用空级别锁:seq1和seq2都没有锁,即使seq2使用了thread_mutex。
1
stl_sequence<int> seq1;
2
stl_sequence<int,thread_mutex> seq2;
stl_sequence<int> seq1;2
stl_sequence<int,thread_mutex> seq2;1
stl_sequence<int,thread_mutex,object_level_lock> seq3, seq4;
stl_sequence<int,thread_mutex,object_level_lock> seq3, seq4;1
stl_sequence<int,thread_mutex,class_level_lock> seq5, seq6;
stl_sequence<int,thread_mutex,class_level_lock> seq5, seq6;1
stl_sequence<int,null_mutex> seq7;
2
stl_sequence<int,null_mutex,class_level_lock> seq8;
3
stl_sequence<int,null_mutex,object_level_lock> seq9;
stl_sequence<int,null_mutex> seq7;2
stl_sequence<int,null_mutex,class_level_lock> seq8;3
stl_sequence<int,null_mutex,object_level_lock> seq9;运行时绑定具体锁
1 lock_base *lb;
2 if(argc>1 && 0==strcmp(argv[1],"thread_mutex"))
3 lb = new lock_adapter<thread_mutex>(*(new thread_mutex));
4 else
5 lb = new lock_adapter<null_mutex> (*(new null_mutex));
6
auto_ptr<lock_base> ap(lb);
7
lock_guard<lock_base> guard(*lb);
8
//do some thing
2 if(argc>1 && 0==strcmp(argv[1],"thread_mutex"))
3 lb = new lock_adapter<thread_mutex>(*(new thread_mutex));
4 else
5 lb = new lock_adapter<null_mutex> (*(new null_mutex));
6
auto_ptr<lock_base> ap(lb);7
lock_guard<lock_base> guard(*lb); 8
//do some thing


auto_ptr<lock_base> ap(lb);
浙公网安备 33010602011771号