Rezervační systém
Veřejné metody | Seznam všech členů
Dokumentace třídy CReadWriteLock

synchronizace přístupu typu více čtení - jeden zápis ...

#include <UtilClass.h>

Diagram dědičnosti pro třídu CReadWriteLock
CBus CCity CMemoryDb CPlan

Veřejné metody

 CReadWriteLock (unsigned uiMaxReaders)
 konstruktor ...
 
 CReadWriteLock (const CReadWriteLock &cSource)
 kopírovací konstruktor ...
 
 ~CReadWriteLock ()
 destruktor ...
 
void EnterRead (void)
 vstup do chráněného bloku pro čtení ...
 
void LeaveRead (void)
 opuštění chráněného bloku po čtení ...
 
void EnterWrite (void)
 vstup do chráněného bloku pro zápis ...
 
void LeaveWrite (void)
 opuštění chráněného bloku po zápisu ...
 
CReadWriteLockoperator= (const CReadWriteLock &cRight)
 přiřazovací operátor ...
 

Detailní popis

synchronizace přístupu typu více čtení - jeden zápis

Třída implementuje zámek pro synchronizaci přístupu k nějakému objektu současně z více vláken. Je možné provádět zároveň více operací čtení (tj. operací bez modifikace dat chráněného objektu), ale pouze jedinou operaci zápisu (modifikaci dat objektu). Jinými slovy umožňuje sdílený (pouze pro čtení) nebo unikátní přístup (pro modifikaci) k datům. Maximální počet současně přistupujících čtenářů se nastavuje v konstruktoru.

Zabezpečení pomocí této třídy má smysl u přístupu k objektům, kdy operace čtení je mnohem četnější než operace zápisu. Implementace zároveň upřednostňuje zápis v tom smyslu, že při požadavku na přístup v zapisovacím režimu nejsou povolovány další požadavky na čtení až do doby ukončení zapisovací operace.

Předpokládá se, že potomci této třídy mohou být umístěni v kontajnerech STL, proto je implementován i kopírovací konstruktor a operátor přiřazení. Každý objekt (i nově vytvořený) si ale vytváří individuální zabezpečení, které není možné kopírovat.

Původně byla navržena implementace využívající objekty jádra - událost a semafor, veřejná část deklarace třídy a tím i použití jsou shodné.

public:
CReadWriteLock(unsigned uiMaxReaders);
CReadWriteLock(const CReadWriteLock &cSource);
void EnterRead(void);
void LeaveRead(void);
void EnterWrite(void);
void LeaveWrite(void);
private:
unsigned m_uiMaxReaders;
HANDLE m_ahLocks[2]; // 0 - událost pro zápis (větší priorita), 1 - semafor pro čtení
};
CReadWriteLock::CReadWriteLock(unsigned uiMaxReaders)
{
m_uiMaxReaders = uiMaxReaders;
// přístup pro zápis - signalizovaná auto-reset událost
m_ahLocks[0] = CreateEvent(NULL, FALSE, TRUE, NULL); // neprobíhá zápis
// přístup pro čtení - semafor nastavený na max. hodnotu
m_ahLocks[1] = CreateSemaphore(NULL, uiMaxReaders, uiMaxReaders, NULL); // žádné aktivní čtení
}
{
m_uiMaxReaders = cSource.m_uiMaxReaders;
// objekty jádra si vytváří své
m_ahLocks[0] = CreateEvent(NULL, FALSE, TRUE, NULL);
m_ahLocks[1] = CreateSemaphore(NULL, m_uiMaxReaders, m_uiMaxReaders, NULL);
}
{
// žádné čtení ani zápis nejsou aktivní - lze rušit objekty jádra
CloseHandle(m_ahLocks[0]);
CloseHandle(m_ahLocks[1]);
}
{
// čekání na ukončení zápisu i volnou pozici pro čtení zároveň
WaitForMultipleObjects(2, m_ahLocks, TRUE, INFINITE);
SetEvent(m_ahLocks[0]); // uvolnění omezení pro zápis
}
{
// čtení dokončeno - uvolnění pozice
ReleaseSemaphore(m_ahLocks[1], 1, NULL);
}
{
unsigned uiLastCount;
// čekání na ukončení jiného zápisu
WaitForSingleObject(m_ahLocks[0], INFINITE); // zablokuje další EnterRead
// čekání na dokončení všech čtení
while(true) {
WaitForSingleObject(m_ahLocks[1], INFINITE); // -1
ReleaseSemaphore(m_ahLocks[1], 1, (LPLONG)&uiLastCount); // +1
if(uiLastCount == m_uiMaxReaders - 1)
return; // čítač na maximální hodnotě => žádné aktivní čtení
Sleep(0);
}
}
{
// zápis dokončen - povolení dalšího zápisu
SetEvent(m_ahLocks[0]);
}
{
// žádná činnost
return *this;
}

Vzhledem k možnému vyčerpání dostupných objektů jádra (při rozsáhlejších databázích) i s přihlédnutím k výkonu je nyní třída implementována zcela v uživatelském prostoru. Další možností by bylo použití slim read-write locks, kde však není zaručena přednost zapisovacích požadavků (dnes již asi není příliš podstatné, že nejsou podporovány ve Windows XP).

Pozor
Při použití třídy je zásadní správně párovat metody pro vstup do chráněného bloku a jeho opuštění! Je možné vnoření bloků, ale není správné takto chráněné bloky překrývat. Nerespektování těchto pravidel povede nejspíše k "deadlocku" či zhroucení aplikace.

Dokumentace konstruktoru a destruktoru

CReadWriteLock::CReadWriteLock ( unsigned  uiMaxReaders)

konstruktor

Vytvoření instance třídy a inicializace používaných objektů.

Parametry
[in]uiMaxReadersnastavení počtu čtenářů, kteří mohou zároveň přistupovat k chráněnému objektu
CReadWriteLock::CReadWriteLock ( const CReadWriteLock cSource)

kopírovací konstruktor

Vytvoření instance třídy s tím, že objekty k ochraně si vytváří vlastní.

CReadWriteLock::~CReadWriteLock ( )

destruktor

Dojde k uvolnění použitých objektů.

Dokumentace k metodám

void CReadWriteLock::EnterRead ( void  )

vstup do chráněného bloku pro čtení

Chráněný blok je zpřístupněn za podmínek, že není požadován či neprobíhá zápis a zároveň není vyčerpán povolený počet čtenářů. Do splnění podmínek je volající vlákno blokováno.

void CReadWriteLock::EnterWrite ( void  )

vstup do chráněného bloku pro zápis

Chráněný blok je zpřístupněn za podmínek, že není požadován či neprobíhá jiný zápis a zároveň není aktivní žádné čtení.

void CReadWriteLock::LeaveRead ( void  )

opuštění chráněného bloku po čtení

Provede uvolnění pozice pro dalšího čtenáře.

void CReadWriteLock::LeaveWrite ( void  )

opuštění chráněného bloku po zápisu

Chráněný blok je zpřístupněn dalším operacím, ať již se jedná o čtení nebo o zápis.

CReadWriteLock& CReadWriteLock::operator= ( const CReadWriteLock cRight)

přiřazovací operátor

Operace přiřazení neprovádí žádnou činnost kromě definování návratové hodnoty. Cílová třída má již z konstruktoru inicializovány vlastní prostředky pro svou činnost a není možné tyto nějak navzájem mísit. Přiřazování instancí může mít smysl v případě potomků, přičemž defaultní přiřazovací operátor by narušoval činnost blokovacího mechanismu.


Dokumentace pro tuto třídu byla generována z následujícího souboru: