首页 > CLucene, 程序人生 > CLucene源码剖析(三) 实现跨平台的线程安全

CLucene源码剖析(三) 实现跨平台的线程安全

在多线程编程中,程序的线程安全(thread-safe)是十分重要的,要做到这一点,一方面要在程序设计的过程中,尽可能设计多的单线程访问的数据结构,一方面就是合理的使用锁(Mutex)。在CLucene中,实现了如下跨平台的锁相关的宏:
(1) _LUCENE_SLEEP(x) 挂起当前线程 x微秒
(2) _LUCENE_THREADMUTEX 线程锁(mutex)
(3) _LUCENE_CURRTHREADID 获取当前线程的thread ID
(4) _LUCENE_THREADID_TYPE thread ID的类型定义
通过上面几个宏,就可以实现基本的线程安全的相关操作。下面对上述宏的具体实现进行一一详细说明:
1.在windows平台下:
(1) _LUCENE_SLEEP(x)由系统API Sleep()实现

1
#define _LUCENE_SLEEP(x) Sleep(x)

(2) _LUCENE_THREADMUTEX由CRITICAL_SECTION相关的内容实现

1
#define _LUCENE_THREADMUTEX CL_NS(util)::mutex_win32

(3) _LUCENE_CURRTHREADID由系统API GetCurrentThreadId()实现

1
#define _LUCEN colla="E_CURRTHREADID GetCurrentThreadId()

(4) _LUCENE_THREADID_TYPE类型为 DWORD类型

1
#define _LUCENE_THREADID_TYPE DWORD

2.在unix平台下:
(1) _LUCENE_SLEEP(x)由系统函数 usleep()实现

1
#define _LUCENE_SLEEP(x) usleep(x*1000)

(2) _LUCENE_THREADMUTEX由pthread_mutex_t相关的内容实现

1
#define _LUCENE_THREADMUTEX CL_NS(util)::mutex_pthread

(3) _LUCENE_CURRTHREADID由pthread中的pthread_self()的实现

1
#define _LUCENE_CURRTHREADID pthread_self()

(4) _LUCENE_THREADID_TYPE类型为pthread_t类型

1
#define _LUCENE_THREADID_TYPE pthread_t

从上面的讲解过程中,我们可以看出_LUCENE_THREADMUTEX的实现,还是有一层包装的,在windows下是mutex_win32,在unix下是mutex_pthread,所以要想深入理解,还需要更加深入一步。
下面是mutex_win32的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class mutex_win32
{
private:
	CRITICAL_SECTION mtx;
public:
	mutex_win32(const mutex_win32& clone);
	mutex_win32();
	~mutex_win32();
	void lock();
	void unlock();
};
mutex_win32::mutex_win32(const mutex_win32& clone){
	InitializeCriticalSection(&mtx); 
}
mutex_win32::mutex_win32()
{ 
	InitializeCriticalSection(&mtx); 
}
 
mutex_win32::~mutex_win32()
{ 
	DeleteCriticalSection(&mtx); 
}
 
void mutex_win32::lock()
{ 
	EnterCriticalSection(&mtx); 
}
 
void mutex_win32::unlock()
{ 
	LeaveCriticalSection(&mtx); 
}

下面是mutex_pthread的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class mutex_pthread
{
private:
	pthread_mutex_t mtx;
 
public:
	mutex_pthread(const mutex_pthread& clone);
	mutex_pthread();
	~mutex_pthread();
	void lock();
	void unlock();
 
private:
	#ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
	pthread_t lockOwner;
	unsigned int lockCount;
	#endif
};
#ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
	bool mutex_pthread_attr_initd=false;
	pthread_mutexattr_t mutex_pthread_attr;
#endif
 
#ifdef _CL__CND_DEBUG
	#define _CLPTHREAD_CHECK(c,m) CND_PRECONDITION(c==0,m)
#else
	#define _CLPTHREAD_CHECK(c,m) c;
#endif
 
mutex_pthread::mutex_pthread(const mutex_pthread& clone){
	#ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
	_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, &mutex_pthread_attr), "mutex_pthread(clone) constructor failed")
	#else
  	#if defined(__hpux) && defined(_DECTHREADS_)
		_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, pthread_mutexattr_default), "mutex_pthread(clone) constructor failed")
	#else
		_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, 0), "mutex_pthread(clone) constructor failed")
	#endif
	lockCount=0;
	lockOwner=0;
	#endif
}
mutex_pthread::mutex_pthread()
{ 
	#ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
  	if ( mutex_pthread_attr_initd == false ){
  		pthread_mutexattr_init(&mutex_pthread_attr);
	  	pthread_mutexattr_settype(&mutex_pthread_attr, PTHREAD_MUTEX_RECURSIVE);
	  	mutex_pthread_attr_initd = true;
	}
	_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, &mutex_pthread_attr), "mutex_pthread(clone) constructor failed")
	#else
  	#if defined(__hpux) && defined(_DECTHREADS_)
		_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, pthread_mutexattr_default), "mutex_pthread(clone) constructor failed")
	#else
		_CLPTHREAD_CHECK(pthread_mutex_init(&mtx, 0), "mutex_pthread(clone) constructor failed")
	#endif
	lockCount=0;
	lockOwner=0;
	#endif
}
 
mutex_pthread::~mutex_pthread()
{ 
	_CLPTHREAD_CHECK(pthread_mutex_destroy(&mtx), "~mutex_pthread destructor failed") 
}
 
void mutex_pthread::lock()
{ 
	#ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
	pthread_t currentThread = pthread_self();
	if( pthread_equal( lockOwner, currentThread ) ) {
		++lockCount;
	} else {
		_CLPTHREAD_CHECK(pthread_mutex_lock(&mtx), "mutex_pthread::lock")
		lockOwner = currentThread;
		lockCount = 1;
	}
	#else
	_CLPTHREAD_CHECK(pthread_mutex_lock(&mtx), "mutex_pthread::lock")
	#endif
}
 
void mutex_pthread::unlock()
{ 
	#ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE
	--lockCount;
	if( lockCount == 0 )
	{
		lockOwner = 0;
		_CLPTHREAD_CHECK(pthread_mutex_unlock(&mtx), "mutex_pthread::unlock")
	}
	#else
	_CLPTHREAD_CHECK(pthread_mutex_unlock(&mtx), "mutex_pthread::unlock")
	#endif
}

由上面的实现可以看出,mutex_win32直接就是对CRITICAL_SECTION相关的操作进行了封装,而mutex_pthread是对pthread_mutex_t相关操作的封装。其实在这里,我不知道作者为什么要采用这种宏的方式,我觉得完全可以能过封装一个通用的Thread类和Mutex类,这样用起来更为方便,而且要做扩展也比较容易。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.
您必须在 登录 后才能发布评论.