public void CannotReentryReadToWriteWhenThereAreMoreReaders() { using (var w1 = new ManualResetEvent(false)) { using (var w2 = new ManualResetEvent(false)) { using (var x = new ReadWriteLock(true)) { var ok = true; var a = new Thread ( () => { using (x.EnterRead()) { w2.Set(); w1.WaitOne(); } } ); a.Start(); w2.WaitOne(); using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); IDisposable engagement = null; try { ok &= !x.TryEnterWrite(out engagement); } finally { if (engagement != null) { engagement.Dispose(); } } } w1.Set(); a.Join(); using (x.EnterRead()) { using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); Assert.IsTrue(ok); } } } // This code results in a dead lock in a not reentrant ReadWriteLock } } }
public void CanReentryReadToRead() { var x = new ReadWriteLock(); using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); } } }
public void CanKnowIsReader() { // Reentrant ReadWriteLock is able to tell if a therad is a reader using (var x = new ReadWriteLock(true)) { Assert.IsFalse(x.HasReader); using (x.EnterRead()) { Assert.IsTrue(x.IsCurrentThreadReader); Assert.IsTrue(x.HasReader); } // Not Reentrant ReadWriteLock is not using (var y = new ReadWriteLock(false)) { Assert.IsFalse(y.HasReader); using (y.EnterRead()) { Assert.Throws(typeof(NotSupportedException), () => GC.KeepAlive(y.IsCurrentThreadReader)); Assert.IsTrue(y.HasReader); } // ReadWriteLock is not reentrant by default using (var z = new ReadWriteLock()) { Assert.IsFalse(z.HasReader); using (z.EnterRead()) { Assert.Throws(typeof(NotSupportedException), () => GC.KeepAlive(z.IsCurrentThreadReader)); Assert.IsTrue(z.HasReader); } } } } }
public void CannotWriteWhileReading() { using (var x = new ReadWriteLock()) { var ok = true; var doneThread = false; using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); var a = new Thread ( () => { IDisposable engagement = null; try { ok &= !x.TryEnterWrite(out engagement); } finally { if (engagement != null) { engagement.Dispose(); } doneThread = true; } } ); a.Start(); a.Join(); } Assert.IsTrue(ok); Assert.IsTrue(doneThread); } }
public void ReentryReadToWriteCheck() { var w = new ManualResetEvent(false); var x = new ReadWriteLock(); var enterCount = 0; var doneCount = 0; var errorCount = 0; var successCount = 0; ThreadStart tmp = () => { using (x.EnterRead()) { Interlocked.Increment(ref enterCount); w.WaitOne(); // If a thread is a reader it can become a writer as long as there are no other readers // When we have multiple readers trying to become a writer... IDisposable engagement = null; try { // Write mode is not requested - there are other readers which we don't wait to leave if (x.TryEnterWrite(out engagement)) { Interlocked.Increment(ref successCount); } else { Interlocked.Increment(ref errorCount); } } finally { if (engagement != null) { engagement.Dispose(); } } } Interlocked.Increment(ref doneCount); }; var threads = new Thread[5]; for (int index = 0; index < 5; index++) { threads[index] = new Thread(tmp); } for (int index = 0; index < 5; index++) { threads[index].Start(); } Thread.Sleep(10); Assert.AreEqual(5, enterCount); w.Set(); for (int index = 0; index < 5; index++) { threads[index].Join(); } Assert.AreEqual(5, doneCount); Assert.AreEqual(0, successCount); // None succeds Assert.AreEqual(5, errorCount); // All fail }
public void MultipleReadersAtTheTime() { var w = new ManualResetEvent(false); var x = new ReadWriteLock(); int[] z = { 0 }; var threads = new Thread[5]; for (int index = 0; index < 5; index++) { threads[index] = new Thread ( () => { w.WaitOne(); using (x.EnterRead()) { Interlocked.Increment(ref z[0]); Thread.Sleep(10); } } ); } for (int index = 0; index < 5; index++) { threads[index].Start(); } w.Set(); for (int index = 0; index < 5; index++) { threads[index].Join(); } Assert.AreEqual(6, Interlocked.Increment(ref z[0])); }
public void ReentryReadToWriteRaceCondition() { using (var w = new ManualResetEvent(false)) { using (var x = new ReadWriteLock(true)) { var enterCount = 0; var doneCount = 0; var errorCount = 0; var successCount = 0; ThreadStart tmp = () => { using (x.EnterRead()) { Interlocked.Increment(ref enterCount); w.WaitOne(); // If a thread is a reader it can become a writer as long as there are no other readers // When we have multiple readers trying to become a writer... try { // write mode is requested and reserved by one thread - others fail using (x.EnterWrite()) { Interlocked.Increment(ref successCount); } } catch (InvalidOperationException) { Interlocked.Increment(ref errorCount); } } Interlocked.Increment(ref doneCount); }; var threads = new Thread[5]; for (var index = 0; index < 5; index++) { threads[index] = new Thread(tmp); } for (var index = 0; index < 5; index++) { threads[index].Start(); } do { Thread.Sleep(10); } while (enterCount < 5); w.Set(); for (var index = 0; index < 5; index++) { threads[index].Join(); } Assert.AreEqual(5, doneCount); Assert.AreEqual(1, successCount); // One succeds - the thread that succeds to reserve write waits for others to leave Assert.AreEqual(4, errorCount); // The others get InvalidOperationException - the threads that fail the reserve fail } // This code results in a dead lock in a not reentrant ReadWriteLock } }
public void WriteWaitsMultipleReadsToFinish() // TODO: Review { using (var w0 = new ManualResetEvent(false)) { using (var w1 = new ManualResetEvent(false)) { using (var x = new ReadWriteLock()) { var ok = false; int[] z = { 0 }; var threads = new Thread[5]; for (var index = 0; index < 5; index++) { threads[index] = new Thread ( () => { w0.WaitOne(); using (x.EnterRead()) { w1.Set(); Interlocked.Increment(ref z[0]); Thread.Sleep(10); } } ); } var a = new Thread ( () => { w1.WaitOne(); using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); ok = Interlocked.Increment(ref z[0]) == 6; } } ); for (var index = 0; index < 5; index++) { threads[index].Start(); } a.Start(); w0.Set(); for (var index = 0; index < 5; index++) { threads[index].Join(); } a.Join(); Assert.IsTrue(ok); Assert.AreEqual(7, Interlocked.Increment(ref z[0])); } } } }
public void CanEnterRead() { using (var x = new ReadWriteLock()) { using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); } } }
public void CanReentryWriteToRead() { var x = new ReadWriteLock(); using (x.EnterWrite()) { // If a thread is a writer it can be also a reader using (x.EnterRead()) { } } }
public void CanReentryReadToWrite() { var x = new ReadWriteLock(true); // This code results in a dead lock in a not reentrant ReadWriteLock using (x.EnterRead()) { Assert.IsFalse(x.IsCurrentThreadWriter); // If a thread is a reader it can become a writer as long as there are no other readers using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); } } }
public void WriteWaitsReadToFinish() { using (var w = new ManualResetEvent(false)) { using (var x = new ReadWriteLock()) { int[] z = { 0 }; var ok = true; var a = new Thread ( () => { w.WaitOne(); using (x.EnterWrite()) { ok = ok && Interlocked.Increment(ref z[0]) == 2; } } ); var b = new Thread ( () => { using (x.EnterRead()) { w.Set(); Thread.Sleep(10); ok = ok && Interlocked.Increment(ref z[0]) == 1; } } ); a.Start(); b.Start(); a.Join(); b.Join(); Assert.IsTrue(ok); Assert.AreEqual(3, Interlocked.Increment(ref z[0])); } } }
public void WriteWaitsMultipleReadsToFinish() { using (var w0 = new ManualResetEvent(false)) { using (var w1 = new ManualResetEvent(false)) { using (var x = new ReadWriteLock()) { int[] z = { 0, 0 }; var foundReaders = -1; var ok = false; var threads = new Thread[5]; for (var index = 0; index < 5; index++) { threads[index] = new Thread ( () => { w0.WaitOne(); using (x.EnterRead()) { Interlocked.Increment(ref z[1]); w1.Set(); Interlocked.Increment(ref z[0]); Thread.Sleep(10); Interlocked.Decrement(ref z[1]); } } ); } var a = new Thread ( () => { w1.WaitOne(); using (x.EnterWrite()) { foundReaders = Volatile.Read(ref z[1]); ok = x.IsCurrentThreadWriter; Interlocked.Increment(ref z[0]); } } ); for (var index = 0; index < 5; index++) { threads[index].Start(); } a.Start(); w0.Set(); for (var index = 0; index < 5; index++) { threads[index].Join(); } a.Join(); Assert.IsTrue(ok); Assert.AreEqual(0, foundReaders); Assert.AreEqual(7, Interlocked.Increment(ref z[0])); } } } }