public async Task MixedSyncAndAsync() { var myLock = new AsyncReaderWriterLockSlim(); myLock.EnterReadLock(); await myLock.EnterReadLockAsync(); myLock.ExitReadLock(); myLock.ExitReadLock(); myLock.EnterWriteLock(); Assert.IsFalse(await myLock.TryEnterWriteLockAsync(10)); myLock.ExitWriteLock(); }
public void CanEnterLocksSync() { var myLock = new AsyncReaderWriterLockSlim(); myLock.EnterReadLock(); Assert.IsTrue(myLock.TryEnterReadLock(0)); Assert.IsFalse(myLock.TryEnterWriteLock(0)); myLock.ExitReadLock(); myLock.ExitReadLock(); myLock.EnterWriteLock(); Assert.IsFalse(myLock.TryEnterReadLock(0)); Assert.IsFalse(myLock.TryEnterWriteLock(0)); myLock.ExitWriteLock(); }
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 void DowngradeLockAllowsReadLock() { var myLock = new AsyncReaderWriterLockSlim(); myLock.EnterWriteLock(); Assert.IsFalse(myLock.TryEnterWriteLock(0)); Assert.IsFalse(myLock.TryEnterReadLock(0)); // After downgrading the lock and after the try to get the write lock is canceled, // it should be possible to enter another read lock. myLock.DowngradeWriteLockToReadLock(); Assert.IsFalse(myLock.TryEnterWriteLock(0)); Assert.IsTrue(myLock.TryEnterReadLock(0)); myLock.ExitReadLock(); myLock.ExitReadLock(); }
public async Task ReleasingOneOfTwoReadLocksDoesNotReleaseWaitingWriteAndReadLocks() { var myLock = new AsyncReaderWriterLockSlim(); await myLock.EnterReadLockAsync(); await myLock.EnterReadLockAsync(); var writeLockTask = myLock.TryEnterWriteLockAsync(500); var readLockTask = myLock.TryEnterReadLockAsync(300); // When releasing one of the two read locks, the waiting write lock should not // be released, and also the waiting read lock should not be released because of // the waiting write lock. myLock.ExitReadLock(); Assert.IsFalse(await readLockTask); Assert.IsFalse(await writeLockTask); }
public void MultipleThreads() { var myLock = new AsyncReaderWriterLockSlim(); myLock.EnterReadLock(); bool enteredWriteLock = false; var t1 = new Thread(() => { myLock.EnterWriteLock(); Volatile.Write(ref enteredWriteLock, true); myLock.ExitWriteLock(); }); t1.Start(); // Wait a bit, then release the read lock, so that the other thread can enter // the write lock. Thread.Sleep(200); Assert.IsFalse(Volatile.Read(ref enteredWriteLock)); myLock.ExitReadLock(); t1.Join(); Assert.IsTrue(Volatile.Read(ref enteredWriteLock)); }
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); }