Рассматривается контейнер (словарь), для которого имеются 1-2 writer и 4-5 readers. Ищется решение для реализации следуюшей политики блокировок:
- writer экслюзивно блокирует любые операции других wtiters/readers, выполняя acquireLockExclusive();
- reader не блокирует других readers, но блокирует любых writers выполняя acquireLockShared().
Ниже приводится простое решение, которое, как представляется, неплохо работает (я тестировал его на 1-4CPU компьютерах для различных OS).
class SRWLock_favor_readers3
{
public:
void acquireLockShared()
{
// try lock
while(_InterlockedIncrement(&m_writers_readers_flag) > 0xFFFF)
{
// rollback
_InterlockedDecrement(&m_writers_readers_flag);
::WaitForSingleObject(m_evt_no_writers, INFINITE);
}
}
void acquireLockExclusive()
{
// lock writers
::EnterCriticalSection(&m_cswriters);
do
{ // wait for all readers shared locks released
while(m_writers_readers_flag != 0x0)
{
::Sleep(1);
}
}
// doublecheck
while( _InterlockedCompareExchange(&m_writers_readers_flag,0x1+0xFFFF,0x0) != 0x0);
::ResetEvent(m_evt_no_writers);
}
void releaseLockShared()
{
// release reference to a reader
_InterlockedDecrement(&m_writers_readers_flag);
}
void releaseLockExclusive()
{
// unlock readers
_InterlockedXor(&m_writers_readers_flag, 0x1+0xFFFF);
::SetEvent(m_evt_no_writers);
// unlock writers
::LeaveCriticalSection(&m_cswriters);
}
// lock statistics
LONGLONG locked_acquiringLockExclusive(void) const
{
return 0;
}
LONGLONG locked_acquiringLockShared(void) const
{
return 0;
}
SRWLock_favor_readers3(): m_writers_readers_flag(0L)
{
::InitializeCriticalSection(&m_cswriters);
m_evt_no_writers = ::CreateEvent(NULL, TRUE, TRUE, NULL);
}
~SRWLock_favor_readers3()
{
::DeleteCriticalSection(&m_cswriters);
::CloseHandle(m_evt_no_writers);
}
private:
CRITICAL_SECTION m_cswriters;
HANDLE m_evt_no_writers;
LONG m_writers_readers_flag;
};
---
Спасибо за критику и за найденные ошибки.
|