public void CannotWriteWhileWritingEx() { var x = new ReadWriteLock(); var ok = true; var doneThread = false; IDisposable engagementA = null; try { if (x.TryEnterWrite(out engagementA)) { Assert.IsTrue(x.IsCurrentThreadWriter); var a = new Thread ( () => { IDisposable engagementB = null; try { if (x.TryEnterWrite(out engagementB)) { 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 CanEnterWriteEx() { using (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 CannotWriteWhileWriting() { using (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 { 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 CanReentryWriteToWriteEx() { using (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 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 OnlyOneWriterAtTheTimeEx() // TODO: Review - race condition { using (var w = new ManualResetEvent(false)) { using (var x = new ReadWriteLock()) { var doneThread = 0; var ok = true; ThreadStart tmp = () => { w.WaitOne(); IDisposable engagementA = null; try { ok &= !x.TryEnterWrite(out engagementA); } 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 CanReentryReadToWriteEx() { using (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(); } } // using (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(); } } } } }