From 851e6cbcb4a72f8b0e4dc77d17d723bf7510fc59 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sun, 25 Oct 2026 13:17:17 +0100 Subject: [PATCH] ReaderWriterLockSlim sample: .NET 10, Lock field, async pitfall demo, recursion tests --- .../ReaderWriterLockSlimReadWriteTests.cs | 35 +++++++++++++++++++ .../Tests/Tests.csproj | 10 +++--- .../AsyncPitfall.cs | 26 ++++++++++++++ .../LockReadWrite.cs | 2 +- .../Program.cs | 4 ++- .../ReaderWriterLockSlimReadWrite.cs | 4 +-- ...eaderWriterLockSlimOverLockInCSharp.csproj | 2 +- 7 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/AsyncPitfall.cs diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/ReaderWriterLockSlimReadWriteTests.cs b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/ReaderWriterLockSlimReadWriteTests.cs index 4ccc2bd5f8..5d404cd87a 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/ReaderWriterLockSlimReadWriteTests.cs +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/ReaderWriterLockSlimReadWriteTests.cs @@ -48,4 +48,39 @@ public void WhenReadOrAdd_ListCountIsEqualOne() Assert.AreEqual(1, readerWriterLockSlimReadWrite.ListOfNumbers.Count); } + + [TestMethod] + public void WhenReadLockIsEnteredTwiceWithDefaultPolicy_ThrowsLockRecursionException() + { + using var readerWriterLockSlim = new ReaderWriterLockSlim(); + readerWriterLockSlim.EnterReadLock(); + + Assert.ThrowsExactly(() => readerWriterLockSlim.EnterReadLock()); + + readerWriterLockSlim.ExitReadLock(); + } + + [TestMethod] + public void WhenReadLockIsEnteredTwiceWithSupportsRecursion_RecursiveReadCountIsTwo() + { + using var readerWriterLockSlim = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + readerWriterLockSlim.EnterReadLock(); + readerWriterLockSlim.EnterReadLock(); + + Assert.AreEqual(2, readerWriterLockSlim.RecursiveReadCount); + + readerWriterLockSlim.ExitReadLock(); + readerWriterLockSlim.ExitReadLock(); + } + + [TestMethod] + public void WhenReadLockHolderEntersWriteLock_ThrowsLockRecursionException() + { + using var readerWriterLockSlim = new ReaderWriterLockSlim(); + readerWriterLockSlim.EnterReadLock(); + + Assert.ThrowsExactly(() => readerWriterLockSlim.EnterWriteLock()); + + readerWriterLockSlim.ExitReadLock(); + } } \ No newline at end of file diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/Tests.csproj b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/Tests.csproj index 9cf18106a8..adeebb80fb 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/Tests.csproj +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net10.0 enable enable @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/AsyncPitfall.cs b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/AsyncPitfall.cs new file mode 100644 index 0000000000..211c8347ac --- /dev/null +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/AsyncPitfall.cs @@ -0,0 +1,26 @@ +namespace WhenToUseReaderWriterLockSlimOverLockInCSharp; + +public static class AsyncPitfall +{ + public static async Task ExitWriteLockAfterAwait() + { + var readerWriterLockSlim = new ReaderWriterLockSlim(); + var threadBefore = Environment.CurrentManagedThreadId; + + readerWriterLockSlim.EnterWriteLock(); + await Task.Delay(50); + var threadAfter = Environment.CurrentManagedThreadId; + + try + { + readerWriterLockSlim.ExitWriteLock(); + + return $"Exited on the same thread ({threadBefore})."; + } + catch (SynchronizationLockException ex) + { + return $"{ex.GetType().Name} on thread {threadAfter} " + + $"(entered on thread {threadBefore}): {ex.Message}"; + } + } +} diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/LockReadWrite.cs b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/LockReadWrite.cs index 703bb54604..27a0f651e1 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/LockReadWrite.cs +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/LockReadWrite.cs @@ -2,7 +2,7 @@ public class LockReadWrite : BaseReaderWriter { - private static readonly object LockObject = new(); + private static readonly Lock LockObject = new(); public override void AddNumbersToList(int writerExecutionsCount, int writerExecutionDelay) { diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/Program.cs b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/Program.cs index 1c0575bb46..c5aa167508 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/Program.cs +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/Program.cs @@ -18,4 +18,6 @@ var readerWriterLockSlimReadWrite = new ReaderWriterLockSlimReadWrite(); Console.WriteLine($"ReaderWriterLockSlim execution time: " + - $"{readerWriterLockSlimReadWrite.Execute(config)} milliseconds."); \ No newline at end of file + $"{readerWriterLockSlimReadWrite.Execute(config)} milliseconds."); + +Console.WriteLine(await AsyncPitfall.ExitWriteLockAfterAwait()); diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/ReaderWriterLockSlimReadWrite.cs b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/ReaderWriterLockSlimReadWrite.cs index e32378f0a8..51d5d111b6 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/ReaderWriterLockSlimReadWrite.cs +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/ReaderWriterLockSlimReadWrite.cs @@ -45,12 +45,12 @@ public override void ReadListCount(int readerExecutionsCount, int readerExecutio public void ReadOrAdd(int writerExecutionDelay) { - var random = Random.Shared.Next(0, NumbersList.Count); - ReaderWriterLockSlim.EnterUpgradeableReadLock(); try { + var random = Random.Shared.Next(0, NumbersList.Count); + if (!NumbersList.Contains(random)) { ReaderWriterLockSlim.EnterWriteLock(); diff --git a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp.csproj b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp.csproj index f02677bf64..dfb40caafc 100644 --- a/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp.csproj +++ b/csharp-intermediate-topics/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp/WhenToUseReaderWriterLockSlimOverLockInCSharp.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable