I have the following code:
private static object _dbLock = new object();
public static void LoadData()
{
lock (_dbLock)
{
//Load data from the database
}
}
public static string ReadData(Guid key)
{
lock (_dbLock)
{
//Lookup key in data and return value
}
}
I don't want to allow people to read the data while it's being loaded from the database, thus I put a lock
in ReadData
. However, right now if multiple people call ReadData
at the same time, only one call can run at once.
Is there a way I can allow simultaneous calls to ReadData
but block readers when LoadData
is being run?
In many situations, data is read more often than it is modified or written. In these cases, you can allow threads to read concurrently while holding the lock and allow only one thread to hold the lock when data is modified. A multiple-reader single-writer lock (or read/write lock) does this.
An RW lock allows concurrent access for read-only operations, write operations require exclusive access. This means that multiple threads can read the data in parallel but an exclusive lock is needed for writing or modifying data.
A readers/writer lock regulates access to a set of data. The readers/writer lock is so called because many threads can hold the lock simultaneously for reading, but only one thread can hold the lock for writing. Most device drivers do not use readers/writer locks.
Instead of having a single lock method, they have two - one for readers and one for writers. When readers enter the critical section they invoke the reader lock (and then reader unlock on exit); when writers enter the critical section they invoke the writer lock (and then writer unlock on exit).
The ReaderWriterLock
and ReaderWriterLockSlim
classes support that use case. Use the 'Slim' version unless you need pre-3.5 support.
private static ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim();
public static void LoadData()
{
_cacheLock.EnterWriteLock();
try
{
// Load data from the database
}
finally
{
_cacheLock.ExitWriteLock();
}
}
public static string ReadData(Guid key)
{
_cacheLock.EnterReadLock();
try
{
// Lookup key in data and return value
}
finally
{
_cacheLock.ExitReadLock();
}
}
Try using the ManualResetEvent
:
private static object _dbLock = new object();
private static ManualResetEvent _mrse = new ManualResetEvent(true);
public static void LoadData()
{
lock (_dbLock)
{
_mrse.Reset();
//Load data from the database
_mrse.Set();
}
}
public static string ReadData(Guid key)
{
_mrse.Wait();
//Lookup key in data and return value
}
This allows multiple readers to wait for the data loader to finish its work and then simultaneously read. If the collection is not thread safe, then you need to add another locking object or use another synchronization construct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With