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);
        }