casa
$Rev:20696$
|
00001 //# Mutex.h: Classes to handle mutexes and (un)locking 00002 //# Copyright (C) 2011 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: Mutex.h 21100 2011-06-28 12:49:00Z gervandiepen $ 00027 00028 #ifndef CASA_MUTEX_H 00029 #define CASA_MUTEX_H 00030 00031 #include <casa/aips.h> 00032 00033 //# Mostly copied from the LOFAR software. 00034 00035 namespace casa { 00036 00037 // <summary>Wrapper around a pthreads mutex</summary> 00038 // <use visibility=export> 00039 // 00040 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos=""> 00041 // </reviewed> 00042 // 00043 // <synopsis> 00044 // This class is a wrapper around a phtreads mutex. 00045 // <br>Although the Mutex class has a lock function, class ScopedMutexLock 00046 // should be used to obtain a lock, because it makes locking exception-safe. 00047 // </synopsis> 00048 00049 class Mutex 00050 { 00051 public: 00052 // Define the type of mutex. 00053 // (see phtread_mutexattr_settype for their meaning). 00054 // In Debug mode, type Auto will use PTHREAD_MUTEX_ERRORCHECK, 00055 // otherwise PTHREAD_MUTEX_DEFAULT. 00056 enum Type {Normal, ErrorCheck, Recursive, Default, Auto}; 00057 00058 // Create the mutex. 00059 Mutex (Type type=Auto); 00060 00061 // Destroy the mutex. 00062 ~Mutex(); 00063 00064 // Set a lock on the mutex. It waits till it gets the lock. 00065 void lock(); 00066 00067 // Unlock the mutex. 00068 void unlock(); 00069 00070 // Try to lock the mutex. True is returned if it succeeded. 00071 bool trylock(); 00072 00073 private: 00074 // Forbid copy constructor. 00075 Mutex (const Mutex&); 00076 // Forbid assignment. 00077 Mutex& operator= (const Mutex&); 00078 00079 //# Data members 00080 //# Use void*, because we cannot forward declare pthread_mutex_t. 00081 void* itsMutex; 00082 }; 00083 00084 00085 // <summary>Exception-safe lock/unlock of a mutex</summary> 00086 // <use visibility=export> 00087 // 00088 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos=""> 00089 // </reviewed> 00090 // 00091 // <synopsis> 00092 // The constructor of this class locks a mutex, while the destructor 00093 // unlocks it. In this way the user does not need to take care of 00094 // unlocking a mutex and is mutex locking fully exception-safe 00095 // </synopsis> 00096 00097 class ScopedMutexLock 00098 { 00099 public: 00100 // Create a lock on the mutex. 00101 ScopedMutexLock (Mutex& mutex) 00102 : itsMutexRef(mutex) 00103 { itsMutexRef.lock(); } 00104 00105 // The destructor automatically unlocks the mutex. 00106 ~ScopedMutexLock() 00107 { itsMutexRef.unlock(); } 00108 00109 private: 00110 // Forbid copy constructor. 00111 ScopedMutexLock (const ScopedMutexLock&); 00112 // Forbid assignment. 00113 ScopedMutexLock& operator= (const ScopedMutexLock&); 00114 00115 Mutex& itsMutexRef; 00116 }; 00117 00118 00119 // <summary>Thread-safe initialization of global variables</summary> 00120 // <use visibility=export> 00121 // 00122 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos=""> 00123 // </reviewed> 00124 // 00125 // <synopsis> 00126 // This class does a double checked lock. 00127 // <br> 00128 // Often data needs to be initialized once and accessed many times. To do 00129 // this in a thread-safe way, a mutex lock needs to be used. However, that 00130 // is relatively expensive. 00131 // The double checked lock idiom overcomes this problem. A Bool flag tells 00132 // if an operation needs to be done. If so, a lock is set and the flag is 00133 // tested again in case another thread happened to do the operation between 00134 // the test and acquiring the lock. 00135 // At the end of the operation the flag is cleared. 00136 // 00137 // 00138 // The flag needs to be declared volatile to avoid execution ordering 00139 // problems in case a compiler optimizes too much. 00140 // <note role-warning> 00141 // This idiom is not fully portable, because on more exotic machines the 00142 // caches in different cores may not be synchronized well. 00143 // </note> 00144 // </synopsis> 00145 // 00146 // <example> 00147 // <srcblock> 00148 // // Declare static variables. 00149 // static volatile Bool needInit = True; 00150 // static Mutex mutex; 00151 // // Execute the code in a scope, so the destructor is called automatically. 00152 // { 00153 // CheckedMutexLock locker(mutex, needInit); 00154 // if (locker.doIt()) { 00155 // .. do the initialization 00156 // } 00157 // } 00158 // </srcblock> 00159 // </example> 00160 00161 class MutexedInit 00162 { 00163 public: 00164 // Define the initialization function to call. 00165 typedef void InitFunc (void*); 00166 00167 // Create the mutex and set that the initialization should be done. 00168 MutexedInit (InitFunc* func, void* arg=0, Mutex::Type type=Mutex::Auto); 00169 00170 // Execute the initialization function if not done yet. 00171 void exec() 00172 { if (itsDoExec) doExec(); } 00173 00174 // Get the mutex (to make it possible to lock for other purposes). 00175 Mutex& mutex() 00176 { return itsMutex; } 00177 00178 private: 00179 // Forbid copy constructor. 00180 MutexedInit (const MutexedInit&); 00181 // Forbid assignment. 00182 MutexedInit& operator= (const MutexedInit&); 00183 00184 // Thread-safe execution of the initialization function (if still needed). 00185 void doExec(); 00186 00187 //# Data members 00188 Mutex itsMutex; 00189 InitFunc* itsFunc; 00190 void* itsArg; 00191 volatile Bool itsDoExec; 00192 }; 00193 00194 00195 } // namespace casa 00196 00197 #endif