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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3765 - (hide 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 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3765 * Copyright (C) 2005 - 2020 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 3765 // 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 senoner 1481 #if defined(WIN32)
32     #include <windows.h>
33     #else
34 schoenebeck 53 #include <pthread.h>
35 senoner 1481 #endif
36 schoenebeck 53
37 schoenebeck 880 namespace LinuxSampler {
38    
39 schoenebeck 550 /** @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 schoenebeck 53 class Mutex {
52     public:
53 schoenebeck 3290 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 schoenebeck 550 */
88 schoenebeck 3290 Mutex(type_t type = RECURSIVE);
89 schoenebeck 550
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 schoenebeck 53 void Lock();
107 schoenebeck 550
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 senkov 165 bool Trylock();
120 schoenebeck 550
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 schoenebeck 53 void Unlock();
127 persson 2427
128 schoenebeck 3765 #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 schoenebeck 53 protected:
153 senoner 1481 #if defined(WIN32)
154 persson 2427 HANDLE hMutex;
155 senoner 1481 #else
156 schoenebeck 53 pthread_mutex_t __posix_mutex;
157     pthread_mutexattr_t __posix_mutexattr;
158 senoner 1481 #endif
159 schoenebeck 3290 type_t type;
160 schoenebeck 3765 #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 schoenebeck 53 };
167    
168 persson 2427 // Lock guard for exception safe locking
169     class LockGuard {
170     public:
171 schoenebeck 2500 LockGuard(Mutex& m) : pm(&m) {
172 persson 2427 m.Lock();
173     }
174 schoenebeck 2500
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 schoenebeck 2501 LockGuard(const LockGuard& g) : pm(g.pm) {
188 schoenebeck 2500 if (pm) pm->Lock();
189     }
190    
191 persson 2427 ~LockGuard() {
192 schoenebeck 2500 if (pm) pm->Unlock();
193 persson 2427 }
194     private:
195 schoenebeck 2500 Mutex* pm;
196 persson 2427 };
197    
198 schoenebeck 880 } // namespace LinuxSampler
199    
200 schoenebeck 53 #endif // __MUTEX_H__

  ViewVC Help
Powered by ViewVC