一种简单的跨平台互斥锁

来源:岁月联盟 编辑:exp 时间:2012-06-25

前言  
   互斥锁,用来保证任一时刻只有单个线程或进程拥有对共享资源的互斥访问权,在这里将posix thread中的互斥体、win32中的互斥体和临界区,统称为互斥锁,其特点如下
   ● 范围:线程锁和进程锁,前者仅用于同一进程内多线程间,而后者用于进程间,显然,它也能用于同一进程内多线程间,但效率较低。posix的互斥体既可以是线程锁,也可以是进程锁,这由它的一个属性决定:pthread_process_shared或pthread_process_private。win32中的临界区是一种线程锁,而互斥体既可以是线程锁,也可以是进程锁,这由它的一个名称决定:createmutex中的第3个参数。
   ● 类型:posix中的互斥体,包括普通锁、递归锁、检测锁和适应锁四种;而win32中的临界区在同一线程内可多次加锁和解锁,相当于递归锁,而互斥体则相当于普通锁。
   ● 操作:包括创建锁、加锁、解锁、检测锁和销毁锁5种操作,其中加锁操作又可分为永久等待和超时等待2种。对于win32中的临界区,不存在超时等待的加锁。

接口
   所有锁操作,成功返回0,失败posix返回非0的错误码,win32返回-1,调用getlasterror可获取错误码。对于超时加锁,第2个参数超时不是时间差,而是绝对到期时间。对于win32中的互斥体,废弃返回1,超时返回2。
 1 #ifdef __cplusplus
 2  extern "C" {
 3 #endif
 4
 5 #ifdef _POSIX_THREAD
 6 #include <pthread.h>
 7 #include <sys/time.h>
 8
 9 typedef pthread_mutex_t mutex_t;
10 typedef pthread_mutexattr_t mutexattr_t;
11 typedef void SECURITY_ATTRIBUTES;
12
13 #elif defined(_WIN32_THREAD)
14 #ifndef _WIN32_WINNT
15 # define _WIN32_WINNT 0x0501
16 #endif
17 #include <winsock2.h>
18
19 typedef struct 
20  {
21     int type_;
22     union
23      {
24         HANDLE proc_lock_;
25         CRITICAL_SECTION thr_lock_;
26     };
27 }mutex_t;
28 typedef void mutexattr_t;
29
30 #else
31 #error Currently only support win32 and posix thread models
32 #endif
33
34 #define MUTEX_THREAD_SHARED  1
35 #define MUTEX_PROCESS_SHARED 2
36
37 int mutex_init(mutex_t* m,int scope,int type,const char* name,mutexattr_t* attr,SECURITY_ATTRIBUTES* sa);
38
39 int mutex_lock(mutex_t* m);
40
41 int mutex_timedlock(mutex_t* m,const struct timeval* val);
42
43 int mutex_trylock(mutex_t* m);
44
45 int mutex_unlock(mutex_t* m);
46
47 int mutex_destroy(mutex_t* m);
48
49 #ifdef __cplusplus
50 }
51 #endif

实现 
  1 int mutex_init(mutex_t* m,int scope,int type,const char* name,mutexattr_t* attr,SECURITY_ATTRIBUTES* sa)
  2  {
  3 #ifdef _POSIX_THREAD
  4     int ret, init = 0;
  5     pthread_mutexattr_t tmp;
  6     if(0==attr) attr = &tmp;
  7     if(attr==&tmp)
  8      {
  9         ret = pthread_mutexattr_init(attr);
 10         if (0==ret) init = 1;
 11     }
 12     if(0==ret && 0 != scope)
 13      {
 14 #ifdef  _POSIX_THREAD_PROCESS_SHARED
 15         ret = pthread_mutexattr_setpshared(attr,lock_scope);
 16 #endif
 17     }
 18     if(0==ret && 0 != type)
 19      {
 20 #ifdef __USE_UNIX98
 21         ret = pthread_mutexattr_settype(attr,lock_type);
 22 #endif
 23     }
 24     if (0==ret)
 25         ret = pthread_mutex_init(m,attr);
 26     if (1==init && attr==&tmp)
 27         pthread_mutexattr_destroy(attr);
 28     return ret;
 29 #else
 30     m->type_ = scope;
 31     switch (m->type_)
 32      {
 33     case MUTEX_THREAD_SHARED:
 34         __try
 35          {
 36             InitializeCriticalSection(&m->thr_lock_);
 37         }
 38         __except(EXCEPTION_EXECUTE_HANDLER)
 39          {
 40             return -1;
 41         }
 42         return 0;
 43
 44     case MUTEX_PROCESS_SHARED:
 45         m->proc_lock_ = CreateMutexA(sa,FALSE,name);
 46         if (0==m->proc_lock_&&ERROR_ACCESS_DENIED==GetLastError())
 47             m->proc_lock_ = OpenMutexA(MUTEX_ALL_ACCESS,FALSE,name);
 48         if (0==m->proc_lock_)
 49             return -1;       
 50         return 0;
 51
 52     default: return -1;
 53     }
 54 #endif
 55 }
 56
 57 int mutex_lock(mutex_t* m)
 58  {
 59 #ifdef _POSIX_THREAD
 60     return pthread_mutex_lock(m);
 61 #else
 62     switch(m->type_)
 63      {
 64     case MUTEX_THREAD_SHARED:
 65         EnterCriticalSection(&m->thr_lock_);
 66         return 0;
 67    
 68     case MUTEX_PROCESS_SHARED:
 69         switch (WaitForSingleObject (m->proc_lock_, INFINITE))
 70          {
 71         case WAIT_OBJECT_0:  return 0;
 72         case WAIT_ABANDONED: return 1;
 73         default: return -1;
 74         }
 75         break;
 76
 77     default: return -1;
 78     }
 79 #endif
 80 }
 81
 82 int mutex_timedlock(mutex_t* m,const struct timeval* val)
 83  {
 84     //val should be an absolute time.
 85 #ifdef _POSIX_THREAD
 86      struct timespec ts = {.tv_sec = val->tv_sec,.tv_nsec=val->tv_usec*1000};
 87     return pthread_mutex_timedlock(m,&ts);
 88 #else
 89     switch(m->type_)
 90      {
 91     // not support CriticalSection,so simply return -1.
 92     case MUTEX_THREAD_SHARED:
 93         return -1;
 94
 95     case MUTEX_PROCESS_SHARED:
 96          {
 97             FILETIME ft;
 98             struct timeval cur,diff;
 99        
100             GetSystemTimeAsFileTime(&ft);
101             cur = FileTime2TimeVal(&ft);
102             diff = timeval_sub(val,&cur);
103
104             switch (WaitForSingleObject (m->proc_lock_, timeval_millsec(&diff)))
105              {
106             case WAIT_OBJECT_0:  return 0;
107             case WAIT_ABANDONED: return 1;
108             case WAIT_TIMEOUT:      return 2;
109             default: return -1;
110             }
111         }
112         break;
113
114     default: return -1;
115     }
116 #endif
117 }
118
119 int mutex_trylock(mutex_t* m)
120  {
121 #ifdef _POSIX_THREAD
122     return pthread_mutex_trylock(m);
123 #else
124     switch(m->type_)
125      {
126     case MUTEX_THREAD_SHARED:
127         if (!TryEnterCriticalSection(&m->thr_lock_))
128             return -1;
129         return 0;
130        
131     case MUTEX_PROCESS_SHARED:
132         switch (WaitForSingleObject (m->proc_lock_, 0))
133          {
134         case WAIT_OBJECT_0:  return 0;
135         case WAIT_ABANDONED: return 1;
136         case WAIT_TIMEOUT:   return 2;
137         default: return -1;
138         }
139         break;
140
141     default: return -1;
142     }
143 #endif
144 }
145
146 int mutex_unlock(mutex_t* m)
147  {
148 #ifdef _POSIX_THREAD
149     return pthread_mutex_unlock(m);
150 #else
151     switch(m->type_)
152      {
153     case MUTEX_THREAD_SHARED:
154         LeaveCriticalSection(&m->thr_lock_);
155         return 0;
156
157     case MUTEX_PROCESS_SHARED:
158         if (!ReleaseMutex(m->proc_lock_))
159             return -1;
160         return 0;
161
162     default: return -1;
163     }
164 #endif
165 }
166www.2cto.com
167 int mutex_destroy(mutex_t* m)
168  {
169 #ifdef _POSIX_THREAD
170     return pthread_mutex_destroy(m);
171 #else
172     switch(m->type_)
173      {
174     case MUTEX_THREAD_SHARED:
175         DeleteCriticalSection(&m->thr_lock_);
176         return 0;
177
178     case MUTEX_PROCESS_SHARED:
179         if (!CloseHandle(m->proc_lock_))
180             return -1;
181         return 0;
182
183     default: return -1;
184     }
185 #endif
186 }

 

作者:春秋十二月