Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "cxutils/mutex.h"
00042 #include "cxutils/time.h"
00043 #include "cxutils/thread.h"
00044 #include <assert.h>
00045 #include <string>
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048
00049 #ifdef WIN32
00050 #include <windows.h>
00051 #ifndef MINGW
00052 #include <atlbase.h>
00053 #else
00054 #define USES_CONVERSION
00055 #define A2W(x) (x)
00056 #define W2A(x) (x)
00057 #endif
00058 #endif
00059
00060 using namespace CxUtils;
00061
00062 unsigned int Mutex::mCount = 0;
00063
00073 Mutex::ScopedLock::ScopedLock(const Mutex* mutex) : mUnlockFlag(true), mpMutex(mutex)
00074 {
00075 if(mpMutex)
00076 {
00077 if(mpMutex->IsLocked())
00078 {
00079 mUnlockFlag = false;
00080 }
00081 else
00082 {
00083 mpMutex->Lock();
00084 }
00085 }
00086 }
00087
00088
00094 Mutex::ScopedLock::~ScopedLock()
00095 {
00096 if(mpMutex && mUnlockFlag)
00097 {
00098 mpMutex->Unlock();
00099 }
00100 }
00101
00102
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00128 Mutex::Mutex(const std::string& name)
00129 {
00130 mThreadID = 0;
00131 #ifdef WIN32
00132 mMutex = 0;
00133 #else
00134 pthread_mutex_init(&mMutex, NULL);
00135 mSemUnion.mVal = 0;
00136 mSemUnion.mpArray = NULL;
00137 mSemUnion.mpBuff = NULL;
00138 mSemUnion.mpBuffIPC = NULL;
00139 #endif
00140 Create(name);
00141 }
00142
00143
00149 Mutex::~Mutex()
00150 {
00151 #ifdef WIN32
00152 if (mMutex)
00153 {
00154 ReleaseMutex(mMutex);
00155 CloseHandle(mMutex);
00156 mMutex = 0;
00157 }
00158 #else
00159 if(IsLocked())
00160 {
00161 Unlock();
00162 }
00163
00164 if( !mName.empty() )
00165 {
00166 mSemUnion.mVal = 0;
00167 mSemUnion.mpArray = NULL;
00168 mSemUnion.mpBuff = NULL;
00169 mSemUnion.mpBuffIPC = NULL;
00170 mName.clear();
00171 }
00172 else
00173 {
00174
00175 pthread_mutex_destroy(&mMutex);
00176 }
00177 #endif
00178 }
00179
00180
00190 void Mutex::Create(const std::string& name)
00191 {
00192 #ifdef WIN32
00193 if (mMutex)
00194 {
00195 ReleaseMutex(mMutex);
00196 CloseHandle(mMutex);
00197 mMutex = 0;
00198 }
00199 #else
00200
00201 Unlock();
00202
00203 pthread_mutex_destroy(&mMutex);
00204 mName.clear();
00205 #endif
00206
00207 #if defined(WIN32)
00208 mMutex = 0;
00209 if(name.empty())
00210 {
00211 mCount++;
00212 mMutex = CreateMutex(NULL, FALSE, NULL);
00213 assert(mMutex);
00214 }
00215 else
00216 {
00217 USES_CONVERSION;
00218 mMutex = CreateMutex(NULL, FALSE, A2W(name.c_str()));
00219 assert(mMutex);
00220 }
00221 #else
00222 if( !name.empty() )
00223 {
00224 mName = name;
00225 int flag = 0;
00226
00227 flag = IPC_CREAT;
00228
00229 if( (mSemKey = (key_t)atol( mName.c_str())) == 0)
00230 {
00231
00232 char* buffer = new char[mName.size() * 3 + 1];
00233 char* ptr = buffer;
00234 for(unsigned int i = 0; i < (unsigned int)mName.size(); i++)
00235 {
00236 sprintf(ptr, "%.03d", (int)mName.c_str()[i]);
00237 ptr += 3;
00238 }
00239 if( (mSemKey = (key_t)atol( buffer )) == 0)
00240 {
00241 mName.clear();
00242 printf("ERROR: Failed to Create Global Mutex\n");
00243 assert("Failed to Create Mutex");
00244 exit(0);
00245 }
00246 }
00247
00248
00249 flag = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
00250
00251
00252 mSemID = (int)semget( mSemKey, 1, flag );
00253
00254
00255
00256 if( mSemID < 0)
00257 {
00258 mSemID = (int)semget( mSemKey, 1, flag | IPC_CREAT);
00259 if(mSemID < 0)
00260 {
00261 mName.clear();
00262 printf("ERROR: Failed to Create Global Mutex\n");
00263 exit(0);
00264 }
00265
00266 mSemUnion.mVal = 1;
00267 if( semctl( mSemID, 0, SETVAL, mSemUnion) == -1)
00268 {
00269 mName.clear();
00270 printf("ERROR: Failed to Create Global Mutex\n");
00271 exit(0);
00272 }
00273 }
00274
00275 }
00276 else
00277 {
00278 pthread_mutex_init(&mMutex, NULL);
00279 }
00280 #endif
00281 }
00282
00283
00296 bool Mutex::Lock(unsigned long wait ) const
00297 {
00298 if(mThreadID != 0)
00299 {
00300 Thread::ID callingID = Thread::GetCurrentThreadID();
00301 if(mThreadID == callingID)
00302 {
00303 assert("Created Mutex Deadlock!" && 0);
00304 return true;
00305 }
00306 }
00307 #ifdef WIN32
00308 if (mMutex)
00309 {
00310 DWORD result = WaitForSingleObject(mMutex, wait);
00311 if(result == WAIT_TIMEOUT)
00312 {
00313 return false;
00314 }
00315 *((ID *)(&mThreadID)) = Thread::GetCurrentThreadID();
00316 return true;
00317 }
00318 return false;
00319 #else
00320 if( !mName.empty() )
00321 {
00322 struct sembuf buff;
00323 unsigned int startTimeMs = GetTimeMs();
00324
00325
00326 buff.sem_num = 0;
00327 buff.sem_op = -1;
00328 buff.sem_flg = SEM_UNDO;
00329
00330 struct timespec delay;
00331 delay.tv_sec = 0;
00332 delay.tv_nsec = 1000;
00333 while(GetTimeMs() - startTimeMs < wait || wait == INFINITE)
00334 {
00335 if( semop( mSemID, &buff, 1) >= 0 )
00336 {
00337
00338 *((ID *)(&mThreadID)) = Thread::GetCurrentThreadID();
00339 return true;
00340 }
00341 nanosleep(&delay, NULL);
00342 }
00343
00344
00345 return false;
00346 }
00347 else
00348 {
00349 pthread_mutex_t *mut = (pthread_mutex_t *)(&mMutex);
00350 pthread_mutex_lock(mut);
00351 }
00352
00353 *((ID *)(&mThreadID)) = Thread::GetCurrentThreadID();
00354
00355 return true;
00356 #endif
00357 }
00358
00359
00365 void Mutex::Unlock() const
00366 {
00367 if(mThreadID != 0 && Thread::GetCurrentThreadID() == mThreadID)
00368 {
00369 *((ID *)(&mThreadID)) = 0;
00370 }
00371 #ifdef WIN32
00372 if(mMutex)
00373 {
00374 ReleaseMutex(mMutex);
00375 }
00376 #else
00377 if( !mName.empty() )
00378 {
00379 struct sembuf buff;
00380
00381
00382
00383 buff.sem_num = 0;
00384 buff.sem_op = 1;
00385 buff.sem_flg = SEM_UNDO;
00386
00387 if( semop( mSemID, &buff, 1) != 0)
00388 {
00389
00390 }
00391
00392 }
00393 else
00394 {
00395 pthread_mutex_t *mut = (pthread_mutex_t *)(&mMutex);
00396 pthread_mutex_unlock(mut);
00397 }
00398 #endif
00399 }
00400
00401
00408 bool Mutex::IsLocked() const
00409 {
00410 if(mThreadID == Thread::GetCurrentThreadID())
00411 {
00412 return true;
00413 }
00414 return false;
00415 }
00416
00417