/[svn]/linuxsampler/trunk/src/common/Mutex.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/Mutex.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3765 - (show annotations) (download) (as text)
Mon Apr 6 09:46:52 2020 UTC (4 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 8136 byte(s)
Mutex class: Implemented bug detection and deadlock debugging features.

* Bug detection: By enabling macro DEBUG_MUTEX at compile time and
  calling new method setDebugEnabled(true) at runtime, automatic bug
  detection features are activated which e.g. raise an assertion fault
  if a thread attempts to Unlock() a thread it does not own a lock on,
  or when locking more than once while not using mutex type RECURSIVE
  and much more.

* Deadlock debugging: Also if these features were activated like
  described above, the most recent mutex lock is recorded by capturing
  the name of the thread and the precise call stack which caused the
  mutex lock. This information can be used to identify the exact
  situation that lead to a dead lock efficiently with a debugger.

* Bumped version (2.1.1.svn53).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2020 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef __MUTEX_H__
25 #define __MUTEX_H__
26
27 // enable this for detecting mutex misusage and for debugging dead locks
28 // (these features then still need to be enabled by Mutex::setDebugEnabled())
29 //#define DEBUG_MUTEX 1
30
31 #if defined(WIN32)
32 #include <windows.h>
33 #else
34 #include <pthread.h>
35 #endif
36
37 namespace LinuxSampler {
38
39 /** @brief Mutual exclusive objects
40 *
41 * This class provides the classical thread / process synchronisation
42 * technique called Mutex. It is used to protect critical sections, that is
43 * resources (typically data structures) from being used at the same time by
44 * different threads or processes which otherwise might turn into undefined
45 * and of course undesired behavior.
46 *
47 * Note: as this technique might block the calling thread and also implies
48 * a system call, this should not be used directly in realtime sensitive
49 * threads!
50 */
51 class Mutex {
52 public:
53 enum type_t {
54 RECURSIVE,
55 NON_RECURSIVE
56 };
57
58 /** @brief Constructor
59 *
60 * Creates a new Mutex object. The optional @a type argument defines
61 * the fundamental behavior of the Mutex object:
62 *
63 * - If @c RECURSIVE is passed (which is the default type) then the
64 * mutex will manage an additional lock count such that it allows the
65 * same thread to call Lock() multiple times; each time that thread
66 * calls Lock() the lock count will be increased by one, each time it
67 * calls Unlock() it will be decreased by one, and other threads will
68 * only be unblocked once the lock count fell to zero again.
69 *
70 * - If @c NON_RECURSIVE is passed then it is considered to be an error
71 * if the same thread calls Lock() while already owning the lock, and
72 * likewise it is considered to be an error if Unlock() is called if
73 * the calling thread hasn't locked the mutex.
74 *
75 * You should invest the required time to review your design in order to
76 * decide which mutex behavior fits to your design. Even though it might
77 * be tempting to stick with the lazy approach by using the @c RECURSIVE
78 * type, using the @c NON_RECURSIVE type does make sense if your design
79 * does not require a recursive mutex, because modern developer tools
80 * assist you spotting potential threading bugs in your code while using
81 * the @c NON_RECURSIVE type which can avoid developers' biggest fear of
82 * undefined behavior, plus also keep in mind that certain OS APIs are
83 * not compatible with recursive mutexes at all!
84 *
85 * @param type - optional: the fundamental behavior type for this mutex
86 * (default: @c RECURSIVE)
87 */
88 Mutex(type_t type = RECURSIVE);
89
90 /**
91 * Destructor
92 */
93 virtual ~Mutex();
94
95 /** @brief Lock this Mutex.
96 *
97 * If this Mutex object is currently be locked by another thread,
98 * then the calling thread will be blocked until the other thread
99 * unlocks this Mutex object. The calling thread though can safely
100 * call this method several times without danger to be blocked
101 * himself.
102 *
103 * The calling thread should call Unlock() as soon as the critical
104 * section was left.
105 */
106 void Lock();
107
108 /** @brief Try to lock this Mutex.
109 *
110 * Same as Lock() except that this method won't block the calling
111 * thread in case this Mutex object is currently locked by another
112 * thread. So this call will always immediately return and the
113 * return value has to be checked if the locking request was
114 * successful or not.
115 *
116 * @returns true if the Mutex object could be locked, false if the
117 * Mutex is currently locked by another thread
118 */
119 bool Trylock();
120
121 /** @brief Unlock this Mutex.
122 *
123 * If other threads are currently blocked and waiting due to a
124 * Lock() call, one of them will be awaken.
125 */
126 void Unlock();
127
128 #if DEBUG_MUTEX
129 /** @brief Enable bug detection and debugging features.
130 *
131 * By passing @c true to this method, bug detection and debugging features
132 * will be enabled for this Mutex object. For instance this will trigger an
133 * assertion fault if a thread attempts to Unlock() a thread it does not own
134 * a lock on, or when locking more than once while not using mutex type
135 * @c RECURSIVE and much more. Additionally this will also record the name
136 * of the thread currently holding a lock, and the backtrace of that
137 * thread's lock. The latter information can then be used to debug
138 * deadlocks.
139 *
140 * By default this is turned off and must be enabled for individual Mutex
141 * objects, because otherwise it would cause a large number of false
142 * positives (i.e. in certain edge cases like thread constructors /
143 * destructors for instance).
144 *
145 * @param b - whether to enable bug detection / debugging features
146 */
147 void setDebugEnabled(bool b) {
148 debugSelf = b;
149 }
150 #endif
151
152 protected:
153 #if defined(WIN32)
154 HANDLE hMutex;
155 #else
156 pthread_mutex_t __posix_mutex;
157 pthread_mutexattr_t __posix_mutexattr;
158 #endif
159 type_t type;
160 #if DEBUG_MUTEX
161 std::string owner; ///< Name of the thread owning the current lock.
162 long long int count; ///< How many times the owner currently acquired the lock recursively.
163 std::string backtrace; ///< Call stack trace of (last) lock.
164 bool debugSelf; ///< Whether bug detection and debugging features are enabled.
165 #endif
166 };
167
168 // Lock guard for exception safe locking
169 class LockGuard {
170 public:
171 LockGuard(Mutex& m) : pm(&m) {
172 m.Lock();
173 }
174
175 /**
176 * Empty LockGuard. This constructor can be used to implement conditional
177 * mutex protection like:
178 * @code
179 * Mutex m;
180 * LockGuard g;
181 * if (requiresMutexProtection()) g = LockGuard(m);
182 * @endcode
183 */
184 LockGuard() : pm(NULL) {
185 }
186
187 LockGuard(const LockGuard& g) : pm(g.pm) {
188 if (pm) pm->Lock();
189 }
190
191 ~LockGuard() {
192 if (pm) pm->Unlock();
193 }
194 private:
195 Mutex* pm;
196 };
197
198 } // namespace LinuxSampler
199
200 #endif // __MUTEX_H__

  ViewVC Help
Powered by ViewVC