📄 ncbimtx.cpp
字号:
{ } ~CPthreadCond(void) { if ( m_Initialized ) { pthread_cond_destroy(&m_Handle); } } operator pthread_cond_t*(void) { return &m_Handle; } operator pthread_cond_t&(void) { return m_Handle; }protected: pthread_cond_t m_Handle; bool m_Initialized;};#endifclass CInternalRWLock{public: CInternalRWLock(void); // Platform-dependent RW-lock data#if defined(NCBI_WIN32_THREADS) CWindowsSemaphore m_Rsema; CWindowsSemaphore m_Wsema; CFastMutex m_Mutex;#elif defined(NCBI_POSIX_THREADS) CPthreadCond m_Rcond; CPthreadCond m_Wcond; CFastMutex m_Mutex;#endif};inlineCInternalRWLock::CInternalRWLock(void)#if defined(NCBI_WIN32_THREADS) : m_Rsema(1, 1), m_Wsema(1, 1)#endif{}/////////////////////////////////////////////////////////////////////////////// CRWLock:://CRWLock::CRWLock(void) : m_RW(new CInternalRWLock), m_Count(0){#if defined(_DEBUG) m_Readers.reserve(16);#endif}CRWLock::~CRWLock(void){}void CRWLock::ReadLock(void){#if defined(NCBI_NO_THREADS) return;#else // Lock mutex now, unlock before exit. // (in fact, it will be unlocked by the waiting function for a while) CFastMutexGuard guard(m_RW->m_Mutex); CThreadSystemID self_id = CThreadSystemID::GetCurrent(); if ( m_Count < 0 ) { if ( m_Owner.Is(self_id) ) { // if W-locked by the same thread - update W-counter m_Count--; } else { // W-locked by another thread#if defined(NCBI_WIN32_THREADS) HANDLE obj[2]; DWORD wait_res; obj[0] = m_RW->m_Mutex.GetHandle(); obj[1] = m_RW->m_Rsema; xncbi_Validate(ReleaseMutex(m_RW->m_Mutex.GetHandle()), "CRWLock::ReadLock() - release mutex error"); wait_res = WaitForMultipleObjects(2, obj, TRUE, INFINITE); xncbi_Validate(wait_res >= WAIT_OBJECT_0 && wait_res < WAIT_OBJECT_0 + 2, "CRWLock::ReadLock() - R-lock waiting error"); // Success, check the semaphore xncbi_Validate(m_RW->m_Rsema.Release() == 0, "CRWLock::ReadLock() - invalid R-semaphore state"); if (m_Count == 0) { xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0) == WAIT_OBJECT_0, "CRWLock::ReadLock() - " "failed to lock W-semaphore"); }#elif defined(NCBI_POSIX_THREADS) while (m_Count < 0) { xncbi_Validate(pthread_cond_wait(m_RW->m_Rcond, m_RW->m_Mutex.GetHandle()) == 0, "CRWLock::ReadLock() - R-lock waiting error"); }#else // Can not be already W-locked by another thread without MT xncbi_Validate(0, "CRWLock::ReadLock() - " "weird R-lock error in non-MT mode");#endif xncbi_Validate(m_Count >= 0, "CRWLock::ReadLock() - invalid readers counter"); m_Count++; } } else {#if defined(NCBI_WIN32_THREADS) if (m_Count == 0) { // Unlocked // Lock against writers xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0) == WAIT_OBJECT_0, "CRWLock::ReadLock() - " "can not lock W-semaphore"); }#endif m_Count++; }#if defined(_DEBUG) // Remember new reader if (m_Count > 0) { m_Readers.push_back(self_id); }#endif#endif}bool CRWLock::TryReadLock(void){#if defined(NCBI_NO_THREADS) return true;#else CFastMutexGuard guard(m_RW->m_Mutex); CThreadSystemID self_id = CThreadSystemID::GetCurrent(); if (m_Count < 0) { if ( m_Owner.IsNot(self_id) ) { // W-locked by another thread return false; } else { // W-locked, try to set R after W if in the same thread m_Count--; return true; } } // Unlocked - do R-lock#if defined(NCBI_WIN32_THREADS) if (m_Count == 0) { // Lock W-semaphore in MSWIN xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0) == WAIT_OBJECT_0, "CRWLock::TryReadLock() - " "can not lock W-semaphore"); }#endif m_Count++;#if defined(_DEBUG) m_Readers.push_back(self_id);#endif return true;#endif}void CRWLock::WriteLock(void){#if defined(NCBI_NO_THREADS) return;#else CFastMutexGuard guard(m_RW->m_Mutex); CThreadSystemID self_id = CThreadSystemID::GetCurrent(); if ( m_Count < 0 && m_Owner.Is(self_id) ) { // W-locked by the same thread m_Count--; } else { // Unlocked or RW-locked by another thread // Look in readers - must not be there xncbi_Validate(find(m_Readers.begin(), m_Readers.end(), self_id) == m_Readers.end(), "CRWLock::WriteLock() - " "attempt to set W-after-R lock");#if defined(NCBI_WIN32_THREADS) HANDLE obj[3]; obj[0] = m_RW->m_Rsema; obj[1] = m_RW->m_Wsema; obj[2] = m_RW->m_Mutex.GetHandle(); DWORD wait_res; if (m_Count == 0) { // Unlocked - lock both semaphores wait_res = WaitForMultipleObjects(2, obj, TRUE, 0); xncbi_Validate(wait_res >= WAIT_OBJECT_0 && wait_res < WAIT_OBJECT_0+2, "CRWLock::WriteLock() - " "error locking R&W-semaphores"); } else { // Locked by another thread - wait for unlock xncbi_Validate(ReleaseMutex(m_RW->m_Mutex.GetHandle()), "CRWLock::ReadLock() - release mutex error"); wait_res = WaitForMultipleObjects(3, obj, TRUE, INFINITE); xncbi_Validate(wait_res >= WAIT_OBJECT_0 && wait_res < WAIT_OBJECT_0+3, "CRWLock::WriteLock() - " "error locking R&W-semaphores"); }#elif defined(NCBI_POSIX_THREADS) while (m_Count != 0) { xncbi_Validate(pthread_cond_wait(m_RW->m_Wcond, m_RW->m_Mutex.GetHandle()) == 0, "CRWLock::WriteLock() - " "error locking R&W-conditionals"); }#endif xncbi_Validate(m_Count >= 0, "CRWLock::WriteLock() - invalid readers counter"); m_Count = -1; m_Owner.Set(self_id); } // No readers allowed _ASSERT(m_Readers.empty());#endif}bool CRWLock::TryWriteLock(void){#if defined(NCBI_NO_THREADS) return true;#else CFastMutexGuard guard(m_RW->m_Mutex); CThreadSystemID self_id = CThreadSystemID::GetCurrent(); if ( m_Count < 0 ) { // W-locked if ( m_Owner.IsNot(self_id) ) { // W-locked by another thread return false; } // W-locked by same thread m_Count--; } else if ( m_Count > 0 ) { // R-locked return false; } else { // Unlocked - do W-lock#if defined(NCBI_WIN32_THREADS) // In MSWIN lock semaphores HANDLE obj[2]; obj[0] = m_RW->m_Rsema; obj[1] = m_RW->m_Wsema; DWORD wait_res; wait_res = WaitForMultipleObjects(2, obj, TRUE, 0); xncbi_Validate(wait_res >= WAIT_OBJECT_0 && wait_res < WAIT_OBJECT_0 + 2, "CRWLock::TryWriteLock() - " "error locking R&W-semaphores");#endif m_Count = -1; m_Owner.Set(self_id); } // No readers allowed _ASSERT(m_Readers.empty()); return true;#endif}void CRWLock::Unlock(void){#if defined(NCBI_NO_THREADS) return;#else CFastMutexGuard guard(m_RW->m_Mutex); CThreadSystemID self_id = CThreadSystemID::GetCurrent(); if (m_Count < 0) { // Check it is R-locked or W-locked by the same thread xncbi_Validate(m_Owner.Is(self_id), "CRWLock::Unlock() - " "RWLock is locked by another thread"); if ( ++m_Count == 0 ) { // Unlock the last W-lock#if defined(NCBI_WIN32_THREADS) xncbi_Validate(m_RW->m_Rsema.Release() == 0, "CRWLock::Unlock() - invalid R-semaphore state"); xncbi_Validate(m_RW->m_Wsema.Release() == 0, "CRWLock::Unlock() - invalid R-semaphore state");#elif defined(NCBI_POSIX_THREADS) xncbi_Validate(pthread_cond_broadcast(m_RW->m_Rcond) == 0, "CRWLock::Unlock() - error signalling unlock"); xncbi_Validate(pthread_cond_signal(m_RW->m_Wcond) == 0, "CRWLock::Unlock() - error signalling unlock");#endif }#if defined(_DEBUG) // Check if the unlocking thread is in the owners list _ASSERT(find(m_Readers.begin(), m_Readers.end(), self_id) == m_Readers.end());#endif } else { xncbi_Validate(m_Count != 0, "CRWLock::Unlock() - RWLock is not locked"); if ( --m_Count == 0 ) { // Unlock the last R-lock#if defined(NCBI_WIN32_THREADS) xncbi_Validate(m_RW->m_Wsema.Release() == 0, "CRWLock::Unlock() - invalid W-semaphore state");#elif defined(NCBI_POSIX_THREADS) xncbi_Validate(pthread_cond_signal(m_RW->m_Wcond) == 0, "CRWLock::Unlock() - error signaling unlock");#endif }#if defined(_DEBUG) // Check if the unlocking thread is in the owners list vector<CThreadSystemID>::iterator found = find(m_Readers.begin(), m_Readers.end(), self_id); _ASSERT(found != m_Readers.end()); m_Readers.erase(found); if ( m_Count == 0 ) { _ASSERT(m_Readers.empty()); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -