2 // ReaderWriterLockSlimTest.cs
5 // Marek Safar (marek.safar@gmail.com)
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using NUnit.Framework;
31 using System.Threading;
33 using System.Threading.Tasks;
35 namespace MonoTests.System.Threading
38 public class ReaderWriterLockSlimTests
41 public void DefaultValues ()
43 var v = new ReaderWriterLockSlim ();
44 Assert.AreEqual (0, v.CurrentReadCount, "1");
45 Assert.AreEqual (false, v.IsReadLockHeld, "2");
46 Assert.AreEqual (false, v.IsUpgradeableReadLockHeld, "3");
47 Assert.AreEqual (false, v.IsWriteLockHeld, "4");
48 Assert.AreEqual (LockRecursionPolicy.NoRecursion, v.RecursionPolicy, "5");
49 Assert.AreEqual (0, v.RecursiveReadCount, "6");
50 Assert.AreEqual (0, v.RecursiveUpgradeCount, "7");
51 Assert.AreEqual (0, v.RecursiveWriteCount, "8");
52 Assert.AreEqual (0, v.WaitingReadCount, "9");
53 Assert.AreEqual (0, v.WaitingUpgradeCount, "10");
54 Assert.AreEqual (0, v.WaitingWriteCount, "11");
58 public void Dispose_Errors ()
60 var v = new ReaderWriterLockSlim ();
64 v.EnterUpgradeableReadLock ();
66 } catch (ObjectDisposedException) {
72 } catch (ObjectDisposedException) {
78 } catch (ObjectDisposedException) {
83 public void Dispose_WithReadLock ()
85 var rwl = new ReaderWriterLockSlim ();
90 } catch (SynchronizationLockException) {
95 public void Dispose_WithWriteLock ()
97 var rwl = new ReaderWriterLockSlim ();
98 rwl.EnterWriteLock ();
102 } catch (SynchronizationLockException) {
107 public void Dispose_UpgradeableReadLock ()
109 var rwl = new ReaderWriterLockSlim ();
110 rwl.EnterUpgradeableReadLock ();
114 } catch (SynchronizationLockException) {
119 public void TryEnterReadLock_OutOfRange ()
121 var v = new ReaderWriterLockSlim ();
123 v.TryEnterReadLock (-2);
125 } catch (ArgumentOutOfRangeException) {
129 v.TryEnterReadLock (TimeSpan.MaxValue);
131 } catch (ArgumentOutOfRangeException) {
135 v.TryEnterReadLock (TimeSpan.MinValue);
137 } catch (ArgumentOutOfRangeException) {
142 public void TryEnterUpgradeableReadLock_OutOfRange ()
144 var v = new ReaderWriterLockSlim ();
146 v.TryEnterUpgradeableReadLock (-2);
148 } catch (ArgumentOutOfRangeException) {
152 v.TryEnterUpgradeableReadLock (TimeSpan.MaxValue);
154 } catch (ArgumentOutOfRangeException) {
158 v.TryEnterUpgradeableReadLock (TimeSpan.MinValue);
160 } catch (ArgumentOutOfRangeException) {
165 public void TryEnterWriteLock_OutOfRange ()
167 var v = new ReaderWriterLockSlim ();
169 v.TryEnterWriteLock (-2);
171 } catch (ArgumentOutOfRangeException) {
175 v.TryEnterWriteLock (TimeSpan.MaxValue);
177 } catch (ArgumentOutOfRangeException) {
181 v.TryEnterWriteLock (TimeSpan.MinValue);
183 } catch (ArgumentOutOfRangeException) {
187 [Test, ExpectedException (typeof (SynchronizationLockException))]
188 public void ExitReadLock ()
190 var v = new ReaderWriterLockSlim ();
194 [Test, ExpectedException (typeof (SynchronizationLockException))]
195 public void ExitWriteLock ()
197 var v = new ReaderWriterLockSlim ();
202 public void EnterReadLock_NoRecursionError ()
204 var v = new ReaderWriterLockSlim ();
206 Assert.AreEqual (1, v.RecursiveReadCount);
211 } catch (LockRecursionException) {
217 } catch (LockRecursionException) {
222 public void EnterReadLock ()
224 var v = new ReaderWriterLockSlim ();
227 Assert.IsTrue (v.IsReadLockHeld, "A");
228 Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
229 Assert.AreEqual (1, v.RecursiveReadCount, "A2");
230 Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
231 Assert.AreEqual (0, v.WaitingReadCount, "A4");
232 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
233 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
237 Assert.IsTrue (v.IsReadLockHeld, "B");
238 Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
239 Assert.AreEqual (1, v.RecursiveReadCount, "B2");
240 Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
241 Assert.AreEqual (0, v.WaitingReadCount, "B4");
242 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
243 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
248 public void EnterWriteLock_NoRecursionError ()
250 var v = new ReaderWriterLockSlim ();
252 Assert.AreEqual (1, v.RecursiveWriteCount);
257 } catch (LockRecursionException) {
263 } catch (LockRecursionException) {
268 public void EnterWriteLock ()
270 var v = new ReaderWriterLockSlim ();
273 Assert.IsTrue (v.IsWriteLockHeld, "A");
274 Assert.AreEqual (1, v.RecursiveWriteCount, "A1");
275 Assert.AreEqual (0, v.RecursiveReadCount, "A2");
276 Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
277 Assert.AreEqual (0, v.WaitingReadCount, "A4");
278 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
279 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
283 Assert.IsTrue (v.IsWriteLockHeld, "B");
284 Assert.AreEqual (1, v.RecursiveWriteCount, "B1");
285 Assert.AreEqual (0, v.RecursiveReadCount, "B2");
286 Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
287 Assert.AreEqual (0, v.WaitingReadCount, "B4");
288 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
289 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
294 public void EnterUpgradeableReadLock_NoRecursionError ()
296 var v = new ReaderWriterLockSlim ();
297 v.EnterUpgradeableReadLock ();
298 Assert.AreEqual (1, v.RecursiveUpgradeCount);
301 v.EnterUpgradeableReadLock ();
303 } catch (LockRecursionException) {
308 public void EnterUpgradeableReadLock ()
310 var v = new ReaderWriterLockSlim ();
312 v.EnterUpgradeableReadLock ();
313 Assert.IsTrue (v.IsUpgradeableReadLockHeld, "A");
314 Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
315 Assert.AreEqual (0, v.RecursiveReadCount, "A2");
316 Assert.AreEqual (1, v.RecursiveUpgradeCount, "A3");
317 Assert.AreEqual (0, v.WaitingReadCount, "A4");
318 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
319 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
320 v.ExitUpgradeableReadLock ();
322 v.EnterUpgradeableReadLock ();
323 Assert.IsTrue (v.IsUpgradeableReadLockHeld, "B");
324 Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
325 Assert.AreEqual (0, v.RecursiveReadCount, "B2");
326 Assert.AreEqual (1, v.RecursiveUpgradeCount, "B3");
327 Assert.AreEqual (0, v.WaitingReadCount, "B4");
328 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
329 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
332 v.ExitUpgradeableReadLock ();
334 Assert.IsTrue (v.IsReadLockHeld, "C");
335 Assert.AreEqual (0, v.RecursiveWriteCount, "C1");
336 Assert.AreEqual (1, v.RecursiveReadCount, "C2");
337 Assert.AreEqual (0, v.RecursiveUpgradeCount, "C3");
338 Assert.AreEqual (0, v.WaitingReadCount, "C4");
339 Assert.AreEqual (0, v.WaitingUpgradeCount, "C5");
340 Assert.AreEqual (0, v.WaitingWriteCount, "C6");
346 public void EnterReadLock_MultiRead ()
348 var v = new ReaderWriterLockSlim ();
351 var r = from i in Enumerable.Range (1, 30) select new Thread (() => {
353 // Just to cause some contention
358 Assert.AreEqual (10, local);
361 var threads = r.ToList ();
363 foreach (var t in threads) {
367 foreach (var t in threads) {
368 // Console.WriteLine (t.ThreadState);
374 public void TryEnterWriteLock_WhileReading ()
376 var v = new ReaderWriterLockSlim ();
377 AutoResetEvent ev = new AutoResetEvent (false);
378 AutoResetEvent ev2 = new AutoResetEvent (false);
380 Thread t1 = new Thread (() => {
390 Assert.IsFalse (v.TryEnterWriteLock (100));
394 Assert.IsTrue (v.TryEnterWriteLock (100));
398 public void EnterWriteLock_MultiRead ()
400 var v = new ReaderWriterLockSlim ();
403 int entered_count = 0;
404 const int thread_count = 10;
406 var r = from i in Enumerable.Range (1, thread_count) select new Thread (() => {
407 Interlocked.Increment (ref ready_count);
409 Interlocked.Increment (ref entered_count);
411 Assert.AreEqual (11, local);
416 var threads = r.ToList ();
417 foreach (var t in threads) {
421 while (ready_count != thread_count)
424 /* Extra up to 2s of sleep to ensure all threads got the chance to enter the lock */
425 for (int i = 0; i < 200 && v.WaitingReadCount != thread_count; ++i)
429 Assert.AreEqual (0, v.WaitingWriteCount, "in waiting write");
430 Assert.AreEqual (thread_count, v.WaitingReadCount, "in waiting read");
431 Assert.AreEqual (0, v.WaitingUpgradeCount, "in waiting upgrade");
434 foreach (var t in threads) {
435 // Console.WriteLine (t.ThreadState);
441 public void EnterWriteLock_After_ExitUpgradeableReadLock ()
443 var v = new ReaderWriterLockSlim ();
445 v.EnterUpgradeableReadLock ();
446 Assert.IsTrue (v.TryEnterWriteLock (100));
448 v.ExitUpgradeableReadLock ();
449 Assert.IsTrue (v.TryEnterWriteLock (100));
453 public void EnterWriteLockWhileInUpgradeAndOtherWaiting ()
455 var v = new ReaderWriterLockSlim ();
457 var task2 = new Task(() => {
462 var task1 = new Task(() =>
464 v.EnterUpgradeableReadLock ();
469 v.ExitUpgradeableReadLock ();
473 Assert.IsTrue (task1.Wait (500));
476 public void RecursiveReadLockTest ()
478 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
480 Assert.IsTrue (v.TryEnterReadLock (100), "#1");
481 Assert.IsTrue (v.TryEnterReadLock (100), "#2");
482 Assert.IsTrue (v.TryEnterReadLock (100), "#3");
484 Assert.AreEqual (3, v.RecursiveReadCount);
488 public void RecursiveReadPlusWriteLockTest ()
490 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
496 } catch (LockRecursionException ex) {
497 Assert.IsNotNull (ex, "#1");
502 public void RecursiveReadPlusUpgradeableLockTest ()
504 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
508 v.EnterUpgradeableReadLock ();
510 } catch (LockRecursionException ex) {
511 Assert.IsNotNull (ex, "#1");
516 public void RecursiveWriteLockTest ()
518 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
520 Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
521 Assert.IsTrue (v.TryEnterWriteLock (100), "#2");
522 Assert.IsTrue (v.TryEnterWriteLock (100), "#3");
524 Assert.AreEqual (3, v.RecursiveWriteCount);
528 public void RecursiveWritePlusReadLockTest ()
530 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
532 Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
533 Assert.AreEqual (1, v.RecursiveWriteCount, "1b");
534 Assert.AreEqual (0, v.RecursiveReadCount, "1c");
536 Assert.IsTrue (v.TryEnterReadLock (100), "#2");
537 Assert.AreEqual (1, v.RecursiveWriteCount, "2b");
538 Assert.AreEqual (1, v.RecursiveReadCount, "2c");
540 Assert.IsTrue (v.TryEnterReadLock (100), "#3");
541 Assert.AreEqual (1, v.RecursiveWriteCount, "3b");
542 Assert.AreEqual (2, v.RecursiveReadCount, "3c");
545 Assert.AreEqual (1, v.RecursiveWriteCount, "4b");
546 Assert.AreEqual (1, v.RecursiveReadCount, "4c");
550 public void RecursiveUpgradeableReadLockTest ()
552 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
554 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#1");
555 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#2");
556 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#3");
558 Assert.AreEqual (3, v.RecursiveUpgradeCount);
562 public void RecursiveReadPropertiesTest ()
564 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
569 Assert.AreEqual (true, v.IsReadLockHeld, "#1a");
570 Assert.AreEqual (1, v.CurrentReadCount, "#2a");
571 Assert.AreEqual (2, v.RecursiveReadCount, "#3a");
574 int cReadCount = -1, rReadCount = -1;
576 Thread t = new Thread ((_) => {
577 rLock = v.IsReadLockHeld;
578 cReadCount = v.CurrentReadCount;
579 rReadCount = v.RecursiveReadCount;
585 Assert.AreEqual (false, rLock, "#1b");
586 Assert.AreEqual (1, cReadCount, "#2b");
587 Assert.AreEqual (0, rReadCount, "#3b");
591 public void RecursiveUpgradePropertiesTest ()
593 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
595 v.EnterUpgradeableReadLock ();
596 v.EnterUpgradeableReadLock ();
598 Assert.AreEqual (true, v.IsUpgradeableReadLockHeld, "#1a");
599 Assert.AreEqual (false, v.IsReadLockHeld, "#11a");
600 Assert.AreEqual (0, v.CurrentReadCount, "#2a");
601 Assert.AreEqual (2, v.RecursiveUpgradeCount, "#3a");
603 bool upLock = false, rLock = false;
604 int rCount = -1, rUCount = -1;
606 Thread t = new Thread ((_) => {
607 upLock = v.IsUpgradeableReadLockHeld;
608 rLock = v.IsReadLockHeld;
609 rCount = v.CurrentReadCount;
610 rUCount = v.RecursiveUpgradeCount;
616 Assert.AreEqual (false, upLock, "#1b");
617 Assert.AreEqual (false, rLock, "#11b");
618 Assert.AreEqual (0, rCount, "#2b");
619 Assert.AreEqual (0, rUCount, "#3b");
623 public void RecursiveWritePropertiesTest ()
625 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
630 Assert.AreEqual (true, v.IsWriteLockHeld, "#1a");
631 Assert.AreEqual (2, v.RecursiveWriteCount, "#3a");
636 Thread t = new Thread ((_) => {
637 wLock = v.IsWriteLockHeld;
638 rWrite = v.RecursiveWriteCount;
644 Assert.AreEqual (false, wLock, "#1b");
645 Assert.AreEqual (0, rWrite, "#3b");
649 public void RecursiveEnterExitReadTest ()
651 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
657 Assert.IsTrue (v.IsReadLockHeld);
658 Assert.AreEqual (3, v.RecursiveReadCount);
662 Assert.IsTrue (v.IsReadLockHeld);
663 Assert.AreEqual (2, v.RecursiveReadCount);
667 public void RecursiveEnterExitWriteTest ()
669 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
675 Assert.IsTrue (v.IsWriteLockHeld);
676 Assert.AreEqual (3, v.RecursiveWriteCount);
681 Assert.IsTrue (v.IsWriteLockHeld);
682 Assert.AreEqual (1, v.RecursiveWriteCount);
686 public void RecursiveEnterExitUpgradableTest ()
688 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
690 v.EnterUpgradeableReadLock ();
691 v.EnterUpgradeableReadLock ();
692 v.EnterUpgradeableReadLock ();
694 Assert.IsTrue (v.IsUpgradeableReadLockHeld);
695 Assert.AreEqual (3, v.RecursiveUpgradeCount);
697 v.ExitUpgradeableReadLock ();
699 Assert.IsTrue (v.IsUpgradeableReadLockHeld);
700 Assert.AreEqual (2, v.RecursiveUpgradeCount);
704 public void RecursiveWriteUpgradeReadTest ()
706 var rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
708 rwlock.EnterWriteLock ();
709 Assert.IsTrue (rwlock.IsWriteLockHeld);
710 rwlock.EnterUpgradeableReadLock ();
711 Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
712 rwlock.EnterReadLock ();
713 Assert.IsTrue (rwlock.IsReadLockHeld);
714 rwlock.ExitUpgradeableReadLock();
715 Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
716 Assert.IsTrue (rwlock.IsReadLockHeld);
717 Assert.IsTrue (rwlock.IsWriteLockHeld);
719 rwlock.ExitReadLock ();
720 Assert.IsTrue (rwlock.IsWriteLockHeld);
724 public void RecursiveWriteUpgradeTest ()
726 ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
728 rwlock.EnterWriteLock ();
729 Assert.IsTrue (rwlock.IsWriteLockHeld);
730 rwlock.EnterUpgradeableReadLock ();
731 Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
732 rwlock.ExitUpgradeableReadLock ();
733 Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
734 Assert.IsTrue (rwlock.IsWriteLockHeld);
735 rwlock.ExitWriteLock ();
736 Assert.IsFalse (rwlock.IsWriteLockHeld);
737 rwlock.EnterWriteLock ();
738 Assert.IsTrue (rwlock.IsWriteLockHeld);
742 public void RecursiveWriteReadAcquisitionInterleaving ()
744 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
747 Assert.IsTrue (v.IsWriteLockHeld, "#1");
750 var t = new Thread (delegate () {
751 result = v.TryEnterReadLock (100);
755 Assert.IsFalse (result, "#2");
758 t = new Thread (delegate () {
759 result = v.TryEnterReadLock (100);
763 Assert.IsTrue (result, "#3");