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/atomicity.h>
32 #include <cxxtools/noncopyable.h>
33 #include <cxxtools/thread.h>
34 
35 namespace cxxtools {
36 
44 class Mutex : private NonCopyable
45 {
46  private:
47  class MutexImpl* _impl;
48 
49  public:
51  Mutex();
52 
58  ~Mutex();
59 
67  void lock();
68 
69  bool tryLock();
70 
72  void unlock();
73 
79  bool unlockNoThrow();
80 
82  MutexImpl& impl()
83  { return *_impl; }
84 };
85 
117 class MutexLock : private NonCopyable
118 {
119  public:
127  MutexLock(Mutex& m, bool doLock = true, bool isLocked = false)
128  : _mutex(m)
129  , _isLocked(isLocked)
130  {
131  if(doLock)
132  this->lock();
133  }
134 
137  {
138  if(_isLocked)
139  _mutex.unlockNoThrow();
140  }
141 
142  void lock()
143  {
144  if(!_isLocked)
145  {
146  _mutex.lock();
147  _isLocked = true;
148  }
149  }
150 
152  void unlock()
153  {
154  if(_isLocked)
155  {
156  _mutex.unlock();
157  _isLocked = false;
158  }
159  }
160 
163  { return _mutex; }
164 
166  const Mutex& mutex() const
167  { return _mutex; }
168 
169  private:
170  Mutex& _mutex;
171  bool _isLocked;
172 };
173 
177 {
178  private:
179  class MutexImpl* _impl;
180 
181  public:
182  RecursiveMutex();
183 
184  ~RecursiveMutex();
185 
186  void lock();
187 
188  bool tryLock();
189 
196  void unlock();
197 
198  bool unlockNoThrow();
199 };
200 
203 class RecursiveLock : private NonCopyable
204 {
205  public:
213  RecursiveLock(RecursiveMutex& m, bool doLock = true, bool isLocked = false)
214  : _mutex(m)
215  , _isLocked(isLocked)
216  {
217  if(doLock)
218  this->lock();
219  }
220 
223  {
224  if(_isLocked)
225  _mutex.unlockNoThrow();
226  }
227 
228  void lock()
229  {
230  if(!_isLocked)
231  {
232  _mutex.lock();
233  _isLocked = true;
234  }
235  }
236 
238  void unlock()
239  {
240  if(_isLocked)
241  {
242  _mutex.unlock();
243  _isLocked = false;
244  }
245  }
246 
249  { return _mutex; }
250 
252  const RecursiveMutex& mutex() const
253  { return _mutex; }
254 
255  private:
256  RecursiveMutex& _mutex;
257  bool _isLocked;
258 };
259 
266 {
267  public:
269  ReadWriteMutex();
270 
272  ~ReadWriteMutex();
273 
274  void readLock();
280  bool tryReadLock();
281 
288  void writeLock();
289 
296  bool tryWriteLock();
297 
299  void unlock();
300 
301  bool unlockNoThrow();
302 
303  private:
305  class ReadWriteMutexImpl* _impl;
306 };
307 
308 
309 class ReadLock : private NonCopyable
310 {
311  public:
312  ReadLock(ReadWriteMutex& m, bool doLock = true, bool isLocked = false)
313  : _mutex(m)
314  , _locked(isLocked)
315  {
316  if(doLock)
317  this->lock();
318  }
319 
321  {
322  if(_locked)
323  _mutex.unlockNoThrow();
324  }
325 
326  void lock()
327  {
328  if( ! _locked )
329  {
330  _mutex.readLock();
331  _locked = true;
332  }
333  }
334 
335  void unlock()
336  {
337  if( _locked)
338  {
339  _mutex.unlock();
340  _locked = false;
341  }
342  }
343 
345  { return _mutex; }
346 
347  private:
348  ReadWriteMutex& _mutex;
349  bool _locked;
350 };
351 
352 
353 class WriteLock : private NonCopyable
354 {
355  public:
356  WriteLock(ReadWriteMutex& m, bool doLock = true, bool isLocked = false)
357  : _mutex(m)
358  , _locked(isLocked)
359  {
360  if(doLock)
361  this->lock();
362  }
363 
365  {
366  if(_locked)
367  _mutex.unlockNoThrow();
368  }
369 
370  void lock()
371  {
372  if( ! _locked )
373  {
374  _mutex.writeLock();
375  _locked = true;
376  }
377  }
378 
379  void unlock()
380  {
381  if( _locked)
382  {
383  _mutex.unlock();
384  _locked = false;
385  }
386  }
387 
389  { return _mutex; }
390 
391  private:
392  ReadWriteMutex& _mutex;
393  bool _locked;
394 };
395 
396 
410 class SpinMutex : private NonCopyable
411 {
412  public:
415  : _count(0)
416  {}
417 
420  {}
421 
422 
431  inline void lock()
432  {
433  // busy loop until unlock
434  while( atomicCompareExchange(_count, 1, 0) )
435  {
436  Thread::yield();
437  }
438  }
439 
440  bool tryLock()
441  {
442  return ! atomicCompareExchange(_count, 1, 0);
443  }
444 
446  void unlock()
447  {
448  // set unlocked
449  atomicExchange(_count, 0);
450  }
451 
453  bool testIsLocked() const
454  { return _count != 0; }
455 
456 private:
457  volatile cxxtools::atomic_t _count;
458 };
459 
460 
461 class SpinLock : private NonCopyable
462 {
463  public:
464  SpinLock(SpinMutex& m, bool doLock = true, bool isLocked = false)
465  : _mutex(m)
466  , _locked(isLocked)
467  {
468  if(doLock)
469  this->lock();
470  }
471 
473  {
474  if(_locked)
475  this->unlock();
476  }
477 
478  void lock()
479  {
480  if( ! _locked )
481  {
482  _mutex.lock();
483  _locked = true;
484  }
485  }
486 
487  void unlock()
488  {
489  if( _locked)
490  {
491  _mutex.unlock();
492  _locked = false;
493  }
494  }
495 
496  private:
497  SpinMutex& _mutex;
498  bool _locked;
499 };
500 
501 } // !namespace cxxtools
502 
503 #endif