Reader & Writer Lock
A Reader-Writer Lock (often implemented as ReaderWriterLock in .NET) is a synchronization primitive that allows multiple threads to read a shared resource simultaneously but ensures exclusive access when writing to the resource. The primary advantage of a reader-writer lock is that it allows for higher concurrency when multiple threads are reading the resource, while still ensuring mutual exclusion for write operations.
Usage
EnterWriteLockandEnterReadLockExitWriteLockandExitReadLock
TIP
Use TryEnter* and TryExit* if a timeout is required.
internal class Program {
private static readonly ReaderWriterLockSlim _lock = new();
private static void Main(string[] args) {
var collection = Enumerable.Range(1, 10).ToArray();
var tasks = Enumerable.Range(1, 10).Select(_ => {
return Task.Run(() => {
try {
_lock.EnterWriteLock();
collection[Random.Shared.Next(collection.Length)] = 111;
} finally {
_lock.ExitWriteLock();
}
});
});
Task.WaitAll(tasks);
Console.WriteLine(string.Join(", ", collection));
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Upgradable Lock
Since write lock and read lock are atomic, you can't combine the two operation as one atomic, it can be interrupted by another thread when before you enter write/read lock on current thread. So Upgradable Lock simply provides a way to perform reading and writing as one atomic operation.
internal class Program {
private static readonly ReaderWriterLockSlim _lock = new();
private static void Main(string[] args) {
var collection = Enumerable.Range(1, 10).ToArray();
var tasks = Enumerable.Range(1, 10).Select(_ => {
return Task.Run(() => {
try {
_lock.EnterUpgradeableReadLock();
Console.WriteLine(string.Join(", ", collection));
try {
_lock.EnterWriteLock(); // allows you to enter write lock
collection[Random.Shared.Next(collection.Length)] = 111;
} finally {
_lock.ExitWriteLock();
}
} finally {
_lock.ExitUpgradeableReadLock();
}
});
});
Task.WaitAll(tasks);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Recursive Lock
When a implementation needs recursive logic within a entrance of lock inside, this is called recursive lock. ReaderWriterLockSlim supports such recursion when LockRecursionPolicy.SupportsRecursion is specified on creation.
private static readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion);
public void Foo() {
_lock.EnterReadLock();
try {
// recursion happens here...
if (condition) Foo();
// some other operation...
} finally {
_lock.ExitReadLock();
}
}2
3
4
5
6
7
8
9
10
11
Conclusion
- Use
ReaderWriterLockSlimfor a more performant experience instead of oldReaderWriterLock. ReaderWriterLockSlimisIDisposable, remember to release it after finishing the work.- Reader & Writer Lock allows exclusive access for writing but allows multiple threads for reading.
- Do not use
ReaderWriterLockSlimon dotnet framework projects, use oldReaderWriterLock. - Use
EnterUpgradeableReadLockandExitUpgradeableReadLockif you need to combine read and write as one atomic operation.