面向对象锁框架的设计与实现
本文描述了一种简单的跨平台锁框架的设计与实现,该框架小巧实用、易于扩展,它的特点如下:
● 实现了线程间互斥锁
● 实现优化了单线程环境中的空锁和空级别锁
● 支持编译时或运行时选择锁
● 支持对象和类级别的锁粒度
● 支持错误或异常处理
框架结构
由锁抽象、锁适配器、锁守卫、线程互斥锁和锁级别5个基本组件构成,对应类的关系如下图。
锁抽象
提供锁语义的抽象,一般有5种操作:创建或初始化、阻塞加锁、非阻塞加锁、解锁和销毁,实现为lock_base类。
1
class
lock_base
2 {
3public:
4 lock_base(){}
5 virtual ~lock_base(){}
6
7 virtual int lock() = 0;
8 virtual int trylock() = 0;
9 virtual int unlock() = 0;
10} ;
2 {
3public:
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 {
4public:
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
26private:
27 T *lock_;
28 bool del_;
29} ;
2 class lock_adapter : public lock_base
3 {
4public:
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
26private:
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}
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}
1
class
null_mutex
2 {
3public:
4 int lock() { return 0;}
5 int trylock() { return 0;}
6 int unlock() { return 0; }
7} ;
2 {
3public:
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 {
4public:
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
19private:
20 T *lock_;
21 int owner_;
22} ;
2 class lock_guard : noncopyable
3 {
4public:
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
19private:
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 } ;
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 {
4public:
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
16protected:
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
26protected:
27 ~class_level_lock(){}
28
29private:
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
42protected:
43 ~object_level_lock(){}
44
45private:
46 mutable L lock_;
47} ;
2 class level_lock_base : noncopyable
3 {
4public:
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
16protected:
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
26protected:
27 ~class_level_lock(){}
28
29private:
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
42protected:
43 ~object_level_lock(){}
44
45private:
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 {
4protected:
5 ~null_level_lock(){}
6} ;
7
8 template < class T, class L >
9 class lock_guard < const null_level_lock < T,L > >
10 {
11public:
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 {
4protected:
5 ~null_level_lock(){}
6} ;
7
8 template < class T, class L >
9 class lock_guard < const null_level_lock < T,L > >
10 {
11public:
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
15public:
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} ;
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
15public:
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} ;
● 使用空级别锁:seq1和seq2都没有锁,即使seq2使用了thread_mutex。
1
stl_sequence
<
int
>
seq1;
2 stl_sequence < int ,thread_mutex > seq2;
2 stl_sequence < int ,thread_mutex > seq2;
1
stl_sequence
<
int
,thread_mutex,object_level_lock
>
seq3, seq4;
1
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;
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