SUMO - Simulation of Urban MObility
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-2013 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 "_nvwa.h" // NVWA_NAMESPACE_*
41 #include "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(_WIN32) && defined(_MT) && \
46  (!defined(_MSC_VER) || defined(_DLL))
47 // Prefer using std::mutex on Windows to avoid the namespace
48 // pollution caused by <windows.h>. However, MSVC has a re-entry
49 // issue with its std::mutex implementation, and std::mutex should
50 // not be used unless /MD or /MDd is used. For more information,
51 // check out:
52 //
53 // https://connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag
54 // http://stackoverflow.com/questions/14319344/stdmutex-lock-hangs-when-overriding-the-new-operator
55 //
56 # define NVWA_USE_CXX11_MUTEX 1
57 # endif
58 
59 # if !defined(_WIN32THREADS) && \
60  (defined(_WIN32) && defined(_MT))
61 // Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC,
62 // or -mthreads in MinGW GCC.
63 # define _WIN32THREADS
64 # elif !defined(_PTHREADS) && \
65  defined(_REENTRANT)
66 // Automatically use _PTHREADS when specifying -pthread in GCC or Clang.
67 # define _PTHREADS
68 # endif
69 # endif
70 
71 # ifndef NVWA_USE_CXX11_MUTEX
72 # define NVWA_USE_CXX11_MUTEX 0
73 # endif
74 
75 # if !defined(_PTHREADS) && !defined(_WIN32THREADS) && \
76  !defined(_NOTHREADS) && NVWA_USE_CXX11_MUTEX == 0
77 # define _NOTHREADS
78 # endif
79 
80 # if defined(_NOTHREADS)
81 # if defined(_PTHREADS) || defined(_WIN32THREADS) || \
82  NVWA_USE_CXX11_MUTEX != 0
83 # undef _NOTHREADS
84 # error "Cannot define multi-threaded mode with -D_NOTHREADS"
85 # endif
86 # endif
87 
88 # if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT)
89 # error "Be sure to specify -mthreads with -D_WIN32THREADS"
90 # endif
91 
92 # ifndef _FAST_MUTEX_CHECK_INITIALIZATION
93 
101 # define _FAST_MUTEX_CHECK_INITIALIZATION 1
102 # endif
103 
104 # if defined(_PTHREADS) && defined(_WIN32THREADS)
105 // Some C++ libraries have _PTHREADS defined even on Win32 platforms.
106 // Thus this hack.
107 # undef _PTHREADS
108 # endif
109 
110 # ifdef _DEBUG
111 # include <stdio.h>
112 # include <stdlib.h>
114 # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
115  if (!(_Expr)) { \
116  fprintf(stderr, "fast_mutex::%s\n", _Msg); \
117  abort(); \
118  }
119 # else
120 
121 # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
122  ((void)0)
123 # endif
124 
125 # if NVWA_USE_CXX11_MUTEX != 0
126 # include <mutex>
127 NVWA_NAMESPACE_BEGIN
132 # define __VOLATILE volatile
133 
137  class fast_mutex
138  {
139  std::mutex _M_mtx_impl;
140 # if _FAST_MUTEX_CHECK_INITIALIZATION
141  bool _M_initialized;
142 # endif
143 # ifdef _DEBUG
144  bool _M_locked;
145 # endif
146  public:
147  fast_mutex()
148 # ifdef _DEBUG
149  : _M_locked(false)
150 # endif
151  {
152 # if _FAST_MUTEX_CHECK_INITIALIZATION
153  _M_initialized = true;
154 # endif
155  }
156  ~fast_mutex()
157  {
158  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
159 # if _FAST_MUTEX_CHECK_INITIALIZATION
160  _M_initialized = false;
161 # endif
162  }
163  void lock()
164  {
165 # if _FAST_MUTEX_CHECK_INITIALIZATION
166  if (!_M_initialized)
167  return;
168 # endif
169  _M_mtx_impl.lock();
170 # ifdef _DEBUG
171  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
172  _M_locked = true;
173 # endif
174  }
175  void unlock()
176  {
177 # if _FAST_MUTEX_CHECK_INITIALIZATION
178  if (!_M_initialized)
179  return;
180 # endif
181 # ifdef _DEBUG
182  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
183  _M_locked = false;
184 # endif
185  _M_mtx_impl.unlock();
186  }
187  private:
188  fast_mutex(const fast_mutex&);
190  };
191 NVWA_NAMESPACE_END
192 # endif // NVWA_USE_CXX11_MUTEX != 0
193 
194 # if defined(_PTHREADS) && NVWA_USE_CXX11_MUTEX == 0
195 # include <pthread.h>
196 NVWA_NAMESPACE_BEGIN
201 # define __VOLATILE volatile
202 
206  class fast_mutex
207  {
208  pthread_mutex_t _M_mtx_impl;
209 # if _FAST_MUTEX_CHECK_INITIALIZATION
210  bool _M_initialized;
211 # endif
212 # ifdef _DEBUG
213  bool _M_locked;
214 # endif
215  public:
216  fast_mutex()
217 # ifdef _DEBUG
218  : _M_locked(false)
219 # endif
220  {
221  ::pthread_mutex_init(&_M_mtx_impl, NULL);
222 # if _FAST_MUTEX_CHECK_INITIALIZATION
223  _M_initialized = true;
224 # endif
225  }
226  ~fast_mutex()
227  {
228  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
229 # if _FAST_MUTEX_CHECK_INITIALIZATION
230  _M_initialized = false;
231 # endif
232  ::pthread_mutex_destroy(&_M_mtx_impl);
233  }
234  void lock()
235  {
236 # if _FAST_MUTEX_CHECK_INITIALIZATION
237  if (!_M_initialized)
238  return;
239 # endif
240  ::pthread_mutex_lock(&_M_mtx_impl);
241 # ifdef _DEBUG
242  // The following assertion should _always_ be true for a
243  // real `fast' pthread_mutex. However, this assertion can
244  // help sometimes, when people forget to use `-lpthread' and
245  // glibc provides an empty implementation. Having this
246  // assertion is also more consistent.
247  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
248  _M_locked = true;
249 # endif
250  }
251  void unlock()
252  {
253 # if _FAST_MUTEX_CHECK_INITIALIZATION
254  if (!_M_initialized)
255  return;
256 # endif
257 # ifdef _DEBUG
258  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
259  _M_locked = false;
260 # endif
261  ::pthread_mutex_unlock(&_M_mtx_impl);
262  }
263  private:
264  fast_mutex(const fast_mutex&);
266  };
267 NVWA_NAMESPACE_END
268 # endif // _PTHREADS
269 
270 # if defined(_WIN32THREADS) && NVWA_USE_CXX11_MUTEX == 0
271 # ifndef WIN32_LEAN_AND_MEAN
272 # define WIN32_LEAN_AND_MEAN
273 # endif /* WIN32_LEAN_AND_MEAN */
274 # include <windows.h>
275 NVWA_NAMESPACE_BEGIN
280 # define __VOLATILE volatile
281 
285  class fast_mutex
286  {
287  CRITICAL_SECTION _M_mtx_impl;
288 # if _FAST_MUTEX_CHECK_INITIALIZATION
289  bool _M_initialized;
290 # endif
291 # ifdef _DEBUG
292  bool _M_locked;
293 # endif
294  public:
295  fast_mutex()
296 # ifdef _DEBUG
297  : _M_locked(false)
298 # endif
299  {
300  ::InitializeCriticalSection(&_M_mtx_impl);
301 # if _FAST_MUTEX_CHECK_INITIALIZATION
302  _M_initialized = true;
303 # endif
304  }
305  ~fast_mutex()
306  {
307  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
308 # if _FAST_MUTEX_CHECK_INITIALIZATION
309  _M_initialized = false;
310 # endif
311  ::DeleteCriticalSection(&_M_mtx_impl);
312  }
313  void lock()
314  {
315 # if _FAST_MUTEX_CHECK_INITIALIZATION
316  if (!_M_initialized)
317  return;
318 # endif
319  ::EnterCriticalSection(&_M_mtx_impl);
320 # ifdef _DEBUG
321  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
322  _M_locked = true;
323 # endif
324  }
325  void unlock()
326  {
327 # if _FAST_MUTEX_CHECK_INITIALIZATION
328  if (!_M_initialized)
329  return;
330 # endif
331 # ifdef _DEBUG
332  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
333  _M_locked = false;
334 # endif
335  ::LeaveCriticalSection(&_M_mtx_impl);
336  }
337  private:
338  fast_mutex(const fast_mutex&);
340  };
341 NVWA_NAMESPACE_END
342 # endif // _WIN32THREADS
343 
344 # ifdef _NOTHREADS
345 NVWA_NAMESPACE_BEGIN
350 # define __VOLATILE
351 
356  {
357 # ifdef _DEBUG
358  bool _M_locked;
359 # endif
360  public:
362 # ifdef _DEBUG
363  : _M_locked(false)
364 # endif
365  {
366  }
368  {
369  _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
370  }
371  void lock()
372  {
373 # ifdef _DEBUG
374  _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
375  _M_locked = true;
376 # endif
377  }
378  void unlock()
379  {
380 # ifdef _DEBUG
381  _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
382  _M_locked = false;
383 # endif
384  }
385  private:
386  fast_mutex(const fast_mutex&);
388  };
389 NVWA_NAMESPACE_END
390 # endif // _NOTHREADS
391 
392 NVWA_NAMESPACE_BEGIN
395 {
397 public:
398  explicit fast_mutex_autolock(fast_mutex& mtx) : _M_mtx(mtx)
399  {
400  _M_mtx.lock();
401  }
403  {
404  _M_mtx.unlock();
405  }
406 private:
409 };
410 NVWA_NAMESPACE_END
411 
412 #endif // NVWA_FAST_MUTEX_H
void lock()
Definition: fast_mutex.h:371
fast_mutex_autolock(fast_mutex &mtx)
Definition: fast_mutex.h:398
fast_mutex & operator=(const fast_mutex &)
#define _FAST_MUTEX_ASSERT(_Expr, _Msg)
Definition: fast_mutex.h:121
fast_mutex & _M_mtx
Definition: fast_mutex.h:396
void unlock()
Definition: fast_mutex.h:378