casa  5.7.0-16
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Mutex.h
Go to the documentation of this file.
1 //# Mutex.h: Classes to handle mutexes and (un)locking
2 //# Copyright (C) 2011,2016
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //# $Id$
27 
28 #ifndef CASA_MUTEX_H
29 #define CASA_MUTEX_H
30 
31 #include <casacore/casa/aips.h>
32 
33 #include <cerrno>
34 #include <mutex>
35 #include <atomic>
36 #ifdef USE_THREADS
37 # include <pthread.h>
38 #endif
39 
41 
42 //# Mostly copied from the LOFAR software.
43 
44 namespace casacore {
45 
46  // <summary>Wrapper around a pthreads mutex</summary>
47  // <use visibility=export>
48  //
49  // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
50  // </reviewed>
51  //
52  // <synopsis>
53  // This class is a wrapper around a pthreads mutex.
54  // <br>Although the Mutex class has a lock function, class ScopedMutexLock
55  // should be used to obtain a lock, because it makes locking exception-safe.
56  // </synopsis>
57 
58  class Mutex
59  {
60  public:
61  // Define the type of mutex.
62  // (see phtread_mutexattr_settype for their meaning).
63  // In Debug mode, type Auto will use PTHREAD_MUTEX_ERRORCHECK,
64  // otherwise PTHREAD_MUTEX_DEFAULT.
66 
67 #ifdef USE_THREADS
68 
69  // Create the mutex.
70  Mutex (Type type=Auto);
71 
72  // Destroy the mutex.
73  // declaring noexcept(false) to squash compiler warning, although note
74  // that it is usually a bad idea for destructors to throw exceptions
75  ~Mutex() noexcept(false);
76 
77  // Lock the mutex. It blocks until it can get exclusive access to the lock.
78  void lock()
79  {
80  int error = pthread_mutex_lock(&itsMutex);
81  if (AIPS_UNLIKELY(error != 0)) {
82  throw SystemCallError("pthread_mutex_lock", error);
83  }
84  }
85 
86  // Unlock the mutex.
87  void unlock()
88  {
89  int error = pthread_mutex_unlock(&itsMutex);
90  if (AIPS_UNLIKELY(error != 0)) {
91  // Terminates if in a destructor during exception, but acceptable,
92  // since it would be a serious bug hopefully exposed by a test case.
93  throw SystemCallError("pthread_mutex_unlock", error);
94  }
95  }
96 
97  // Try to lock the mutex. True is returned if it succeeded.
98  bool trylock()
99  {
100  int error = pthread_mutex_trylock(&itsMutex);
101  if (error == 0) {
102  return true;
103  } else if (error == EBUSY ||
104  error == EDEADLK) { // returned by ErrorCheck mutex
105  return false;
106  } else {
107  throw SystemCallError("pthread_mutex_trylock", error);
108  }
109  }
110 
111 #else
112 
114  ~Mutex() { }
115  void lock() { }
116  void unlock() { }
117  bool trylock() { return true; }
118 
119 #endif
120 
121  private:
122  // Forbid copy constructor.
123  Mutex (const Mutex&);
124  // Forbid assignment.
125  Mutex& operator= (const Mutex&);
126 
127  //# Data members
128 #ifdef USE_THREADS
129  pthread_mutex_t itsMutex;
130 #endif
131  };
132 
133 
134  // <summary>Exception-safe lock/unlock of a mutex</summary>
135  // <use visibility=export>
136  //
137  // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
138  // </reviewed>
139  //
140  // <synopsis>
141  // The constructor of this class locks a mutex, while the destructor
142  // unlocks it. In this way the user does not need to take care of
143  // unlocking a mutex and is mutex locking fully exception-safe
144  // </synopsis>
145 
147  {
148  public:
149  // Create a lock on the mutex.
151  : itsMutexRef(mutex)
152  { itsMutexRef.lock(); }
153 
154  // The destructor automatically unlocks the mutex.
156  { itsMutexRef.unlock(); }
157 
158  private:
159  // Forbid copy constructor.
161  // Forbid assignment.
163 
165  };
166 
167 
168  // <summary>Wrapper around std::call_once
169  // </summary>
170  // <use visibility=export>
171  //
172  // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
173  // </reviewed>
174  //
175  // <synopsis>
176  // Ease correct lazy initialization of static data in the easy cases.
177  // <br>
178  // Often data needs to be initialized once and accessed many times. To do
179  // this in a thread-safe way, a mutex is expensive, and basic double-checked
180  // locking is not fully thread-safe.
181  // The C++ function std::call_once offers the required functionality.
182  // The classes CallOnce and CallOnce0 are a little wrappers around this
183  // function to call it with 0 or 1 argument.
184  // </synopsis>
185  //
186  // <example>
187  // (Note that this simple case can also be solved with C++11 thread-safe
188  // initialization of function statics (can be slightly more efficient).)
189  // all under namespace casacore:
190  // .h:
191  // class A {
192  // static std::vector<int> theirSharedInts;
193  // static CallOnce theirInitOnce;
194  // void initX();
195  //
196  // public:
197  // int getX(size_t idx);
198  // };
199  // .cc:
200  // vector<int> A::theirSharedInts(1);
201  // CallOnce A::theirInitOnce;
202  //
203  // void A::initX(int val) {
204  // theirSharedInts[0] = val;
205  // }
206  //
207  // int A::getX(size_t idx) {
208  // theirInitOnce(initX, 42);
209  // return theirSharedInts.at(idx);
210  // }
211  // </example>
212 
213  // CallOnce0: func has 0 args.
214  class CallOnce0
215  {
216  public:
218  {
219 #ifndef USE_THREADS
220  itsFlag = True;
221 #endif
222  }
223 
224  void operator()(void (*fn)()) {
225  //# call_once does not work properly without threads.
226 #ifdef USE_THREADS
227  std::call_once(itsFlag, fn);
228 #else
229  if (itsFlag) {
230  fn();
231  itsFlag = False;
232  }
233 #endif
234  }
235 
236 private:
237  // Forbid copy constructor.
238  CallOnce0(const CallOnce0&);
239  // Forbid assignment.
240  CallOnce0& operator= (const CallOnce0&);
241 
242 #ifdef USE_THREADS
243  std::once_flag itsFlag;
244 #else
246 #endif
247  };
248 
249  // CallOnce: func has one arg.
250  // One arg can also be used as an output or to refer to an object (more args).
251  class CallOnce
252  {
253  public:
255  {
256 #ifndef USE_THREADS
257  itsFlag = True;
258 #endif
259  }
260 
261  template<typename T>
262  void operator()(void (*fn)(T), T t) {
263 #ifdef USE_THREADS
264  std::call_once(itsFlag, fn, t);
265 #else
266  if (itsFlag) {
267  fn(t);
268  itsFlag = False;
269  }
270 #endif
271  }
272 
273  private:
274  // Forbid copy constructor.
275  CallOnce(const CallOnce&);
276  // Forbid assignment.
277  CallOnce& operator= (const CallOnce&);
278 
279 #ifdef USE_THREADS
280  std::once_flag itsFlag;
281 #else
283 #endif
284  };
285 
286 } // namespace casacore
287 
288 #endif
Wrapper around std::call_once.
Definition: Mutex.h:214
void operator()(void(*fn)(T), T t)
Definition: Mutex.h:262
void unlock()
Definition: Mutex.h:116
Type
Define the type of mutex.
Definition: Mutex.h:65
~ScopedMutexLock()
The destructor automatically unlocks the mutex.
Definition: Mutex.h:155
virtual casacore::String type() const
Implements RegionShape::type.
Definition: RegionShapes.h:548
void lock()
Definition: Mutex.h:115
ScopedMutexLock(Mutex &mutex)
Create a lock on the mutex.
Definition: Mutex.h:150
#define AIPS_UNLIKELY(x)
Definition: aipsenv.h:248
CallOnce: func has one arg.
Definition: Mutex.h:251
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
CallOnce0 & operator=(const CallOnce0 &)
Forbid assignment.
ScopedMutexLock & operator=(const ScopedMutexLock &)
Forbid assignment.
Mutex & operator=(const Mutex &)
Forbid assignment.
bool trylock()
Definition: Mutex.h:117
CallOnce & operator=(const CallOnce &)
Forbid assignment.
const Bool False
Definition: aipstype.h:44
Mutex(Mutex::Type=Auto)
Definition: Mutex.h:113
Wrapper around a pthreads mutex.
Definition: Mutex.h:58
Exception-safe lock/unlock of a mutex.
Definition: Mutex.h:146
const Bool True
Definition: aipstype.h:43
Exception for an error in a system call.
Definition: Error.h:434
void operator()(void(*fn)())
Definition: Mutex.h:224
#define casacore
&lt;X11/Intrinsic.h&gt; #defines true, false, casacore::Bool, and String.
Definition: X11Intrinsic.h:42