casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Mutex.h
Go to the documentation of this file.
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