libcopp  1.1.0
spin_lock.h
Go to the documentation of this file.
1 
26 #ifndef UTIL_LOCK_SPINLOCK_H
27 #define UTIL_LOCK_SPINLOCK_H
28 
29 #pragma once
30 
31 #if defined(_MSC_VER)
32 
33 #include <Windows.h> // YieldProcessor
34 
35 #include <Processthreadsapi.h>
36 #include <Synchapi.h> // Windows server
37 #include <intrin.h>
38 
39 #endif
40 
42 
43 #include "atomic_int_type.h"
44 
50 #if defined(_MSC_VER)
51 
52 /*
53  * See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687419(v=vs.85).aspx
54  * Not for intel c++ compiler, so ignore http://software.intel.com/en-us/forums/topic/296168
55  */
56 
57 #ifdef YieldProcessor
58 #define __UTIL_LOCK_SPIN_LOCK_PAUSE() YieldProcessor()
59 #endif
60 
61 #elif defined(__GNUC__) || defined(__clang__)
62 #if defined(__i386__) || defined(__x86_64__)
63 
68 #define __UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("pause")
69 #elif defined(__ia64__) || defined(__ia64)
70 
75 #define __UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("hint @pause")
76 #elif defined(__arm__) && !defined(__ANDROID__)
77 
81 #define __UTIL_LOCK_SPIN_LOCK_PAUSE() __asm__ __volatile__("yield")
82 #endif
83 
84 #endif /*compilers*/
85 
86 // set pause do nothing
87 #if !defined(__UTIL_LOCK_SPIN_LOCK_PAUSE)
88 #define __UTIL_LOCK_SPIN_LOCK_PAUSE()
89 #endif
97 #if 0 && defined(_MSC_VER)
98 
99 // SwitchToThread only can be used in desktop system
100 
101 #define __UTIL_LOCK_SPIN_LOCK_CPU_YIELD() SwitchToThread()
102 
103 #elif defined(__linux__) || defined(__unix__)
104 #include <sched.h>
105 #define __UTIL_LOCK_SPIN_LOCK_CPU_YIELD() sched_yield()
106 #endif
107 
108 #ifndef __UTIL_LOCK_SPIN_LOCK_CPU_YIELD
109 #define __UTIL_LOCK_SPIN_LOCK_CPU_YIELD() __UTIL_LOCK_SPIN_LOCK_PAUSE()
110 #endif
111 
117 #if defined(__UTIL_LOCK_ATOMIC_INT_TYPE_ATOMIC_STD)
118 #include <chrono>
119 #include <thread>
120 #define __UTIL_LOCK_SPIN_LOCK_THREAD_YIELD() ::std::this_thread::yield()
121 #define __UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() ::std::this_thread::sleep_for(::std::chrono::milliseconds(1))
122 #elif defined(_MSC_VER)
123 #define __UTIL_LOCK_SPIN_LOCK_THREAD_YIELD() Sleep(0)
124 #define __UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() Sleep(1)
125 #endif
126 
127 #ifndef __UTIL_LOCK_SPIN_LOCK_THREAD_YIELD
128 #define __UTIL_LOCK_SPIN_LOCK_THREAD_YIELD()
129 #define __UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP() __UTIL_LOCK_SPIN_LOCK_CPU_YIELD()
130 #endif
131 
144 #define __UTIL_LOCK_SPIN_LOCK_WAIT(x) \
145  { \
146  unsigned char try_lock_times = static_cast<unsigned char>(x); \
147  if (try_lock_times < 4) { \
148  } else if (try_lock_times < 16) { \
149  __UTIL_LOCK_SPIN_LOCK_PAUSE(); \
150  } else if (try_lock_times < 32) { \
151  __UTIL_LOCK_SPIN_LOCK_THREAD_YIELD(); \
152  } else if (try_lock_times < 64) { \
153  __UTIL_LOCK_SPIN_LOCK_CPU_YIELD(); \
154  } else { \
155  __UTIL_LOCK_SPIN_LOCK_THREAD_SLEEP(); \
156  } \
157  }
158 
159 
160 namespace util {
161  namespace lock {
166  class spin_lock {
167  private:
168  typedef enum { UNLOCKED = 0, LOCKED = 1 } lock_state_t;
170 #if defined(LOCK_DISABLE_MT) && LOCK_DISABLE_MT
172 #else
173  unsigned int
174 #endif
175  >
177 
178  public:
180 
181  void lock() {
182  unsigned char try_times = 0;
183  while (lock_status_.exchange(static_cast<unsigned int>(LOCKED), ::util::lock::memory_order_acq_rel) == LOCKED)
184  __UTIL_LOCK_SPIN_LOCK_WAIT(try_times++); /* busy-wait */
185  }
186 
187  void unlock() { lock_status_.store(static_cast<unsigned int>(UNLOCKED), ::util::lock::memory_order_release); }
188 
190 
191  bool try_lock() {
192  return lock_status_.exchange(static_cast<unsigned int>(LOCKED), ::util::lock::memory_order_acq_rel) == UNLOCKED;
193  }
194 
195  bool try_unlock() {
196  return lock_status_.exchange(static_cast<unsigned int>(UNLOCKED), ::util::lock::memory_order_acq_rel) == LOCKED;
197  }
198  };
199  } // namespace lock
200 } // namespace util
201 
202 #endif /* SPINLOCK_H_ */
value_type exchange(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
void store(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
#define __UTIL_LOCK_SPIN_LOCK_WAIT(x)
Definition: spin_lock.h:144
::util::lock::atomic_int_type< unsigned int > lock_status_
Definition: spin_lock.h:176
整数类型的原子操作跨平台适配 Licensed under the MIT licenses.
value_type load(EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) const UTIL_CONFIG_NOEXCEPT