hmutex.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #ifndef HV_MUTEX_H_
  2. #define HV_MUTEX_H_
  3. /*
  4. * @功能:此头文件封装了跨平台的线程同步手段,包括
  5. * 互斥量 hmutex_t
  6. * 可重入的互斥量 hrecursive_mutex_t
  7. * 自旋锁 hspinlock_t
  8. * 读写锁 hrwlock_t
  9. * 定时锁 htimed_mutex_t
  10. * 条件变量 hcondvar_t
  11. * 信号量 hsem_t
  12. *
  13. */
  14. #include "hexport.h"
  15. #include "hplatform.h"
  16. #include "htime.h"
  17. BEGIN_EXTERN_C
  18. #ifdef _MSC_VER
  19. #define hmutex_t CRITICAL_SECTION
  20. #define hmutex_init InitializeCriticalSection
  21. #define hmutex_destroy DeleteCriticalSection
  22. #define hmutex_lock EnterCriticalSection
  23. #define hmutex_unlock LeaveCriticalSection
  24. #define hrecursive_mutex_t CRITICAL_SECTION
  25. #define hrecursive_mutex_init InitializeCriticalSection
  26. #define hrecursive_mutex_destroy DeleteCriticalSection
  27. #define hrecursive_mutex_lock EnterCriticalSection
  28. #define hrecursive_mutex_unlock LeaveCriticalSection
  29. #define HSPINLOCK_COUNT -1
  30. #define hspinlock_t CRITICAL_SECTION
  31. #define hspinlock_init(pspin) InitializeCriticalSectionAndSpinCount(pspin, HSPINLOCK_COUNT)
  32. #define hspinlock_destroy DeleteCriticalSection
  33. #define hspinlock_lock EnterCriticalSection
  34. #define hspinlock_unlock LeaveCriticalSection
  35. #define hrwlock_t SRWLOCK
  36. #define hrwlock_init InitializeSRWLock
  37. #define hrwlock_destroy(plock)
  38. #define hrwlock_rdlock AcquireSRWLockShared
  39. #define hrwlock_rdunlock ReleaseSRWLockShared
  40. #define hrwlock_wrlock AcquireSRWLockExclusive
  41. #define hrwlock_wrunlock ReleaseSRWLockExclusive
  42. #define htimed_mutex_t HANDLE
  43. #define htimed_mutex_init(pmutex) *(pmutex) = CreateMutex(NULL, FALSE, NULL)
  44. #define htimed_mutex_destroy(pmutex) CloseHandle(*(pmutex))
  45. #define htimed_mutex_lock(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
  46. #define htimed_mutex_unlock(pmutex) ReleaseMutex(*(pmutex))
  47. // true: WAIT_OBJECT_0
  48. // false: WAIT_OBJECT_TIMEOUT
  49. #define htimed_mutex_lock_for(pmutex, ms) ( WaitForSingleObject(*(pmutex), ms) == WAIT_OBJECT_0 )
  50. #define hcondvar_t CONDITION_VARIABLE
  51. #define hcondvar_init InitializeConditionVariable
  52. #define hcondvar_destroy(pcond)
  53. #define hcondvar_wait(pcond, pmutex) SleepConditionVariableCS(pcond, pmutex, INFINITE)
  54. #define hcondvar_wait_for(pcond, pmutex, ms) SleepConditionVariableCS(pcond, pmutex, ms)
  55. #define hcondvar_signal WakeConditionVariable
  56. #define hcondvar_broadcast WakeAllConditionVariable
  57. #define honce_t INIT_ONCE
  58. #define HONCE_INIT INIT_ONCE_STATIC_INIT
  59. typedef void (*honce_fn)();
  60. static inline BOOL WINAPI s_once_func(INIT_ONCE* once, PVOID arg, PVOID* _) {
  61. honce_fn fn = (honce_fn)arg;
  62. fn();
  63. return TRUE;
  64. }
  65. static inline void honce(honce_t* once, honce_fn fn) {
  66. PVOID dummy = NULL;
  67. InitOnceExecuteOnce(once, s_once_func, (PVOID)fn, &dummy);
  68. }
  69. #define hsem_t HANDLE
  70. #define hsem_init(psem, value) *(psem) = CreateSemaphore(NULL, value, value+100000, NULL)
  71. #define hsem_destroy(psem) CloseHandle(*(psem))
  72. #define hsem_wait(psem) WaitForSingleObject(*(psem), INFINITE)
  73. #define hsem_post(psem) ReleaseSemaphore(*(psem), 1, NULL)
  74. // true: WAIT_OBJECT_0
  75. // false: WAIT_OBJECT_TIMEOUT
  76. #define hsem_wait_for(psem, ms) ( WaitForSingleObject(*(psem), ms) == WAIT_OBJECT_0 )
  77. #else
  78. #define hmutex_t pthread_mutex_t
  79. #define hmutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
  80. #define hmutex_destroy pthread_mutex_destroy
  81. #define hmutex_lock pthread_mutex_lock
  82. #define hmutex_unlock pthread_mutex_unlock
  83. #define hrecursive_mutex_t pthread_mutex_t
  84. #define hrecursive_mutex_init(pmutex) \
  85. do {\
  86. pthread_mutexattr_t attr;\
  87. pthread_mutexattr_init(&attr);\
  88. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
  89. pthread_mutex_init(pmutex, &attr);\
  90. } while(0)
  91. #define hrecursive_mutex_destroy pthread_mutex_destroy
  92. #define hrecursive_mutex_lock pthread_mutex_lock
  93. #define hrecursive_mutex_unlock pthread_mutex_unlock
  94. #if HAVE_PTHREAD_SPIN_LOCK
  95. #define hspinlock_t pthread_spinlock_t
  96. #define hspinlock_init(pspin) pthread_spin_init(pspin, PTHREAD_PROCESS_PRIVATE)
  97. #define hspinlock_destroy pthread_spin_destroy
  98. #define hspinlock_lock pthread_spin_lock
  99. #define hspinlock_unlock pthread_spin_unlock
  100. #else
  101. #define hspinlock_t pthread_mutex_t
  102. #define hspinlock_init(pmutex) pthread_mutex_init(pmutex, NULL)
  103. #define hspinlock_destroy pthread_mutex_destroy
  104. #define hspinlock_lock pthread_mutex_lock
  105. #define hspinlock_unlock pthread_mutex_unlock
  106. #endif
  107. #define hrwlock_t pthread_rwlock_t
  108. #define hrwlock_init(prwlock) pthread_rwlock_init(prwlock, NULL)
  109. #define hrwlock_destroy pthread_rwlock_destroy
  110. #define hrwlock_rdlock pthread_rwlock_rdlock
  111. #define hrwlock_rdunlock pthread_rwlock_unlock
  112. #define hrwlock_wrlock pthread_rwlock_wrlock
  113. #define hrwlock_wrunlock pthread_rwlock_unlock
  114. #define htimed_mutex_t pthread_mutex_t
  115. #define htimed_mutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
  116. #define htimed_mutex_destroy pthread_mutex_destroy
  117. #define htimed_mutex_lock pthread_mutex_lock
  118. #define htimed_mutex_unlock pthread_mutex_unlock
  119. static inline void timespec_after(struct timespec* ts, unsigned int ms) {
  120. struct timeval tv;
  121. gettimeofday(&tv, NULL);
  122. ts->tv_sec = tv.tv_sec + ms / 1000;
  123. ts->tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
  124. if (ts->tv_nsec >= 1000000000) {
  125. ts->tv_nsec -= 1000000000;
  126. ts->tv_sec += 1;
  127. }
  128. }
  129. // true: OK
  130. // false: ETIMEDOUT
  131. static inline int htimed_mutex_lock_for(htimed_mutex_t* mutex, unsigned int ms) {
  132. #if HAVE_PTHREAD_MUTEX_TIMEDLOCK
  133. struct timespec ts;
  134. timespec_after(&ts, ms);
  135. return pthread_mutex_timedlock(mutex, &ts) != ETIMEDOUT;
  136. #else
  137. int ret = 0;
  138. unsigned int end = gettick_ms() + ms;
  139. while ((ret = pthread_mutex_trylock(mutex)) != 0) {
  140. if (gettick_ms() >= end) {
  141. break;
  142. }
  143. hv_msleep(1);
  144. }
  145. return ret == 0;
  146. #endif
  147. }
  148. #define hcondvar_t pthread_cond_t
  149. #define hcondvar_init(pcond) pthread_cond_init(pcond, NULL)
  150. #define hcondvar_destroy pthread_cond_destroy
  151. #define hcondvar_wait pthread_cond_wait
  152. #define hcondvar_signal pthread_cond_signal
  153. #define hcondvar_broadcast pthread_cond_broadcast
  154. // true: OK
  155. // false: ETIMEDOUT
  156. static inline int hcondvar_wait_for(hcondvar_t* cond, hmutex_t* mutex, unsigned int ms) {
  157. struct timespec ts;
  158. timespec_after(&ts, ms);
  159. return pthread_cond_timedwait(cond, mutex, &ts) != ETIMEDOUT;
  160. }
  161. #define honce_t pthread_once_t
  162. #define HONCE_INIT PTHREAD_ONCE_INIT
  163. #define honce pthread_once
  164. #include <semaphore.h>
  165. #define hsem_t sem_t
  166. #define hsem_init(psem, value) sem_init(psem, 0, value)
  167. #define hsem_destroy sem_destroy
  168. #define hsem_wait sem_wait
  169. #define hsem_post sem_post
  170. // true: OK
  171. // false: ETIMEDOUT
  172. static inline int hsem_wait_for(hsem_t* sem, unsigned int ms) {
  173. #if HAVE_SEM_TIMEDWAIT
  174. struct timespec ts;
  175. timespec_after(&ts, ms);
  176. return sem_timedwait(sem, &ts) != ETIMEDOUT;
  177. #else
  178. int ret = 0;
  179. unsigned int end = gettick_ms() + ms;
  180. while ((ret = sem_trywait(sem)) != 0) {
  181. if (gettick_ms() >= end) {
  182. break;
  183. }
  184. hv_msleep(1);
  185. }
  186. return ret == 0;
  187. #endif
  188. }
  189. #endif
  190. END_EXTERN_C
  191. #ifdef __cplusplus
  192. #include <mutex>
  193. #include <condition_variable>
  194. // using std::mutex;
  195. // NOTE: test std::timed_mutex incorrect in some platforms, use htimed_mutex_t
  196. // using std::timed_mutex;
  197. using std::condition_variable;
  198. using std::lock_guard;
  199. using std::unique_lock;
  200. BEGIN_NAMESPACE_HV
  201. class MutexLock {
  202. public:
  203. MutexLock() { hmutex_init(&_mutex); }
  204. ~MutexLock() { hmutex_destroy(&_mutex); }
  205. void lock() { hmutex_lock(&_mutex); }
  206. void unlock() { hmutex_unlock(&_mutex); }
  207. protected:
  208. hmutex_t _mutex;
  209. };
  210. class SpinLock {
  211. public:
  212. SpinLock() { hspinlock_init(&_spin); }
  213. ~SpinLock() { hspinlock_destroy(&_spin); }
  214. void lock() { hspinlock_lock(&_spin); }
  215. void unlock() { hspinlock_unlock(&_spin); }
  216. protected:
  217. hspinlock_t _spin;
  218. };
  219. class RWLock {
  220. public:
  221. RWLock() { hrwlock_init(&_rwlock); }
  222. ~RWLock() { hrwlock_destroy(&_rwlock); }
  223. void rdlock() { hrwlock_rdlock(&_rwlock); }
  224. void rdunlock() { hrwlock_rdunlock(&_rwlock); }
  225. void wrlock() { hrwlock_wrlock(&_rwlock); }
  226. void wrunlock() { hrwlock_wrunlock(&_rwlock); }
  227. void lock() { rdlock(); }
  228. void unlock() { rdunlock(); }
  229. protected:
  230. hrwlock_t _rwlock;
  231. };
  232. template<class T>
  233. class LockGuard {
  234. public:
  235. LockGuard(T& t) : _lock(t) { _lock.lock(); }
  236. ~LockGuard() { _lock.unlock(); }
  237. protected:
  238. T& _lock;
  239. };
  240. END_NAMESPACE_HV
  241. // same as java synchronized(lock) { ... }
  242. #define synchronized(lock) for (std::lock_guard<std::mutex> _lock_(lock), *p = &_lock_; p != NULL; p = NULL)
  243. #endif // __cplusplus
  244. #endif // HV_MUTEX_H_