mutex.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2008 by Marc Boris Duerner
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * As a special exception, you may use this file as part of a free
10  * software library without restriction. Specifically, if other files
11  * instantiate templates or use macros or inline functions from this
12  * file, or you compile this file and link it with other files to
13  * produce an executable, this file does not by itself cause the
14  * resulting executable to be covered by the GNU General Public
15  * License. This exception does not however invalidate any other
16  * reasons why the executable file might be covered by the GNU Library
17  * General Public License.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  */
28 #ifndef cxxtools_Mutex_h
29 #define cxxtools_Mutex_h
30 
31 #include <cxxtools/api.h>
32 #include <cxxtools/atomicity.h>
33 #include <cxxtools/noncopyable.h>
34 #include <cxxtools/thread.h>
35 
36 namespace cxxtools {
37 
46 {
47  private:
48  class MutexImpl* _impl;
49 
50  public:
52  Mutex();
53 
59  ~Mutex();
60 
68  void lock();
69 
70  bool tryLock();
71 
73  void unlock();
74 
80  bool unlockNoThrow();
81 
83  MutexImpl& impl()
84  { return *_impl; }
85 };
86 
118 class MutexLock : private NonCopyable
119 {
120  public:
128  MutexLock(Mutex& m, bool doLock = true, bool isLocked = false)
129  : _mutex(m)
130  , _isLocked(isLocked)
131  {
132  if(doLock)
133  this->lock();
134  }
135 
138  {
139  if(_isLocked)
140  _mutex.unlockNoThrow();
141  }
142 
143  void lock()
144  {
145  if(!_isLocked)
146  {
147  _mutex.lock();
148  _isLocked = true;
149  }
150  }
151 
153  void unlock()
154  {
155  if(_isLocked)
156  {
157  _mutex.unlock();
158  _isLocked = false;
159  }
160  }
161 
164  { return _mutex; }
165 
167  const Mutex& mutex() const
168  { return _mutex; }
169 
170  private:
171  Mutex& _mutex;
172  bool _isLocked;
173 };
174 
178 {
179  private:
180  class MutexImpl* _impl;
181 
182  public:
183  RecursiveMutex();
184 
185  ~RecursiveMutex();
186 
187  void lock();
188 
189  bool tryLock();
190 
197  void unlock();
198 
199  bool unlockNoThrow();
200 };
201 
204 class RecursiveLock : private NonCopyable
205 {
206  public:
214  RecursiveLock(RecursiveMutex& m, bool doLock = true, bool isLocked = false)
215  : _mutex(m)
216  , _isLocked(isLocked)
217  {
218  if(doLock)
219  this->lock();
220  }
221 
224  {
225  if(_isLocked)
226  _mutex.unlockNoThrow();
227  }
228 
229  void lock()
230  {
231  if(!_isLocked)
232  {
233  _mutex.lock();
234  _isLocked = true;
235  }
236  }
237 
239  void unlock()
240  {
241  if(_isLocked)
242  {
243  _mutex.unlock();
244  _isLocked = false;
245  }
246  }
247 
250  { return _mutex; }
251 
253  const RecursiveMutex& mutex() const
254  { return _mutex; }
255 
256  private:
257  RecursiveMutex& _mutex;
258  bool _isLocked;
259 };
260 
267 {
268  public:
270  ReadWriteMutex();
271 
273  ~ReadWriteMutex();
274 
275  void readLock();
281  bool tryReadLock();
282 
289  void writeLock();
290 
297  bool tryWriteLock();
298 
300  void unlock();
301 
302  bool unlockNoThrow();
303 
304  private:
306  class ReadWriteMutexImpl* _impl;
307 };
308 
309 
310 class ReadLock : private NonCopyable
311 {
312  public:
313  ReadLock(ReadWriteMutex& m, bool doLock = true, bool isLocked = false)
314  : _mutex(m)
315  , _locked(isLocked)
316  {
317  if(doLock)
318  this->lock();
319  }
320 
322  {
323  if(_locked)
324  _mutex.unlockNoThrow();
325  }
326 
327  void lock()
328  {
329  if( ! _locked )
330  {
331  _mutex.readLock();
332  _locked = true;
333  }
334  }
335 
336  void unlock()
337  {
338  if( _locked)
339  {
340  _mutex.unlock();
341  _locked = false;
342  }
343  }
344 
346  { return _mutex; }
347 
348  private:
349  ReadWriteMutex& _mutex;
350  bool _locked;
351 };
352 
353 
354 class WriteLock : private NonCopyable
355 {
356  public:
357  WriteLock(ReadWriteMutex& m, bool doLock = true, bool isLocked = false)
358  : _mutex(m)
359  , _locked(isLocked)
360  {
361  if(doLock)
362  this->lock();
363  }
364 
366  {
367  if(_locked)
368  _mutex.unlockNoThrow();
369  }
370 
371  void lock()
372  {
373  if( ! _locked )
374  {
375  _mutex.writeLock();
376  _locked = true;
377  }
378  }
379 
380  void unlock()
381  {
382  if( _locked)
383  {
384  _mutex.unlock();
385  _locked = false;
386  }
387  }
388 
390  { return _mutex; }
391 
392  private:
393  ReadWriteMutex& _mutex;
394  bool _locked;
395 };
396 
397 
411 class SpinMutex : private NonCopyable
412 {
413  public:
416  : _count(0)
417  {}
418 
421  {}
422 
423 
432  inline void lock()
433  {
434  // busy loop until unlock
435  while( atomicCompareExchange(_count, 1, 0) )
436  {
437  Thread::yield();
438  }
439  }
440 
441  bool tryLock()
442  {
443  return ! atomicCompareExchange(_count, 1, 0);
444  }
445 
447  void unlock()
448  {
449  // set unlocked
450  atomicExchange(_count, 0);
451  }
452 
454  bool testIsLocked() const
455  { return _count != 0; }
456 
457 private:
458  volatile cxxtools::atomic_t _count;
459 };
460 
461 
462 class SpinLock : private NonCopyable
463 {
464  public:
465  SpinLock(SpinMutex& m, bool doLock = true, bool isLocked = false)
466  : _mutex(m)
467  , _locked(isLocked)
468  {
469  if(doLock)
470  this->lock();
471  }
472 
474  {
475  if(_locked)
476  this->unlock();
477  }
478 
479  void lock()
480  {
481  if( ! _locked )
482  {
483  _mutex.lock();
484  _locked = true;
485  }
486  }
487 
488  void unlock()
489  {
490  if( _locked)
491  {
492  _mutex.unlock();
493  _locked = false;
494  }
495  }
496 
497  private:
498  SpinMutex& _mutex;
499  bool _locked;
500 };
501 
502 } // !namespace cxxtools
503 
504 #endif