nlib
CriticalSection.h
[詳解]
1 
2 #pragma once
3 #ifndef INCLUDE_NN_NLIB_THREADING_CRITICALSECTION_H_
4 #define INCLUDE_NN_NLIB_THREADING_CRITICALSECTION_H_
5 
6 #include "nn/nlib/Config.h"
7 #include "nn/nlib/Swap.h"
8 
9 NLIB_NAMESPACE_BEGIN
10 class TimeSpan;
11 class DateTime;
12 namespace threading {
13 
14 class NLIB_LOCKABLE SimpleCriticalSection {
15  public:
16 #ifdef NLIB_CXX11_CONSTEXPR
18  : m_Mutex(NLIB_MUTEX_INITIALIZER) {}
19 #else
21  errno_t e = nlib_mutex_init(&m_Mutex);
22  NLIB_ASSERT_NOERR(e);
23  NLIB_UNUSED(e);
24  }
25 #endif
26  ~SimpleCriticalSection() NLIB_NOEXCEPT {
27  errno_t e = nlib_mutex_destroy(&m_Mutex);
28  NLIB_UNUSED(e);
29  NLIB_ASSERT_NOERR(e);
30  }
31  void lock() NLIB_NOEXCEPT NLIB_LOCK_FUNC() {
32  errno_t e = nlib_mutex_lock(&m_Mutex);
33  NLIB_UNUSED(e);
34  NLIB_ASSERT_NOERR(e);
35  }
36  void unlock() NLIB_NOEXCEPT NLIB_UNLOCK_FUNC() {
37  errno_t e = nlib_mutex_unlock(&m_Mutex);
38  NLIB_UNUSED(e);
39  NLIB_ASSERT_NOERR(e);
40  }
41  bool try_lock() NLIB_NOEXCEPT NLIB_TRYLOCK_FUNC(true) {
42  errno_t e = nlib_mutex_trylock(&m_Mutex);
43  if (e == 0) return true;
44  NLIB_ASSERT(e == EBUSY);
45  return false;
46  }
48  native_handle_type native_handle() NLIB_NOEXCEPT { return &m_Mutex; }
49 
50  private:
51  nlib_mutex m_Mutex;
52 };
53 
54 #ifndef NLIB_CRITICALSECTION_USE_FALLBACK
56  public:
57 #if defined(NLIB_CXX11_CONSTEXPR)
60 #else
62  errno_t e = nlib_mutex_recursive_init(&m_Mutex);
63  NLIB_ASSERT_NOERR(e);
64  NLIB_UNUSED(e);
65  }
66 #endif
67  ~CriticalSection() NLIB_NOEXCEPT { nlib_mutex_destroy(&m_Mutex); }
69  errno_t e = nlib_mutex_lock(&m_Mutex);
70  NLIB_ASSERT_NOERR(e);
71  NLIB_UNUSED(e);
72  }
74  errno_t e = nlib_mutex_unlock(&m_Mutex);
75  NLIB_ASSERT_NOERR(e);
76  NLIB_UNUSED(e);
77  }
79  errno_t e = nlib_mutex_trylock(&m_Mutex);
80  if (e == 0) return true;
81  NLIB_ASSERT(e == EBUSY);
82  return false;
83  }
85  native_handle_type native_handle() NLIB_NOEXCEPT { return &m_Mutex; }
86 
87  private:
88  nlib_mutex m_Mutex;
89 };
90 #endif
91 
92 #ifndef NLIB_TIMEDCRITICALSECTION_USE_FALLBACK
94  public:
95 #if defined(NLIB_CXX11_CONSTEXPR)
98 #else
101  NLIB_ASSERT_NOERR(e);
102  NLIB_UNUSED(e);
103  }
104 #endif
105  ~TimedCriticalSection() NLIB_NOEXCEPT { nlib_mutex_destroy(&m_Mutex); }
106  NLIB_VIS_PUBLIC bool try_lock_for(const TimeSpan& span) NLIB_NOEXCEPT;
107  NLIB_VIS_PUBLIC bool try_lock_until(const DateTime& abstime) NLIB_NOEXCEPT;
108  void lock() NLIB_NOEXCEPT {
109  errno_t e = nlib_mutex_lock(&m_Mutex);
110  NLIB_ASSERT_NOERR(e);
111  NLIB_UNUSED(e);
112  }
113  void unlock() NLIB_NOEXCEPT {
114  errno_t e = nlib_mutex_unlock(&m_Mutex);
115  NLIB_ASSERT_NOERR(e);
116  NLIB_UNUSED(e);
117  }
118  bool try_lock() NLIB_NOEXCEPT {
119  errno_t e = nlib_mutex_trylock(&m_Mutex);
120  if (e == 0) return true;
121  NLIB_ASSERT(e == EBUSY);
122  return false;
123  }
125  native_handle_type native_handle() NLIB_NOEXCEPT { return &m_Mutex; }
126 
127  private:
128  nlib_mutex m_Mutex;
129 };
130 #endif
131 
132 } // namespace threading
133 NLIB_NAMESPACE_END
134 
135 NLIB_NAMESPACE_BEGIN
136 namespace threading {
137 
138 class DummyCriticalSection {
139  public:
140  NLIB_CEXPR DummyCriticalSection() NLIB_NOEXCEPT {}
141  ~DummyCriticalSection() NLIB_NOEXCEPT {}
142  void lock() NLIB_NOEXCEPT {}
143  void unlock() NLIB_NOEXCEPT {}
144  bool try_lock() NLIB_NOEXCEPT { return true; }
145  bool try_lock_for(const TimeSpan&) NLIB_NOEXCEPT { return true; } // NOLINT
146  bool try_lock_until(const DateTime&) NLIB_NOEXCEPT { return true; } // NOLINT
147  typedef int native_handle_type;
148  native_handle_type native_handle() NLIB_NOEXCEPT { return 0; }
149 
150  private:
151  NLIB_DISALLOW_COPY_AND_ASSIGN(DummyCriticalSection);
152 };
153 
154 class CriticalSectionFallback {
155  public:
156  // NOTE:
157  // -1 must not be a thread-id
158  CriticalSectionFallback() NLIB_NOEXCEPT : m_Counter(0) {
159  m_Tid = -1;
160  }
161  ~CriticalSectionFallback() NLIB_NOEXCEPT {}
162  NLIB_VIS_PUBLIC void lock() NLIB_NOEXCEPT;
163  NLIB_VIS_PUBLIC void unlock() NLIB_NOEXCEPT;
164  NLIB_VIS_PUBLIC bool try_lock() NLIB_NOEXCEPT;
165  typedef SimpleCriticalSection::native_handle_type native_handle_type;
166  native_handle_type native_handle() { return m_Lock.native_handle(); }
167 
168  private:
169  SimpleCriticalSection m_Lock;
170  int32_t m_Counter;
171  nlib_thread_id m_Tid;
172 };
173 
174 #ifdef NLIB_CRITICALSECTION_USE_FALLBACK
175 typedef CriticalSectionFallback CriticalSection;
176 #endif
177 
178 class TimedCriticalSectionFallback {
179  public:
180  TimedCriticalSectionFallback() NLIB_NOEXCEPT {}
181  ~TimedCriticalSectionFallback() NLIB_NOEXCEPT {}
182  void lock() NLIB_NOEXCEPT { m_Lock.lock(); }
183  void unlock() NLIB_NOEXCEPT { m_Lock.unlock(); }
184  bool try_lock() NLIB_NOEXCEPT { return m_Lock.try_lock(); }
185  NLIB_VIS_PUBLIC bool try_lock_for(const TimeSpan& span) NLIB_NOEXCEPT;
186  NLIB_VIS_PUBLIC bool try_lock_until(const DateTime& abstime) NLIB_NOEXCEPT;
187  typedef CriticalSection::native_handle_type native_handle_type;
188  native_handle_type native_handle() { return m_Lock.native_handle(); }
189 
190  private:
191  CriticalSection m_Lock;
192 };
193 
194 #ifdef NLIB_TIMEDCRITICALSECTION_USE_FALLBACK
195 typedef TimedCriticalSectionFallback TimedCriticalSection;
196 #endif
197 
198 } // namespace threading
199 NLIB_NAMESPACE_END
200 
201 NLIB_NAMESPACE_BEGIN
202 namespace threading {
203 
204 struct AdoptLockType {};
205 struct TryToLockType {};
206 struct DeferLockType {};
207 
211 
212 template <class T>
213 class NLIB_SCOPED_LOCKABLE ScopedLock {
214  public:
215  typedef T mutex_type;
216  typedef typename mutex_type::native_handle_type native_handle_type;
217  explicit ScopedLock(mutex_type& m) NLIB_LOCK_FUNC(m_Lock) : m_Lock(m) { // NOLINT
218  m_Lock.lock();
219  }
220  ScopedLock(mutex_type& m, AdoptLockType) NLIB_NOEXCEPT NLIB_LOCK_FUNC(m_Lock) // NOLINT
221  : m_Lock(m) {}
222  ~ScopedLock() NLIB_NOEXCEPT NLIB_UNLOCK_FUNC(m_Lock) { m_Lock.unlock(); }
223  native_handle_type native_handle() { return m_Lock.native_handle(); }
224 
225  private:
226  mutex_type& m_Lock;
228 };
229 
230 template <>
231 class NLIB_SCOPED_LOCKABLE ScopedLock<SimpleCriticalSection> {
232  public:
233  typedef SimpleCriticalSection mutex_type;
234  typedef mutex_type::native_handle_type native_handle_type;
235  explicit ScopedLock(mutex_type& m) NLIB_LOCK_FUNC(m_Lock) : m_Lock(m) { // NOLINT
236  m_Lock.lock();
237  }
238  ScopedLock(mutex_type& m, AdoptLockType) NLIB_NOEXCEPT NLIB_LOCK_REQUIRED(m) // NOLINT
239  NLIB_LOCK_FUNC(m_Lock)
240  : m_Lock(m) {}
241  ~ScopedLock() NLIB_NOEXCEPT NLIB_UNLOCK_FUNC(m_Lock) { m_Lock.unlock(); }
242  native_handle_type native_handle() { return m_Lock.native_handle(); }
243 
244  private:
245  mutex_type& m_Lock;
246  NLIB_DISALLOW_COPY_AND_ASSIGN(ScopedLock);
247 };
248 
249 template<>
250 class NLIB_SCOPED_LOCKABLE ScopedLock<nlib_mutex> {
251  public:
252  typedef nlib_mutex mutex_type;
253  typedef nlib_mutex* native_handle_type;
254  explicit ScopedLock(mutex_type& m) NLIB_LOCK_FUNC(m_Lock) : m_Lock(m) { // NOLINT
255  errno_t e = nlib_mutex_lock(&m_Lock);
256  NLIB_UNUSED(e);
257  NLIB_ASSERT_NOERR(e);
258  }
259  ScopedLock(mutex_type& m, AdoptLockType) NLIB_NOEXCEPT NLIB_LOCK_REQUIRED(m) // NOLINT
260  NLIB_LOCK_FUNC(m_Lock)
261  : m_Lock(m) {}
262  ~ScopedLock() NLIB_NOEXCEPT NLIB_UNLOCK_FUNC(m_Lock) {
263  errno_t e = nlib_mutex_unlock(&m_Lock);
264  NLIB_UNUSED(e);
265  NLIB_ASSERT_NOERR(e);
266  }
267  native_handle_type native_handle() { return &m_Lock; }
268 
269  private:
270  nlib_mutex& m_Lock;
271  NLIB_DISALLOW_COPY_AND_ASSIGN(ScopedLock);
272 };
273 
274 template <class T>
275 class UniqueLock {
276  public:
277  typedef T mutex_type;
278  typedef typename mutex_type::native_handle_type native_handle_type;
279  UniqueLock() NLIB_NOEXCEPT : m_Locker(NULL), m_Locked(false) {}
280  explicit UniqueLock(mutex_type& rhs) : m_Locker(&rhs), m_Locked(true) { // NOLINT
281  rhs.lock();
282  }
283  UniqueLock(mutex_type& rhs, AdoptLockType) // NOLINT
284  : m_Locker(&rhs),
285  m_Locked(true) {}
286  UniqueLock(mutex_type& rhs, DeferLockType) // NOLINT
287  NLIB_NOEXCEPT : m_Locker(&rhs),
288  m_Locked(false) {}
289  UniqueLock(mutex_type& rhs, TryToLockType) // NOLINT
290  : m_Locker(&rhs),
291  m_Locked(rhs.try_lock()) {}
292  NLIB_MOVE_MEMBER_HELPER_2(UniqueLock, m_Locker, m_Locked)
294  if (m_Locked) m_Locker->unlock();
295  }
296  void lock() {
297  NLIB_ASSERT(m_Locker && !m_Locked);
298  if (!m_Locker || m_Locked) {
299  return;
300  }
301  m_Locker->lock();
302  m_Locked = true;
303  }
305  NLIB_ASSERT(m_Locker && m_Locked);
306  if (!m_Locker || !m_Locked) {
307  return;
308  }
309  m_Locker->unlock();
310  m_Locked = false;
311  }
313  NLIB_ASSERT(m_Locker && !m_Locked);
314  if (!m_Locker || m_Locked) {
315  return false;
316  }
317  m_Locked = m_Locker->try_lock();
318  return m_Locked;
319  }
320  bool try_lock_for(const TimeSpan& timeout) NLIB_NOEXCEPT {
321  NLIB_ASSERT(m_Locker && !m_Locked);
322  if (!m_Locker || m_Locked) {
323  return false;
324  }
325  m_Locked = m_Locker->try_lock_for(timeout);
326  return m_Locked;
327  }
328  bool try_lock_until(const DateTime& abstime) NLIB_NOEXCEPT {
329  NLIB_ASSERT(m_Locker && !m_Locked);
330  if (!m_Locker || m_Locked) {
331  return false;
332  }
333  m_Locked = m_Locker->try_lock_until(abstime);
334  return m_Locked;
335  }
336  void swap(UniqueLock& rhs) NLIB_NOEXCEPT { // NOLINT
337  using std::swap;
338  swap(m_Locker, rhs.m_Locker);
339  swap(m_Locked, rhs.m_Locked);
340  }
341  mutex_type* release() NLIB_NOEXCEPT {
342  mutex_type* p = m_Locker;
343  m_Locker = NULL;
344  m_Locked = false;
345  return p;
346  }
347  mutex_type* mutex() const NLIB_NOEXCEPT { return m_Locker; }
348  native_handle_type native_handle() { return m_Locker->native_handle(); }
349  bool owns_lock() const NLIB_NOEXCEPT { return m_Locked; }
350  NLIB_SAFE_BOOL(UniqueLock, owns_lock());
351 
352  private:
353  mutex_type* m_Locker;
354  bool m_Locked;
356 };
357 
358 namespace detail {
359 
360 template<class T>
361 NLIB_ALWAYS_INLINE nlib_mutex* GetRawMutex(T& obj) { // NOLINT
362  return obj.native_handle();
363 }
364 
365 template<>
366 NLIB_ALWAYS_INLINE nlib_mutex* GetRawMutex(nlib_mutex& obj) { // NOLINT
367  return &obj;
368 }
369 
370 } // namespace detail
371 
372 } // namespace threading
373 NLIB_NAMESPACE_END
374 
375 #ifndef NLIB_STD_SWAP_WORKAROUND
376 NLIB_NAMESPACE_BEGIN
377 #endif
378 
379 NLIB_DEFINE_STD_SWAP_T_BEGIN1(threading) // NOLINT
380 NLIB_DEFINE_STD_SWAP_T1(T, NLIB_NS::threading::UniqueLock) // NOLINT
381 NLIB_DEFINE_STD_SWAP_T_END1(threading) // NOLINT
382 
383 #ifndef NLIB_STD_SWAP_WORKAROUND
384 NLIB_NAMESPACE_END
385 #endif
386 
387 
388 #endif // INCLUDE_NN_NLIB_THREADING_CRITICALSECTION_H_
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Platform.h:2151
UniqueLock() noexcept
関連付けなしにオブジェクトを初期化します。
native_handle_type native_handle() noexcept
ネイティブ型のミューテックスのポインタを取得します。
bool owns_lock() const noexcept
UniqueLockに関連付けられたロックがロックされていればtrueを返します。
void lock() noexcept
ロックを取得し、クリティカルセクションに入ります。取得できるまでブロックします。
~ScopedLock() noexcept NLIB_UNLOCK_FUNC(m_Lock)
CriticalSection等をアンロックします(unlock()を呼び出します)。
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:126
#define NLIB_SAFE_BOOL(class_name, exp)
クラス内に安全なoperator bool()を定義します。 可能であればC++11のexplicit boolを利用します。 ...
Definition: Config.h:141
bool try_lock() noexcept NLIB_TRYLOCK_FUNC(true)
ロックを取得し、クリティカルセクションに入ることを試みます。
最も単純なクリティカルセクションです。リエントラントではありません。
mutex_type * release() noexcept
関連付けを解除します。アンロックはされません。
errno_t nlib_mutex_lock(nlib_mutex *mutex)
与えられたmutexをロックします。
ScopedLock(mutex_type &m, AdoptLockType) noexcept NLIB_LOCK_FUNC(m_Lock)
CriticalSection等が既にロックされていると仮定して、ロックせずにオブジェクトを初期化します。 デストラ...
mutex_type::native_handle_type native_handle_type
mutex_type::native_handle_type
errno_t nlib_mutex_unlock(nlib_mutex *mutex)
与えられたmutex をアンロックします。
UniqueLock(mutex_type &rhs, AdoptLockType)
CriticalSection等が既にロックされていると仮定して、ロックせずにオブジェクトを初期化します。 デストラ...
bool try_lock() noexcept
関連付けられたCriticalSection等のロックを試みます。
void unlock() noexcept
ロックを開放し、クリティカルセクションから出ます。
mutex_type::native_handle_type native_handle_type
mutex_type::native_handle_type
日時を表すクラスです。
Definition: DateTime.h:249
void swap(UniqueLock &rhs) noexcept
関連付けられているCriticalSection等のオブジェクトをスワップします。
native_handle_type native_handle()
ロックを表す実装固有のハンドルを返します。
constexpr SimpleCriticalSection() noexcept
デフォルトコンストラクタです。
#define NLIB_RECURSIVE_MUTEX_INITIALIZER
nlib_mutexを静的に初期化するためのマクロ。再帰mutexになる。
errno_t nlib_mutex_destroy(nlib_mutex *mutex)
mutexオブジェクトを破壊し、関連付けられているリソース(あれば)を解放します。
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
void unlock() noexcept
ロックを開放し、クリティカルセクションから出ます。
タグ用の型でScopedLockとUniqueLockにおいて利用されます。
constexpr CriticalSection() noexcept
デフォルトコンストラクタです。
void lock() noexcept NLIB_LOCK_FUNC()
ロックを取得し、クリティカルセクションに入ります。取得できるまでブロックします。
CriticalSection等をラップするためのクラスです。
nlib_mutex * native_handle_type
ネイティブのミューテックスへのポインタ型のtypedefです。
bool try_lock() noexcept
ロックを取得し、クリティカルセクションに入ることを試みます。
native_handle_type native_handle()
ロックを表す実装固有のハンドルを返します。
タグ用の型でScopedLockとUniqueLockにおいて利用されます。
nlib_mutex * native_handle_type
ネイティブのミューテックスへのポインタ型のtypedefです。
nlib_mutex * native_handle_type
ネイティブのミューテックスへのポインタ型のtypedefです。
ScopedLock(mutex_type &m) NLIB_LOCK_FUNC(m_Lock)
CriticalSection等をロックします(lock()を呼び出します)。
bool try_lock_for(const TimeSpan &timeout) noexcept
関連付けられたCriticalSection等のタイムアウト付きロックを試みます。
constexpr const DeferLockType deferLock
DeferLockType 型の値です。
開発環境別の設定が書かれるファイルです。
#define NLIB_RECURSIVE_TIMED_MUTEX_INITIALIZER
nlib_mutexを静的に初期化するためのマクロ。再帰でタイムアウト可能なmutexになる。
NLIB_CHECK_RESULT errno_t nlib_mutex_trylock(nlib_mutex *mutex)
mutexがロックされていない場合のみロックします。
constexpr const AdoptLockType adoptLock
AdoptLockType 型の値です。
タグ用の型でScopedLockとUniqueLockにおいて利用されます。
void lock() noexcept
ロックを取得し、クリティカルセクションに入ります。取得できるまでブロックします。
UniqueLock(mutex_type &rhs, TryToLockType)
初期化の際にtry_lock()でロックを試みます。
int nlib_thread_id
スレッド毎にユニークな整数値
Definition: Platform.h:859
CriticalSection等をラップしてコンストラクタでロック、デストラクタでアンロックします。 ...
pthread_mutex_t nlib_mutex
ミューテックス変数の型です。
#define NLIB_MUTEX_INITIALIZER
nlib_mutexを静的に初期化するためのマクロ。
#define NLIB_ALWAYS_INLINE
コンパイラに関数をインライン展開するように強く示します。
Definition: Platform_unix.h:59
void unlock() noexcept NLIB_UNLOCK_FUNC()
ロックを開放し、クリティカルセクションから出ます。
#define NLIB_VIS_PUBLIC
関数やクラス等のシンボルをライブラリの外部に公開します。
Definition: Platform_unix.h:51
UniqueLock(mutex_type &rhs)
CriticalSection等をロックして、このオブジェクトに関連付けます。
時間を表すクラスです。
Definition: DateTime.h:93
リエントラントでタイムアウトが可能なクリティカルセクションです。
native_handle_type native_handle() noexcept
ネイティブ型のミューテックスのポインタを取得します。
constexpr const TryToLockType tryToLock
TryToLockType 型の値です。
void unlock() noexcept
関連付けられたCriticalSection等をアンロックします。
リエントラントなミューテックスです。
bool try_lock() noexcept
ロックを取得し、クリティカルセクションに入ることを試みます。
UniqueLock(mutex_type &rhs, DeferLockType) noexcept
ロックせずにオブジェクトを初期化します。
constexpr TimedCriticalSection() noexcept
デフォルトコンストラクタです。
errno_t nlib_mutex_recursive_init(nlib_mutex *mutex)
再帰ミューテックスを初期化します。
void lock()
関連付けられたCriticalSection等をロックします。
errno_t nlib_mutex_init(nlib_mutex *mutex)
ミューテックスを初期化します。
mutex_type * mutex() const noexcept
関連付けられているCriticalSection等のオブジェクトへのポインタを取得します。
bool try_lock_until(const DateTime &abstime) noexcept
関連付けられたCriticalSection等のタイムアウト付きロックを試みます。
native_handle_type native_handle() noexcept
ネイティブ型のミューテックスのポインタを取得します。
errno_t nlib_mutex_recursive_timed_init(nlib_mutex *mutex)
再帰かつタイムアウト可能なミューテックスを初期化します。
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:24