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>>
203 class batch_lock_t
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
278 batch_lock_t(batch_lock_t&& _Right)
279 : _LkN(_Right._LkN)
280 , _LA(std::move(_Right._LA))
281 {
282 _Right._LkN = nullptr;
283 }
284
288 batch_lock_t& operator=(batch_lock_t&& _Right)
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