public async Task WriteTakesPriorityOverRead1() { var myLock = new AsyncReaderWriterLockSlim(); // Check that no new read lock can be entered when another thread/task wants // to enter the write lock while at least one read lock is active. myLock.EnterReadLock(); using (var cts = new CancellationTokenSource()) { var enterWriteLockTask = myLock.EnterWriteLockAsync(cts.Token); Assert.IsFalse(myLock.TryEnterReadLock(0)); cts.Cancel(); try { await enterWriteLockTask; Assert.Fail(); } catch (OperationCanceledException) { } } // Verify that now a new read lock can be entered. Assert.IsTrue(await myLock.TryEnterReadLockAsync(0)); }
public async Task CanEnterLocksAync() { var myLock = new AsyncReaderWriterLockSlim(); await myLock.EnterReadLockAsync(); Assert.IsTrue(await myLock.TryEnterReadLockAsync(0)); Assert.IsFalse(await myLock.TryEnterWriteLockAsync(0)); myLock.ExitReadLock(); myLock.ExitReadLock(); await myLock.EnterWriteLockAsync(); Assert.IsFalse(await myLock.TryEnterReadLockAsync(0)); Assert.IsFalse(await myLock.TryEnterWriteLockAsync(0)); myLock.ExitWriteLock(); }
public async Task WriteTakesPriorityOverRead2() { var myLock = new AsyncReaderWriterLockSlim(); // Check that when at least one thread/task wants to enter the read lock and at least // one thread/task wants to enter the write lock while another write lock is active, // writers always get precedence over readers when the existing write lock is released. for (int i = 0; i < 1000; i++) { myLock.EnterWriteLock(); var readLockTask = myLock.EnterReadLockAsync(); var writeLockTask = myLock.EnterWriteLockAsync(); // Release the current write lock. Now the writeLockTask should complete. myLock.ExitWriteLock(); await writeLockTask; // After releasing the second write lock, the readLockTask should complete. myLock.ExitWriteLock(); await readLockTask; myLock.ExitReadLock(); } }
public void LoadTest() { var myLock = new AsyncReaderWriterLockSlim(); object lockCountSyncRoot = new object(); int readLockCount = 0, writeLockCount = 0; bool incorrectLockCount = false; void checkLockCount() { Debug.WriteLine($"ReadLocks = {readLockCount}, WriteLocks = {writeLockCount}"); bool countIsCorrect = readLockCount == 0 && writeLockCount == 0 || readLockCount > 0 && writeLockCount == 0 || readLockCount == 0 && writeLockCount == 1; if (!countIsCorrect) { Volatile.Write(ref incorrectLockCount, true); } } bool cancel = false; var threads = new Thread[20]; var tasks = new Task[20]; var masterRandom = new Random(); for (int i = 0; i < threads.Length; i++) { var random = new Random(masterRandom.Next()); (threads[i] = new Thread(() => { bool isRead = random.Next(100) < 70; if (isRead) { myLock.EnterReadLock(); } else { myLock.EnterWriteLock(); } lock (lockCountSyncRoot) { if (isRead) { readLockCount++; } else { writeLockCount++; } } // Simulate work. Thread.Sleep(10); lock (lockCountSyncRoot) { if (isRead) { myLock.ExitReadLock(); readLockCount--; } else { myLock.ExitWriteLock(); writeLockCount--; } } })).Start(); } for (int i = 0; i < tasks.Length; i++) { var random = new Random(masterRandom.Next()); tasks[i] = Task.Run(async() => { while (!Volatile.Read(ref cancel)) { bool isRead = random.Next(10) < 7; if (isRead) { await myLock.EnterReadLockAsync(); } else { await myLock.EnterWriteLockAsync(); } lock (lockCountSyncRoot) { if (isRead) { readLockCount++; } else { writeLockCount++; } checkLockCount(); } // Simulate work. await Task.Delay(10); lock (lockCountSyncRoot) { if (isRead) { myLock.ExitReadLock(); readLockCount--; } else { myLock.ExitWriteLock(); writeLockCount--; } checkLockCount(); } } }); } // Run for 5 seconds, then stop the tasks and threads. Thread.Sleep(5000); Volatile.Write(ref cancel, true); foreach (var thread in threads) { thread.Join(); } foreach (var task in tasks) { task.GetAwaiter().GetResult(); } Assert.IsFalse(incorrectLockCount); }