public void CanEnterWrite() { var x = new ReadWriteLock(); using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); } }
public void CanEnterWriteEx() { var x = new ReadWriteLock(); IDisposable engagement = null; try { if (x.TryEnterWrite(out engagement)) { Assert.IsTrue(x.IsCurrentThreadWriter); } else { Assert.Fail(); } } finally { if (engagement != null) { engagement.Dispose(); } } }
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 CanReentryWriteToWriteEx() { var x = new ReadWriteLock(); IDisposable engagementA = null; try { if (x.TryEnterWrite(out engagementA)) { Assert.IsTrue(x.IsCurrentThreadWriter); IDisposable engagementB = null; try { if (x.TryEnterWrite(out engagementB)) { Assert.IsTrue(x.IsCurrentThreadWriter); } else { Assert.Fail(); } } finally { if (engagementB != null) { engagementB.Dispose(); } } } else { Assert.Fail(); } } finally { if (engagementA != null) { engagementA.Dispose(); } } }
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 CanReentryReadToWriteEx() { var x = new ReadWriteLock(false); IDisposable engagementA = null; try { if (x.TryEnterRead(out engagementA)) { Assert.IsFalse(x.IsCurrentThreadWriter); IDisposable engagementB = null; try { if (x.TryEnterWrite(out engagementB)) { Assert.Fail(); } else { // Not reentrant ReadWriteLock will not be able to upgrade the lock Assert.IsFalse(x.IsCurrentThreadWriter); } } finally { if (engagementB != null) { engagementB.Dispose(); } } } else { Assert.Fail(); } } finally { if (engagementA != null) { engagementA.Dispose(); } } // var y = new ReadWriteLock(true); IDisposable engagementC = null; try { if (y.TryEnterRead(out engagementC)) { Assert.IsFalse(y.IsCurrentThreadWriter); IDisposable engagementD = null; try { if (y.TryEnterWrite(out engagementD)) { // Reentrant ReadWriteLock will be able to upgrade the lock Assert.IsTrue(y.IsCurrentThreadWriter); } else { Assert.Fail(); } } finally { if (engagementD != null) { engagementD.Dispose(); } } } else { Assert.Fail(); } } finally { if (engagementC != null) { engagementC.Dispose(); } } }
public void WriteWaitsMultipleReadsToFinish() { var w0 = new ManualResetEvent(false); var w1 = new ManualResetEvent(false); var x = new ReadWriteLock(); var ok = false; int[] z = { 0 }; var threads = new Thread[5]; for (int 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 (int index = 0; index < 5; index++) { threads[index].Start(); } a.Start(); w0.Set(); for (int index = 0; index < 5; index++) { threads[index].Join(); } a.Join(); Assert.IsTrue(ok); Assert.AreEqual(7, Interlocked.Increment(ref z[0])); }
public void OnlyOneWriterAtTheTimeEx() { var w = new ManualResetEvent(false); var x = new ReadWriteLock(); var doneThread = 0; var ok = true; ThreadStart tmp = () => { w.WaitOne(); IDisposable engagementA = null; try { if (x.TryEnterWrite(out engagementA)) { ok = false; } } finally { if (engagementA != null) { engagementA.Dispose(); } Interlocked.Increment(ref doneThread); } }; var a = new Thread(tmp); using (x.EnterWrite()) { a.Start(); w.Set(); Thread.Sleep(10); } a.Join(); Assert.IsTrue(ok); Assert.AreEqual(1, doneThread); var b = new Thread(tmp); IDisposable engagementB = null; try { if (x.TryEnterWrite(out engagementB)) { Assert.IsTrue(x.IsCurrentThreadWriter); b.Start(); w.Set(); b.Join(); } else { Assert.Fail(); } } finally { if (engagementB != null) { engagementB.Dispose(); } } Assert.IsTrue(ok); Assert.AreEqual(2, doneThread); }
public void CannotWriteWhileWriting() { var x = new ReadWriteLock(); var ok = true; var doneThread = false; using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); var a = new Thread ( () => { IDisposable engagement = null; try { if (x.TryEnterWrite(out engagement)) { ok = false; } } finally { if (engagement != null) { engagement.Dispose(); } doneThread = true; } } ); a.Start(); a.Join(); } Assert.IsTrue(ok); Assert.IsTrue(doneThread); }
public void CanReadWhileReadingEx() { var x = new ReadWriteLock(); var ok = true; var doneThread = false; IDisposable engagementA = null; try { if (x.TryEnterRead(out engagementA)) { Assert.IsFalse(x.IsCurrentThreadWriter); var a = new Thread ( () => { IDisposable engagementB = null; try { if (x.TryEnterRead(out engagementB)) { } else { ok = false; } } finally { if (engagementB != null) { engagementB.Dispose(); } doneThread = true; } } ); a.Start(); a.Join(); } } finally { if (engagementA != null) { engagementA.Dispose(); } doneThread = true; } Assert.IsTrue(ok); Assert.IsTrue(doneThread); }
public void CannotReentryReadToWriteWhenThereAreMoreReaders() { var w1 = new ManualResetEvent(false); var w2 = new ManualResetEvent(false); var x = new ReadWriteLock(true); // This code results in a dead lock in a not reentrant ReadWriteLock 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 { if (x.TryEnterWrite(out engagement)) { ok = false; } } finally { if (engagement != null) { engagement.Dispose(); } } } w1.Set(); a.Join(); using (x.EnterRead()) { using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); Assert.IsTrue(ok); } } }
public void CanKnowIsWriter() { // ReadWriteLock always able to tell if a therad is the writer var x = new ReadWriteLock(true); Assert.IsFalse(x.HasWriter); using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); Assert.IsTrue(x.HasWriter); } // Not Reentrant ReadWriteLock is not var y = new ReadWriteLock(false); Assert.IsFalse(y.HasWriter); using (y.EnterWrite()) { Assert.IsTrue(y.IsCurrentThreadWriter); Assert.IsTrue(y.HasWriter); } // ReadWriteLock is not reentrant by default var z = new ReadWriteLock(); Assert.IsFalse(z.HasWriter); using (z.EnterWrite()) { Assert.IsTrue(z.IsCurrentThreadWriter); Assert.IsTrue(z.HasWriter); } }
public void WriteWaitsReadToFinish() { var w = new ManualResetEvent(false); 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 OnlyOneWriterAtTheTime() { var w = new ManualResetEvent(false); var x = new ReadWriteLock(); int[] z = { 0 }; var ok = true; var threads = new Thread[5]; for (int index = 0; index < 5; index++) { threads[index] = new Thread ( () => { w.WaitOne(); using (x.EnterWrite()) { var got = Interlocked.Increment(ref z[0]); Thread.Sleep(10); ok = ok && Interlocked.Increment(ref z[0]) == got + 1; } } ); } for (int index = 0; index < 5; index++) { threads[index].Start(); } w.Set(); for (int index = 0; index < 5; index++) { threads[index].Join(); } Assert.IsTrue(ok); Assert.AreEqual(11, Interlocked.Increment(ref z[0])); }
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 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 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 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 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 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 ReentryReadToWriteRaceCondition() { var w = new ManualResetEvent(false); var x = new ReadWriteLock(true); // This code results in a dead lock in a not reentrant 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... 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 (int index = 0; index < 5; index++) { threads[index] = new Thread(tmp); } for (int index = 0; index < 5; index++) { threads[index].Start(); } do { Thread.Sleep(10); } while (enterCount < 5); w.Set(); for (int 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 }