Area di riferimento
- Implementing service processes, threading, and application domains in a .NET Framework application
- Develop multithreaded .NET Framework applications
- ReaderWriterLock class
ReaderWriterLock
La classe ReaderWriterLock permette di risolvere il classico problema dei lettori e scrittori su una risorsa. In particolare questo oggetto è pensato per gestire al meglio le situazioni in cui esistono tanti lettori e pochi scrittori quindi è opportuno utilizzarlo soltanto se la risorsa che viene gestita debba essere modificata poco frequentemente.
E' possibile trovare un esempio completo su msdn al seguente indirizzo: http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx
In particolare supponendo di avere una istanza dell'oggetto ReaderWriterLock di nome rwl ( con molta fantasia direi :D ) ecco come si dovrebbe procedere per tentare un accesso in lettura alla risorsa.
try
{
rwl.AcquireReaderLock(timeOut);
try
{
// Qui è possibile effettuare una lettura della risorsa
}
finally
{
// E' importante assicurarsi di rilasciare il lock in lettura
rwl.ReleaseReaderLock();
}
}
catch (ApplicationException)
{
// La richiesta di accesso in lettura è andata in time-out
}
Un codice analogo si dovrebbe scrivere per effettuare un accesso in scrittura con la sola differenza di utilizzare i metodi AcquireWriterLock(timeOut) e ReleaseWriterLock().
All'interno di un blocco in lettura è possibile effettuare una richiesta di upgrade in modo tale da poter effettuare ahce una operazione di scrittura. Il metodo UpgradeToWriterLock(timeOut) viene utilizzato proprio per questo scopo e restituisce un oggetto LockCookie che dopo aver effettuato le opportune operazioni di scrittura deve essere passato al metodo DowngradeFromWriterLock() per tornare al solo permesso in lettura.
Ecco uno spezzone di codice che mostra quello che ho appena detto:
try
{
LockCookie lc = rwl.UpgradeToWriterLock(timeOut);
try
{
// Qui è possibile sia leggere che scrivere
}
finally
{
// E' importante ricordarsi di effettuare il downgrade
rwl.DowngradeFromWriterLock(ref lc);
}
}
catch (ApplicationException)
{
// La richiesta di upgrade è andata in time-out
Interlocked.Increment(ref writerTimeouts);
}
Altri metodi che possono essere utilizzati sono ReleaseLock() e RestoreLock(ref lc) per rilasciare temporaneamente il lock il lettura e poi riprenderlo. In questo caso è importante controllare se nel frattempo si è verificato almeno un accesso in scrittura utilizzando il metodo AnyWritersSince(lastWriter) che accetta come parametro il numero di sequenza dell'ultimo scrittore che deve essere letto prima di rilasciare il lock mediante la proprietà WriterSeqNum. Ciò è necessario per confermare la validità o meno dei dati locali letti in precedenza al rilascio.
// Salva il numero di sequenza dello scrittore corrente
lastWriter = rwl.WriterSeqNum;
// Rilascia il lock
LockCookie lc = rwl.ReleaseLock();
// Riottiene il lock
rwl.RestoreLock(ref lc);
if (rwl.AnyWritersSince(lastWriter))
{
// la risorsa è cambiata, i dati locali potrebbero essere non validi
}
else
{
// la risorsa non è stata cambiata, i dati locali sono corretti
}