librf
spinlock.h
1 //用于内部实现的循环锁
2 
3 #pragma once
4 
5 namespace resumef
6 {
7 #if defined(RESUMEF_USE_CUSTOM_SPINLOCK)
8  using spinlock = RESUMEF_USE_CUSTOM_SPINLOCK;
9 #else
10 
14  struct spinlock
15  {
16  static const size_t MAX_ACTIVE_SPIN = 4000;
17  static const size_t MAX_YIELD_SPIN = 8000;
18  static const int FREE_VALUE = 0;
19  static const int LOCKED_VALUE = 1;
20 
21  std::atomic<int> lck;
22 #if _DEBUG
23  std::thread::id owner_thread_id;
24 #endif
25 
29  spinlock() noexcept
30  {
31  lck = FREE_VALUE;
32  }
33 
37  void lock() noexcept
38  {
39  int val = FREE_VALUE;
40  if (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel))
41  {
42 #if _DEBUG
43  //诊断错误的用法:进行了递归锁调用
44  assert(owner_thread_id != std::this_thread::get_id());
45 #endif
46 
47  size_t spinCount = 0;
48  auto dt = std::chrono::milliseconds{ 1 };
49  do
50  {
51  while (lck.load(std::memory_order_relaxed) != FREE_VALUE)
52  {
53  if (spinCount < MAX_ACTIVE_SPIN)
54  {
55  ++spinCount;
56  }
57  else if (spinCount < MAX_YIELD_SPIN)
58  {
59  ++spinCount;
60  std::this_thread::yield();
61  }
62  else
63  {
64  std::this_thread::sleep_for(dt);
65  dt = (std::min)(std::chrono::milliseconds{ 128 }, dt * 2);
66  }
67  }
68 
69  val = FREE_VALUE;
70  } while (!lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acq_rel));
71  }
72 
73 #if _DEBUG
74  owner_thread_id = std::this_thread::get_id();
75 #endif
76  }
77 
81  bool try_lock() noexcept
82  {
83  int val = FREE_VALUE;
84  bool ret = lck.compare_exchange_strong(val, LOCKED_VALUE, std::memory_order_acq_rel);
85 
86 #if _DEBUG
87  if (ret) owner_thread_id = std::this_thread::get_id();
88 #endif
89 
90  return ret;
91  }
92 
96  void unlock() noexcept
97  {
98 #if _DEBUG
99  owner_thread_id = std::thread::id();
100 #endif
101  lck.store(FREE_VALUE, std::memory_order_release);
102  }
103  };
104 
105 #endif
106 
107 #ifndef DOXYGEN_SKIP_PROPERTY
108  namespace detail
109  {
110  template<class _Ty, class _Cont = std::vector<_Ty>>
111  struct _LockVectorAssembleT
112  {
113  private:
114  _Cont& _Lks;
115  public:
116  _LockVectorAssembleT(_Cont& _LkN)
117  : _Lks(_LkN)
118  {}
119  size_t size() const
120  {
121  return _Lks.size();
122  }
123  _Ty& operator[](int _Idx)
124  {
125  return _Lks[_Idx];
126  }
127  void _Lock_ref(_Ty& _LkN) const
128  {
129  _LkN.lock();
130  }
131  bool _Try_lock_ref(_Ty& _LkN) const
132  {
133  return _LkN.try_lock();
134  }
135  void _Unlock_ref(_Ty& _LkN) const
136  {
137  _LkN.unlock();
138  }
139  void _Yield() const
140  {
141  std::this_thread::yield();
142  }
143  void _ReturnValue() const;
144  template<class U>
145  U _ReturnValue(U v) const;
146  };
147 
148  template<class _Ty, class _Cont>
149  struct _LockVectorAssembleT<std::reference_wrapper<_Ty>, _Cont>
150  {
151  private:
152  _Cont& _Lks;
153  public:
154  _LockVectorAssembleT(_Cont& _LkN)
155  : _Lks(_LkN)
156  {}
157  size_t size() const
158  {
159  return _Lks.size();
160  }
161  std::reference_wrapper<_Ty> operator[](int _Idx)
162  {
163  return _Lks[_Idx];
164  }
165  void _Lock_ref(std::reference_wrapper<_Ty> _LkN) const
166  {
167  _LkN.get().lock();
168  }
169  void _Unlock_ref(std::reference_wrapper<_Ty> _LkN) const
170  {
171  _LkN.get().unlock();
172  }
173  bool _Try_lock_ref(std::reference_wrapper<_Ty> _LkN) const
174  {
175  return _LkN.get().try_lock();
176  }
177  void _Yield() const
178  {
179  std::this_thread::yield();
180  }
181  void _ReturnValue() const;
182  template<class U>
183  U _ReturnValue(U v) const;
184  };
185 
186 #define LOCK_ASSEMBLE_NAME(fnName) scoped_lock_range_##fnName
187 #define LOCK_ASSEMBLE_AWAIT(a) (a)
188 #define LOCK_ASSEMBLE_RETURN(a) return (a)
189 #include "without_deadlock_assemble.inl"
190 #undef LOCK_ASSEMBLE_NAME
191 #undef LOCK_ASSEMBLE_AWAIT
192 #undef LOCK_ASSEMBLE_RETURN
193  }
194 #endif //DOXYGEN_SKIP_PROPERTY
195 
202  template<class _Ty, class _Cont = std::vector<_Ty>, class _Assemble = detail::_LockVectorAssembleT<_Ty, _Cont>>
204  {
205  public:
209  explicit batch_lock_t(_Cont& locks_)
210  : _LkN(&locks_)
211  , _LA(*_LkN)
212  {
213  detail::scoped_lock_range_lock_impl::_Lock_range(_LA);
214  }
215 
219  explicit batch_lock_t(_Cont& locks_, _Assemble& la_)
220  : _LkN(&locks_)
221  , _LA(la_)
222  {
223  detail::scoped_lock_range_lock_impl::_Lock_range(_LA);
224  }
225 
229  explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_)
230  : _LkN(&locks_)
231  , _LA(*_LkN)
232  { // construct but don't lock
233  }
234 
238  explicit batch_lock_t(std::adopt_lock_t, _Cont& locks_, _Assemble& la_)
239  : _LkN(&locks_)
240  , _LA(la_)
241  { // construct but don't lock
242  }
243 
247  ~batch_lock_t() noexcept
248  {
249  if (_LkN != nullptr)
250  detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA);
251  }
252 
256  void unlock()
257  {
258  if (_LkN != nullptr)
259  {
260  _LkN = nullptr;
261  detail::scoped_lock_range_lock_impl::_Unlock_locks(0, (int)_LA.size(), _LA);
262  }
263  }
264 
268  batch_lock_t(const batch_lock_t&) = delete;
269 
273  batch_lock_t& operator=(const batch_lock_t&) = delete;
274 
279  : _LkN(_Right._LkN)
280  , _LA(std::move(_Right._LA))
281  {
282  _Right._LkN = nullptr;
283  }
284 
289  {
290  if (this != &_Right)
291  {
292  _LkN = _Right._LkN;
293  _Right._LkN = nullptr;
294 
295  _LA = std::move(_Right._LA);
296  }
297  }
298  private:
299  _Cont* _LkN;
300  _Assemble _LA;
301  };
302 }
resumef::batch_lock_t::batch_lock_t
batch_lock_t(std::adopt_lock_t, _Cont &locks_)
通过锁容器构造,容器里的锁已经全部获得。
Definition: spinlock.h:229
resumef::batch_lock_t::batch_lock_t
batch_lock_t(batch_lock_t &&_Right)
支持移动构造。
Definition: spinlock.h:278
resumef::batch_lock_t::~batch_lock_t
~batch_lock_t() noexcept
析构函数里,释放容器里的锁。
Definition: spinlock.h:247
resumef::spinlock::spinlock
spinlock() noexcept
初始为未加锁。
Definition: spinlock.h:29
resumef::batch_lock_t::operator=
batch_lock_t & operator=(const batch_lock_t &)=delete
不支持拷贝赋值。
resumef::spinlock::unlock
void unlock() noexcept
释放锁。
Definition: spinlock.h:96
resumef::batch_lock_t::batch_lock_t
batch_lock_t(_Cont &locks_)
通过锁容器构造,并立刻应用加锁算法。
Definition: spinlock.h:209
resumef::spinlock::lock
void lock() noexcept
获得锁。会一直阻塞线程直到获得锁。
Definition: spinlock.h:37
resumef::batch_lock_t
无死锁的批量枷锁。
Definition: spinlock.h:203
resumef::spinlock::try_lock
bool try_lock() noexcept
尝试获得锁一次。
Definition: spinlock.h:81
resumef::batch_lock_t::batch_lock_t
batch_lock_t(_Cont &locks_, _Assemble &la_)
通过锁容器和锁集合构造,并立刻应用加锁算法。
Definition: spinlock.h:219
resumef::spinlock
一个自旋锁实现。
Definition: spinlock.h:14
resumef::batch_lock_t::operator=
batch_lock_t & operator=(batch_lock_t &&_Right)
支持移动赋值。
Definition: spinlock.h:288
resumef::batch_lock_t::batch_lock_t
batch_lock_t(std::adopt_lock_t, _Cont &locks_, _Assemble &la_)
通过锁容器和锁集合构造,容器里的锁已经全部获得。
Definition: spinlock.h:238
resumef::batch_lock_t::unlock
void unlock()
手工释放容器里的锁,析构函数里将不再有释放操作。
Definition: spinlock.h:256