ManaPlus
fast_mutex.h
Go to the documentation of this file.
1 // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 // vim:tabstop=4:shiftwidth=4:expandtab:
3 
4 /*
5  * Copyright (C) 2004-2015 Wu Yongwei <adah at users dot sourceforge dot net>
6  *
7  * This software is provided 'as-is', without any express or implied
8  * warranty. In no event will the authors be held liable for any
9  * damages arising from the use of this software.
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute
13  * it freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must
16  * not claim that you wrote the original software. If you use this
17  * software in a product, an acknowledgement in the product
18  * documentation would be appreciated but is not required.
19  * 2. Altered source versions must be plainly marked as such, and must
20  * not be misrepresented as being the original software.
21  * 3. This notice may not be removed or altered from any source
22  * distribution.
23  *
24  * This file is part of Stones of Nvwa:
25  * http://sourceforge.net/projects/nvwa
26  *
27  */
28 
37 #ifndef NVWA_FAST_MUTEX_H
38 #define NVWA_FAST_MUTEX_H
39 
40 #include "debug/nvwa/_nvwa.h" // NVWA_NAMESPACE_*
41 #include "debug/nvwa/c++11.h" // HAVE_CXX11_MUTEX
42 
43 # if !defined(_NOTHREADS)
44 # if !defined(NVWA_USE_CXX11_MUTEX) && HAVE_CXX11_MUTEX != 0 && \
45  !defined(_WIN32THREADS) && !defined(NVWA_WIN32THREADS) && \
46  !defined(NVWA_PTHREADS) && !defined(NVWA_NOTHREADS) && \
47  defined(_WIN32) && defined(_MT) && \
48  (!defined(_MSC_VER) || defined(_DLL))
49 // Prefer using std::mutex on Windows to avoid the namespace
50 // pollution caused by <windows.h>. However, MSVC has a re-entry
51 // issue with its std::mutex implementation, and std::mutex should
52 // not be used unless /MD or /MDd is used. For more information,
53 // check out:
54 //
55 // https://connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag
56 // http://stackoverflow.com/questions/14319344/stdmutex-lock-hangs-when-overriding-the-new-operator
57 //
58 # define NVWA_USE_CXX11_MUTEX 1
59 # endif
60 
61 # if !defined(_WIN32THREADS) && \
62  (defined(_WIN32) && defined(_MT))
63 // Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC,
64 // or -mthreads in MinGW GCC.
65 # define _WIN32THREADS
66 # elif !defined(_PTHREADS) && \
67  defined(_REENTRANT)
68 // Automatically use _PTHREADS when specifying -pthread in GCC or Clang.
69 # define _PTHREADS
70 # endif
71 # endif
72 
73 # ifndef NVWA_USE_CXX11_MUTEX
74 # if HAVE_CXX11_MUTEX != 0 && \
75  !defined(_NOTHREADS) && !defined(NVWA_NOTHREADS) && \
76  !defined(_PTHREADS) && !defined(NVWA_PTHREADS) && \
77  !defined(_WIN32THREADS) && !defined(NVWA_WIN32THREADS)
78 # define NVWA_USE_CXX11_MUTEX 1
79 # else
80 # define NVWA_USE_CXX11_MUTEX 0
81 # endif
82 # endif
83 
84 # if !defined(_PTHREADS) && !defined(_WIN32THREADS) && \
85  !defined(_NOTHREADS) && NVWA_USE_CXX11_MUTEX == 0
86 # define _NOTHREADS
87 # endif
88 
89 # if defined(_NOTHREADS)
90 # if defined(_PTHREADS) || defined(_WIN32THREADS) || \
91  NVWA_USE_CXX11_MUTEX != 0
92 # undef _NOTHREADS
93 # error "Cannot define multi-threaded mode with -D_NOTHREADS"
94 # endif
95 # endif
96 
97 # if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT)
98 # error "Be sure to specify -mthreads with -D_WIN32THREADS"
99 # endif
100 
101 // With all the heuristics above, things may still go wrong, maybe even
102 // due to a specific inclusion order. So they may be overridden by
103 // manually defining the NVWA_* macros below.
104 # if NVWA_USE_CXX11_MUTEX == 0 && \
105  !defined(NVWA_WIN32THREADS) && \
106  !defined(NVWA_PTHREADS) && \
107  !defined(NVWA_NOTHREADS)
108 // _WIN32THREADS takes precedence, as some C++ libraries have _PTHREADS
109 // defined even on Win32 platforms.
110 # if defined(_WIN32THREADS)
111 # define NVWA_WIN32THREADS
112 # elif defined(_PTHREADS)
113 # define NVWA_PTHREADS
114 # else
115 # define NVWA_NOTHREADS
116 # endif
117 # endif
118 
119 # ifndef _FAST_MUTEX_CHECK_INITIALIZATION
128 # define _FAST_MUTEX_CHECK_INITIALIZATION 1
129 # endif
130 
131 # ifdef _DEBUG
132 # include <stdio.h>
133 # include <stdlib.h>
135 # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
136  if (!(_Expr)) { \
137  fprintf(stderr, "fast_mutex::%s\n", _Msg); \
138  abort(); \
139  }
140 # else
142 # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
143  ((void)0)
144 # endif
145 
146 # if NVWA_USE_CXX11_MUTEX != 0
147 # include <mutex>
153 # define __VOLATILE volatile
158  class fast_mutex
159  {
160  std::mutex _M_mtx_impl;
161 # if _FAST_MUTEX_CHECK_INITIALIZATION
162  bool _M_initialized;
163 # endif
164 # ifdef _DEBUG
165  bool _M_locked;
166 # endif
167  public:
168  fast_mutex()
169 # ifdef _DEBUG
170  : _M_locked(false)
171 # endif
172  {
173 # if _FAST_MUTEX_CHECK_INITIALIZATION
174  _M_initialized = true;
175 # endif
176  }
177  ~fast_mutex()
178  {
179  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
180 # if _FAST_MUTEX_CHECK_INITIALIZATION
181  _M_initialized = false;
182 # endif
183  }
184  void lock()
185  {
186 # if _FAST_MUTEX_CHECK_INITIALIZATION
187  if (!_M_initialized)
188  return;
189 # endif
190  _M_mtx_impl.lock();
191 # ifdef _DEBUG
192  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
193  _M_locked = true;
194 # endif
195  }
196  void unlock()
197  {
198 # if _FAST_MUTEX_CHECK_INITIALIZATION
199  if (!_M_initialized)
200  return;
201 # endif
202 # ifdef _DEBUG
203  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
204  _M_locked = false;
205 # endif
206  _M_mtx_impl.unlock();
207  }
208  private:
209  fast_mutex(const fast_mutex&);
211  };
213 # elif defined(NVWA_PTHREADS)
214 # include <pthread.h>
220 # define __VOLATILE volatile
225  class fast_mutex
226  {
227  pthread_mutex_t _M_mtx_impl;
228 # if _FAST_MUTEX_CHECK_INITIALIZATION
229  bool _M_initialized;
230 # endif
231 # ifdef _DEBUG
232  bool _M_locked;
233 # endif
234  public:
235  fast_mutex()
236 # ifdef _DEBUG
237  : _M_locked(false)
238 # endif
239  {
240  ::pthread_mutex_init(&_M_mtx_impl, _NULLPTR);
241 # if _FAST_MUTEX_CHECK_INITIALIZATION
242  _M_initialized = true;
243 # endif
244  }
245  ~fast_mutex()
246  {
247  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
248 # if _FAST_MUTEX_CHECK_INITIALIZATION
249  _M_initialized = false;
250 # endif
251  ::pthread_mutex_destroy(&_M_mtx_impl);
252  }
253  void lock()
254  {
255 # if _FAST_MUTEX_CHECK_INITIALIZATION
256  if (!_M_initialized)
257  return;
258 # endif
259  ::pthread_mutex_lock(&_M_mtx_impl);
260 # ifdef _DEBUG
261  // The following assertion should _always_ be true for a
262  // real `fast' pthread_mutex. However, this assertion can
263  // help sometimes, when people forget to use `-lpthread' and
264  // glibc provides an empty implementation. Having this
265  // assertion is also more consistent.
266  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
267  _M_locked = true;
268 # endif
269  }
270  void unlock()
271  {
272 # if _FAST_MUTEX_CHECK_INITIALIZATION
273  if (!_M_initialized)
274  return;
275 # endif
276 # ifdef _DEBUG
277  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
278  _M_locked = false;
279 # endif
280  ::pthread_mutex_unlock(&_M_mtx_impl);
281  }
282  private:
283  fast_mutex(const fast_mutex&);
285  };
287 # elif defined(NVWA_WIN32THREADS)
288 # ifndef WIN32_LEAN_AND_MEAN
289 # define WIN32_LEAN_AND_MEAN
290 # endif /* WIN32_LEAN_AND_MEAN */
291 # include <windows.h>
297 # define __VOLATILE volatile
302  class fast_mutex
303  {
304  CRITICAL_SECTION _M_mtx_impl;
305 # if _FAST_MUTEX_CHECK_INITIALIZATION
306  bool _M_initialized;
307 # endif
308 # ifdef _DEBUG
309  bool _M_locked;
310 # endif
311  public:
312  fast_mutex()
313 # ifdef _DEBUG
314  : _M_locked(false)
315 # endif
316  {
317  ::InitializeCriticalSection(&_M_mtx_impl);
318 # if _FAST_MUTEX_CHECK_INITIALIZATION
319  _M_initialized = true;
320 # endif
321  }
322  ~fast_mutex()
323  {
324  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
325 # if _FAST_MUTEX_CHECK_INITIALIZATION
326  _M_initialized = false;
327 # endif
328  ::DeleteCriticalSection(&_M_mtx_impl);
329  }
330  void lock()
331  {
332 # if _FAST_MUTEX_CHECK_INITIALIZATION
333  if (!_M_initialized)
334  return;
335 # endif
336  ::EnterCriticalSection(&_M_mtx_impl);
337 # ifdef _DEBUG
338  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
339  _M_locked = true;
340 # endif
341  }
342  void unlock()
343  {
344 # if _FAST_MUTEX_CHECK_INITIALIZATION
345  if (!_M_initialized)
346  return;
347 # endif
348 # ifdef _DEBUG
349  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
350  _M_locked = false;
351 # endif
352  ::LeaveCriticalSection(&_M_mtx_impl);
353  }
354  private:
355  fast_mutex(const fast_mutex&);
357  };
359 # elif defined(NVWA_NOTHREADS)
365 # define __VOLATILE
371  {
372 # ifdef _DEBUG
373  bool _M_locked;
374 # endif
375  public:
377 # ifdef _DEBUG
378  : _M_locked(false)
379 # endif
380  {
381  }
383  {
384  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
385  }
386  void lock()
387  {
388 # ifdef _DEBUG
389  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
390  _M_locked = true;
391 # endif
392  }
393  void unlock()
394  {
395 # ifdef _DEBUG
396  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
397  _M_locked = false;
398 # endif
399  }
400  private:
403  };
405 # endif // Definition of class fast_mutex
406 
410 {
412 public:
413  explicit fast_mutex_autolock(fast_mutex& mtx) : _M_mtx(mtx)
414  {
415  _M_mtx.lock();
416  }
418  {
419  _M_mtx.unlock();
420  }
421 private:
424 };
426 
427 #endif // NVWA_FAST_MUTEX_H
#define NVWA_NAMESPACE_BEGIN
Definition: _nvwa.h:59
#define NVWA_NAMESPACE_END
Definition: _nvwa.h:60
#define _NULLPTR
Definition: c++11.h:327
fast_mutex & _M_mtx
Definition: fast_mutex.h:411
fast_mutex_autolock(fast_mutex &mtx)
Definition: fast_mutex.h:413
fast_mutex_autolock & operator=(const fast_mutex_autolock &)
fast_mutex_autolock(const fast_mutex_autolock &)
void unlock()
Definition: fast_mutex.h:393
fast_mutex(const fast_mutex &)
fast_mutex & operator=(const fast_mutex &)
void lock()
Definition: fast_mutex.h:386
#define _FAST_MUTEX_ASSERT(_Expr, _Msg)
Definition: fast_mutex.h:142