public void CanEnterWrite() { var x = new ReadWriteLock(); using (x.EnterWrite()) { Assert.IsTrue(x.IsCurrentThreadWriter); } }
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 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 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 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 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 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 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 }