📄 tlibthrd.cxx
字号:
}///////////////////////////////////////////////////////////////////////////////PSemaphore::PSemaphore(PXClass pxc){ pxClass = pxc; mutex = MutexInitialiser; condVar = CondInitialiser; // these should never be used, as this constructor is // only used for PMutex and PSyncPoint and they have their // own copy constructors initialVar = maxCountVar = 0;}PSemaphore::PSemaphore(unsigned initial, unsigned maxCount){ pxClass = PXSemaphore; mutex = MutexInitialiser; condVar = CondInitialiser; initialVar = initial; maxCountVar = maxCount;#ifdef P_HAS_SEMAPHORES PAssertPTHREAD(sem_init, (&semId, 0, initial));#else PAssert(maxCount > 0, "Invalid semaphore maximum."); if (initial > maxCount) initial = maxCount; currentCount = initial; maximumCount = maxCount; queuedLocks = 0;#endif}PSemaphore::PSemaphore(const PSemaphore & sem){ pxClass = sem.GetSemClass(); mutex = MutexInitialiser; condVar = CondInitialiser; initialVar = sem.GetInitial(); maxCountVar = sem.GetMaxCount();#ifdef P_HAS_SEMAPHORES PAssertPTHREAD(sem_init, (&semId, 0, initialVar));#else PAssert(maxCountVar > 0, "Invalid semaphore maximum."); if (initialVar > maxCountVar) initialVar = maxCountVar; currentCount = initialVar; maximumCount = maxCountVar; queuedLocks = 0;#endif}PSemaphore::~PSemaphore(){ pthread_cond_destroy(&condVar);#ifdef P_NETBSD // If the mutex was not locked, the unlock will fail */ pthread_mutex_trylock(&mutex);#endif pthread_mutex_unlock(&mutex); pthread_mutex_destroy(&mutex); if (pxClass == PXSemaphore) {#ifdef P_HAS_SEMAPHORES PAssertPTHREAD(sem_destroy, (&semId));#else PAssert(queuedLocks == 0, "Semaphore destroyed with queued locks");#endif }}void PSemaphore::Wait(){#ifdef P_HAS_SEMAPHORES PAssertPTHREAD(sem_wait, (&semId));#else PAssertPTHREAD(pthread_mutex_lock, (&mutex)); queuedLocks++; PThread::Current()->PXSetWaitingSemaphore(this); while (currentCount == 0) { int err = pthread_cond_wait(&condVar, &mutex); PAssert(err == 0 || err == EINTR, psprintf("wait error = %i", err)); } PThread::Current()->PXSetWaitingSemaphore(NULL); queuedLocks--; currentCount--; PAssertPTHREAD(pthread_mutex_unlock, (&mutex));#endif}BOOL PSemaphore::Wait(const PTimeInterval & waitTime){ if (waitTime == PMaxTimeInterval) { Wait(); return TRUE; } // create absolute finish time PTime finishTime; finishTime += waitTime;#ifdef P_HAS_SEMAPHORES#ifdef P_HAS_SEMAPHORES_XPG6 // use proper timed spinlocks if supported. // http://www.opengroup.org/onlinepubs/007904975/functions/sem_timedwait.html struct timespec absTime; absTime.tv_sec = finishTime.GetTimeInSeconds(); absTime.tv_nsec = finishTime.GetMicrosecond() * 1000; if (sem_timedwait(&semId, &absTime) == 0) { return TRUE; } else { return FALSE; }#else // loop until timeout, or semaphore becomes available // don't use a PTimer, as this causes the housekeeping // thread to get very busy do { if (sem_trywait(&semId) == 0) return TRUE;#if defined(P_LINUX) // sched_yield in a tight loop is bad karma // for the linux scheduler: http://www.ussg.iu.edu/hypermail/linux/kernel/0312.2/1127.html PThread::Current()->Sleep(10);#else PThread::Yield();#endif } while (PTime() < finishTime); return FALSE;#endif#else struct timespec absTime; absTime.tv_sec = finishTime.GetTimeInSeconds(); absTime.tv_nsec = finishTime.GetMicrosecond() * 1000; PAssertPTHREAD(pthread_mutex_lock, (&mutex)); PThread * thread = PThread::Current(); thread->PXSetWaitingSemaphore(this); queuedLocks++; BOOL ok = TRUE; while (currentCount == 0) { int err = pthread_cond_timedwait(&condVar, &mutex, &absTime); if (err == ETIMEDOUT) { ok = FALSE; break; } else PAssert(err == 0 || err == EINTR, psprintf("timed wait error = %i", err)); } thread->PXSetWaitingSemaphore(NULL); queuedLocks--; if (ok) currentCount--; PAssertPTHREAD(pthread_mutex_unlock, ((pthread_mutex_t *)&mutex)); return ok;#endif}void PSemaphore::Signal(){#ifdef P_HAS_SEMAPHORES PAssertPTHREAD(sem_post, (&semId));#else PAssertPTHREAD(pthread_mutex_lock, (&mutex)); if (currentCount < maximumCount) currentCount++; if (queuedLocks > 0) PAssertPTHREAD(pthread_cond_signal, (&condVar)); PAssertPTHREAD(pthread_mutex_unlock, (&mutex));#endif}BOOL PSemaphore::WillBlock() const{#ifdef P_HAS_SEMAPHORES if (sem_trywait((sem_t *)&semId) != 0) { PAssertOS(errno == EAGAIN || errno == EINTR); return TRUE; } PAssertPTHREAD(sem_post, ((sem_t *)&semId)); return FALSE;#else return currentCount == 0;#endif}#if defined(P_QNX) && (P_HAS_RECURSIVE_MUTEX == 1)#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE#endifPMutex::PMutex() : PSemaphore(PXMutex){#if P_HAS_RECURSIVE_MUTEX pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&mutex, &attr);#else ownerThreadId = (pthread_t)-1;#endif}PMutex::PMutex(const PMutex & /*mut*/) : PSemaphore(PXMutex){#if P_HAS_RECURSIVE_MUTEX pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&mutex, &attr);#else ownerThreadId = (pthread_t)-1;#endif}void PMutex::Wait(){#if P_HAS_RECURSIVE_MUTEX == 0 pthread_t currentThreadId = pthread_self(); // if the mutex is already acquired by this thread, // then just increment the lock count if (pthread_equal(ownerThreadId, currentThreadId)) { // Note this does not need a lock as it can only be touched by the thread // which already has the mutex locked. ++lockCount; return; }#endif // acquire the lock for real PAssertPTHREAD(pthread_mutex_lock, (&mutex));#if P_HAS_RECURSIVE_MUTEX == 0 PAssert((ownerThreadId == (pthread_t)-1) && (lockCount.IsZero()), "PMutex acquired whilst locked by another thread"); // Note this is protected by the mutex itself only the thread with // the lock can alter it. ownerThreadId = currentThreadId;#endif}BOOL PMutex::Wait(const PTimeInterval & waitTime){ // if waiting indefinitely, then do so if (waitTime == PMaxTimeInterval) { Wait(); return TRUE; }#if P_HAS_RECURSIVE_MUTEX == 0 // get the current thread ID pthread_t currentThreadId = pthread_self(); // if we already have the mutex, return immediately if (pthread_equal(ownerThreadId, currentThreadId)) { // Note this does not need a lock as it can only be touched by the thread // which already has the mutex locked. ++lockCount; return TRUE; }#endif // create absolute finish time PTime finishTime; finishTime += waitTime;#if P_PTHREADS_XPG6 struct timespec absTime; absTime.tv_sec = finishTime.GetTimeInSeconds(); absTime.tv_nsec = finishTime.GetMicrosecond() * 1000;#if P_HAS_RECURSIVE_MUTEX return pthread_mutex_timedlock(&mutex, &absTime) == 0;#else if (pthread_mutex_timedlock(&mutex, &absTime) != 0) return FALSE; PAssert((ownerThreadId == (pthread_t)-1) && (lockCount.IsZero()), "PMutex acquired whilst locked by another thread"); // Note this is protected by the mutex itself only the thread with // the lock can alter it. ownerThreadId = currentThreadId; return TRUE;#endif#else // P_PTHREADS_XPG6 do { if (pthread_mutex_trylock(&mutex) == 0) {#if P_HAS_RECURSIVE_MUTEX == 0 PAssert((ownerThreadId == (pthread_t)-1) && (lockCount.IsZero()), "PMutex acquired whilst locked by another thread"); // Note this is protected by the mutex itself only the thread with // the lock can alter it. ownerThreadId = currentThreadId;#endif // P_HAS_RECURSIVE_MUTEX return TRUE; } PThread::Current()->Sleep(10); // sleep for 10ms } while (PTime() < finishTime); return FALSE;#endif // P_PTHREADS_XPG6}void PMutex::Signal(){#if P_HAS_RECURSIVE_MUTEX == 0 if (!pthread_equal(ownerThreadId, pthread_self())) { PAssertAlways("PMutex signal failed - no matching wait or signal by wrong thread"); return; } // if lock was recursively acquired, then decrement the counter // Note this does not need a separate lock as it can only be touched by the thread // which already has the mutex locked. if (!lockCount.IsZero()) { --lockCount; return; } // otherwise mark mutex as available ownerThreadId = (pthread_t)-1;#endif PAssertPTHREAD(pthread_mutex_unlock, (&mutex));}BOOL PMutex::WillBlock() const{#if P_HAS_RECURSIVE_MUTEX == 0 pthread_t currentThreadId = pthread_self(); if (currentThreadId == ownerThreadId) return FALSE;#endif pthread_mutex_t * mp = (pthread_mutex_t*)&mutex; if (pthread_mutex_trylock(mp) != 0) return TRUE; PAssertPTHREAD(pthread_mutex_unlock, (mp)); return FALSE;}PSyncPoint::PSyncPoint() : PSemaphore(PXSyncPoint){ signalCount = 0;}PSyncPoint::PSyncPoint(const PSyncPoint &) : PSemaphore(PXSyncPoint){ signalCount = 0;}void PSyncPoint::Wait(){ PAssertPTHREAD(pthread_mutex_lock, (&mutex)); while (signalCount == 0) pthread_cond_wait(&condVar, &mutex); signalCount--; PAssertPTHREAD(pthread_mutex_unlock, (&mutex));}BOOL PSyncPoint::Wait(const PTimeInterval & waitTime){ PAssertPTHREAD(pthread_mutex_lock, (&mutex)); PTime finishTime; finishTime += waitTime; struct timespec absTime; absTime.tv_sec = finishTime.GetTimeInSeconds(); absTime.tv_nsec = finishTime.GetMicrosecond() * 1000; int err = 0; while (signalCount == 0) { err = pthread_cond_timedwait(&condVar, &mutex, &absTime); if (err == 0 || err == ETIMEDOUT) break; PAssertOS(err == EINTR && errno == EINTR); } if (err == 0) signalCount--; PAssertPTHREAD(pthread_mutex_unlock, (&mutex)); return err == 0;}void PSyncPoint::Signal(){ PAssertPTHREAD(pthread_mutex_lock, (&mutex)); signalCount++; PAssertPTHREAD(pthread_cond_signal, (&condVar)); PAssertPTHREAD(pthread_mutex_unlock, (&mutex));}BOOL PSyncPoint::WillBlock() const{ return signalCount == 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -