public void TestReadWriteLockSlim() { var sentry = new ReaderWriterLockSlim(); var sw = new Stopwatch(); sw.Start(); var barrier = new CountdownEvent(4); //first read ThreadPool.QueueUserWorkItem(_ => { using (sentry.UsingReadLock()) { Console.WriteLine("Acquired read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); Console.WriteLine("Releasing read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); } barrier.Signal(); }); //write ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(100); using (sentry.UsingWriteLock()) { Console.WriteLine("Acquired write: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); Console.WriteLine("Releasing write: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); } barrier.Signal(); }); //read that starts after write but executes before ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(200); using (sentry.UsingReadLock()) { Console.WriteLine("Acquired read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); Console.WriteLine("Releasing read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); } barrier.Signal(); }); //this read task must wait for write on ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(1000); using (sentry.UsingReadLock()) { Console.WriteLine("Acquired read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); Console.WriteLine("Releasing read: {0}ms, thread={1}", sw.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId); } barrier.Signal(); }); barrier.Wait(); sw.Stop(); Console.WriteLine("Test finished"); }