/* * Copyright: JessMA Open Source (ldcsaa@gmail.com) * * Author : Bruce Liang * Website : https://github.com/ldcsaa * Project : https://github.com/ldcsaa/HP-Socket * Blog : http://www.cnblogs.com/ldcsaa * Wiki : http://www.oschina.net/p/hp-socket * QQ Group : 44636872, 75375912 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "RWLock.h" CMutexRWLock::CMutexRWLock() : m_nActive (0) , m_dwWriterTID (0) { } CMutexRWLock::~CMutexRWLock() { ASSERT(m_nActive == 0); ASSERT(m_dwWriterTID == 0); } VOID CMutexRWLock::WaitToRead() { BOOL bWait = FALSE; { CSpinLock locallock(m_cs); if(m_nActive > 0) ++m_nActive; else if(m_nActive == 0) { if(m_mtx.try_lock_shared()) ++m_nActive; else bWait = TRUE; } else if(!IsOwner()) bWait = TRUE; } if(bWait) { m_mtx.lock_shared(); CSpinLock locallock(m_cs); ++m_nActive; } } VOID CMutexRWLock::WaitToWrite() { BOOL bWait = FALSE; { CSpinLock locallock(m_cs); if(m_nActive > 0) bWait = TRUE; else if(m_nActive == 0) { if(m_mtx.try_lock()) { SetOwner(); --m_nActive; } else bWait = TRUE; } else { if(IsOwner()) --m_nActive; else bWait = TRUE; } } if(bWait) { m_mtx.lock(); SetOwner(); --m_nActive; } } VOID CMutexRWLock::ReadDone() { ASSERT(m_nActive != 0); if(m_nActive > 0) { { CSpinLock locallock(m_cs); --m_nActive; } m_mtx.unlock_shared(); } else ASSERT(IsOwner()); } VOID CMutexRWLock::WriteDone() { ASSERT(IsOwner()); ASSERT(m_nActive < 0); BOOL bDone; { CSpinLock locallock(m_cs); bDone = (++m_nActive == 0); } if(bDone) { DetachOwner(); m_mtx.unlock(); } else ASSERT(IsOwner()); } CSEMRWLock::CSEMRWLock() : m_nWaitingReaders (0) , m_nWaitingWriters (0) , m_nActive (0) , m_dwWriterTID (0) { } CSEMRWLock::~CSEMRWLock() { ASSERT(m_nActive == 0); ASSERT(m_dwWriterTID == 0); } VOID CSEMRWLock::WaitToRead() { CMutexLock2 lock(m_mtx); if(IsOwner()) return; ++m_nWaitingReaders; m_cvRead.wait(lock, [=]() -> BOOL { return m_nActive >= 0 && m_nWaitingWriters == 0; }); --m_nWaitingReaders; ++m_nActive; } VOID CSEMRWLock::WaitToWrite() { CMutexLock2 lock(m_mtx); if(IsOwner()) { --m_nActive; return; } ++m_nWaitingWriters; m_cvWrite.wait(lock, [=]() -> BOOL { return m_nActive == 0; }); --m_nWaitingWriters; --m_nActive; SetOwner(); } VOID CSEMRWLock::ReadDone() { CMutexLock2 locallock(m_mtx); if(IsOwner()) return; ASSERT(m_nActive > 0); if(--m_nActive == 0 && m_nWaitingWriters > 0) m_cvWrite.notify_one(); } VOID CSEMRWLock::WriteDone() { ASSERT(IsOwner()); CMutexLock2 lock(m_mtx); if(++m_nActive == 0) { DetachOwner(); if(m_nWaitingWriters > 0) m_cvWrite.notify_one(); else if(m_nWaitingReaders > 0) m_cvRead.notify_all(); } }