00001 #ifndef mutex_header 00002 #define mutex_header 00003 00011 // possible problem: 00012 // LinuxThreads have various non-POSIX types of mutexes. Default mutex type 00013 // is "fast": On "unlock()" it is not checked, whether the caller is the 00014 // owner of the mutex! So any thread can unlock the mutex. You shouldn't 00015 // rely on this "feature". In fact, it has a very serious drawback: In a 00016 // try-catch block you must know the exact state of the mutex, otherwise 00017 // other threads may sneak into critical sections or a deadlock occurs! 00018 00019 00020 extern "C" 00021 { 00022 #include <pthread.h> 00023 } 00024 00025 #include "utils.H" 00026 00027 00029 class CMutex : private ForbidAssignment 00030 { 00031 private: 00032 pthread_mutex_t mutex; 00033 public: 00034 inline CMutex() 00035 { 00036 pthread_mutex_init(&mutex,NULL); 00037 } 00038 inline ~CMutex() 00039 { 00040 #ifndef DEBUG 00041 pthread_mutex_destroy(&mutex); 00042 #else /* only for debugging */ 00043 const int result = pthread_mutex_destroy(&mutex); 00044 if (result==EBUSY) 00045 { 00046 using std::cerr; using std::endl; 00047 cerr << "cannot destroy busy mutex!!" << endl; 00048 exit(1); 00049 } 00050 #endif 00051 } 00052 inline void lock() 00053 { 00054 const int result = pthread_mutex_lock(&mutex); 00055 switch (result) 00056 { 00057 using std::cerr; using std::endl; 00058 case EINVAL: 00059 cerr << "the mutex has not been properly initialized." << endl; 00060 exit(1); 00061 case EDEADLK: 00062 cerr << "the mutex is already locked by the calling thread" << endl; 00063 exit(1); 00064 } 00065 } 00066 inline bool trylock() 00067 { 00068 const int result = pthread_mutex_trylock(&mutex); 00069 switch (result) 00070 { 00071 using std::cerr; using std::endl; 00072 case EINVAL: 00073 cerr << "the mutex has not been properly initialized." << endl; 00074 exit(1); 00075 case EBUSY: 00076 #ifdef VERBOSE 00077 cerr << "the mutex could not be acquired because it was currently locked." << endl; 00078 #endif 00079 return false; 00080 } 00081 return true; 00082 } 00083 inline void unlock() 00084 { 00085 const int result = pthread_mutex_unlock(&mutex); 00086 switch (result) 00087 { 00088 using std::cerr; using std::endl; 00089 case EINVAL: 00090 cerr << "the mutex has not been properly initialized." << endl; 00091 exit(1); 00092 case EPERM: 00093 cerr << "the calling thread does not own the mutex" << endl; 00094 exit(1); 00095 case EBUSY: 00096 cerr << "the mutex is currently locked." << endl; 00097 exit(1); 00098 } 00099 } 00100 }; 00101 00102 00111 class CUnlockMutexAtDestruction : private ForbidAssignment 00112 { 00113 private: 00114 CMutex &mutex; 00115 public: 00116 CUnlockMutexAtDestruction(CMutex &myMutex) : mutex(myMutex) { } 00117 ~CUnlockMutexAtDestruction() { mutex.unlock(); } 00118 }; 00119 00120 00129 class CConditionalUnlockMutexAtDestruction : private ForbidAssignment 00130 { 00131 private: 00132 CMutex &mutex; 00133 bool condition; 00134 public: 00135 CConditionalUnlockMutexAtDestruction(CMutex &myMutex, const bool initial_condition) 00136 : mutex(myMutex), condition(initial_condition) { } 00137 ~CConditionalUnlockMutexAtDestruction() { if (condition) mutex.unlock(); } 00138 void set_condition(const bool new_condition = true) { condition=new_condition; } 00139 }; 00140 00141 00155 class CCriticalSection : private ForbidAssignment 00156 { 00157 public: 00158 class Mutex : private CMutex // private inheritance to forbid usage outside this class 00159 { 00160 friend class CCriticalSection; // the owning class is allowed to call methods! 00161 }; 00162 00163 private: 00164 Mutex &mutex; 00165 bool inside; 00166 00167 public: 00168 00170 inline void enter() 00171 { 00172 #ifdef DEBUG 00173 if (inside) std::cerr << "CCriticalSection::enter(): already entered" << std::endl; 00174 #endif 00175 if (!inside) mutex.lock(); // enter the critical section (wait until mutex can be obtained) 00176 inside=true; 00177 } 00178 00180 inline bool try_enter() 00181 { 00182 #ifdef DEBUG 00183 if (inside) std::cerr << "CCriticalSection::enter(): already entered" << std::endl; 00184 #endif 00185 if (!inside) inside=mutex.trylock(); // try to enter the critical section (but don't wait if mutex cannot be obtained) 00186 return inside; 00187 } 00188 00190 inline void leave() 00191 { 00192 #ifdef DEBUG 00193 if (!inside) std::cerr << "CCriticalSection::leave(): already left" << std::endl; 00194 #endif 00195 if (inside) mutex.unlock(); 00196 inside=false; 00197 } 00198 00200 CCriticalSection(CCriticalSection::Mutex &crit_sect_mutex, const bool enter_now=true) 00201 : mutex(crit_sect_mutex), inside(false) 00202 { 00203 if (enter_now) enter(); // enter the critical section 00204 } 00205 00207 ~CCriticalSection() 00208 { 00209 if (inside) leave(); // leave the critical section 00210 } 00211 00212 }; 00213 00214 #endif