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类,这样用起来更为方便,而且要做扩展也比较容易。
近期评论