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;
34 using System.Threading.Tasks;
37 namespace MonoTests.System.Threading
40 public class ReaderWriterLockSlimTests
43 public void DefaultValues ()
45 var v = new ReaderWriterLockSlim ();
46 Assert.AreEqual (0, v.CurrentReadCount, "1");
47 Assert.AreEqual (false, v.IsReadLockHeld, "2");
48 Assert.AreEqual (false, v.IsUpgradeableReadLockHeld, "3");
49 Assert.AreEqual (false, v.IsWriteLockHeld, "4");
50 Assert.AreEqual (LockRecursionPolicy.NoRecursion, v.RecursionPolicy, "5");
51 Assert.AreEqual (0, v.RecursiveReadCount, "6");
52 Assert.AreEqual (0, v.RecursiveUpgradeCount, "7");
53 Assert.AreEqual (0, v.RecursiveWriteCount, "8");
54 Assert.AreEqual (0, v.WaitingReadCount, "9");
55 Assert.AreEqual (0, v.WaitingUpgradeCount, "10");
56 Assert.AreEqual (0, v.WaitingWriteCount, "11");
60 public void Dispose_Errors ()
62 var v = new ReaderWriterLockSlim ();
66 v.EnterUpgradeableReadLock ();
68 } catch (ObjectDisposedException) {
74 } catch (ObjectDisposedException) {
80 } catch (ObjectDisposedException) {
85 public void Dispose_WithReadLock ()
87 var rwl = new ReaderWriterLockSlim ();
92 } catch (SynchronizationLockException) {
97 public void Dispose_WithWriteLock ()
99 var rwl = new ReaderWriterLockSlim ();
100 rwl.EnterWriteLock ();
104 } catch (SynchronizationLockException) {
109 public void Dispose_UpgradeableReadLock ()
111 var rwl = new ReaderWriterLockSlim ();
112 rwl.EnterUpgradeableReadLock ();
116 } catch (SynchronizationLockException) {
121 public void TryEnterReadLock_OutOfRange ()
123 var v = new ReaderWriterLockSlim ();
125 v.TryEnterReadLock (-2);
127 } catch (ArgumentOutOfRangeException) {
131 v.TryEnterReadLock (TimeSpan.MaxValue);
133 } catch (ArgumentOutOfRangeException) {
137 v.TryEnterReadLock (TimeSpan.MinValue);
139 } catch (ArgumentOutOfRangeException) {
144 public void TryEnterUpgradeableReadLock_OutOfRange ()
146 var v = new ReaderWriterLockSlim ();
148 v.TryEnterUpgradeableReadLock (-2);
150 } catch (ArgumentOutOfRangeException) {
154 v.TryEnterUpgradeableReadLock (TimeSpan.MaxValue);
156 } catch (ArgumentOutOfRangeException) {
160 v.TryEnterUpgradeableReadLock (TimeSpan.MinValue);
162 } catch (ArgumentOutOfRangeException) {
167 public void TryEnterWriteLock_OutOfRange ()
169 var v = new ReaderWriterLockSlim ();
171 v.TryEnterWriteLock (-2);
173 } catch (ArgumentOutOfRangeException) {
177 v.TryEnterWriteLock (TimeSpan.MaxValue);
179 } catch (ArgumentOutOfRangeException) {
183 v.TryEnterWriteLock (TimeSpan.MinValue);
185 } catch (ArgumentOutOfRangeException) {
189 [Test, ExpectedException (typeof (SynchronizationLockException))]
190 public void ExitReadLock ()
192 var v = new ReaderWriterLockSlim ();
196 [Test, ExpectedException (typeof (SynchronizationLockException))]
197 public void ExitWriteLock ()
199 var v = new ReaderWriterLockSlim ();
204 public void EnterReadLock_NoRecursionError ()
206 var v = new ReaderWriterLockSlim ();
208 Assert.AreEqual (1, v.RecursiveReadCount);
213 } catch (LockRecursionException) {
219 } catch (LockRecursionException) {
224 public void EnterReadLock ()
226 var v = new ReaderWriterLockSlim ();
229 Assert.IsTrue (v.IsReadLockHeld, "A");
230 Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
231 Assert.AreEqual (1, v.RecursiveReadCount, "A2");
232 Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
233 Assert.AreEqual (0, v.WaitingReadCount, "A4");
234 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
235 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
239 Assert.IsTrue (v.IsReadLockHeld, "B");
240 Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
241 Assert.AreEqual (1, v.RecursiveReadCount, "B2");
242 Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
243 Assert.AreEqual (0, v.WaitingReadCount, "B4");
244 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
245 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
250 public void EnterWriteLock_NoRecursionError ()
252 var v = new ReaderWriterLockSlim ();
254 Assert.AreEqual (1, v.RecursiveWriteCount);
259 } catch (LockRecursionException) {
265 } catch (LockRecursionException) {
270 public void EnterWriteLock ()
272 var v = new ReaderWriterLockSlim ();
275 Assert.IsTrue (v.IsWriteLockHeld, "A");
276 Assert.AreEqual (1, v.RecursiveWriteCount, "A1");
277 Assert.AreEqual (0, v.RecursiveReadCount, "A2");
278 Assert.AreEqual (0, v.RecursiveUpgradeCount, "A3");
279 Assert.AreEqual (0, v.WaitingReadCount, "A4");
280 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
281 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
285 Assert.IsTrue (v.IsWriteLockHeld, "B");
286 Assert.AreEqual (1, v.RecursiveWriteCount, "B1");
287 Assert.AreEqual (0, v.RecursiveReadCount, "B2");
288 Assert.AreEqual (0, v.RecursiveUpgradeCount, "B3");
289 Assert.AreEqual (0, v.WaitingReadCount, "B4");
290 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
291 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
296 public void EnterUpgradeableReadLock_NoRecursionError ()
298 var v = new ReaderWriterLockSlim ();
299 v.EnterUpgradeableReadLock ();
300 Assert.AreEqual (1, v.RecursiveUpgradeCount);
303 v.EnterUpgradeableReadLock ();
305 } catch (LockRecursionException) {
310 public void EnterUpgradeableReadLock ()
312 var v = new ReaderWriterLockSlim ();
314 v.EnterUpgradeableReadLock ();
315 Assert.IsTrue (v.IsUpgradeableReadLockHeld, "A");
316 Assert.AreEqual (0, v.RecursiveWriteCount, "A1");
317 Assert.AreEqual (0, v.RecursiveReadCount, "A2");
318 Assert.AreEqual (1, v.RecursiveUpgradeCount, "A3");
319 Assert.AreEqual (0, v.WaitingReadCount, "A4");
320 Assert.AreEqual (0, v.WaitingUpgradeCount, "A5");
321 Assert.AreEqual (0, v.WaitingWriteCount, "A6");
322 v.ExitUpgradeableReadLock ();
324 v.EnterUpgradeableReadLock ();
325 Assert.IsTrue (v.IsUpgradeableReadLockHeld, "B");
326 Assert.AreEqual (0, v.RecursiveWriteCount, "B1");
327 Assert.AreEqual (0, v.RecursiveReadCount, "B2");
328 Assert.AreEqual (1, v.RecursiveUpgradeCount, "B3");
329 Assert.AreEqual (0, v.WaitingReadCount, "B4");
330 Assert.AreEqual (0, v.WaitingUpgradeCount, "B5");
331 Assert.AreEqual (0, v.WaitingWriteCount, "B6");
334 v.ExitUpgradeableReadLock ();
336 Assert.IsTrue (v.IsReadLockHeld, "C");
337 Assert.AreEqual (0, v.RecursiveWriteCount, "C1");
338 Assert.AreEqual (1, v.RecursiveReadCount, "C2");
339 Assert.AreEqual (0, v.RecursiveUpgradeCount, "C3");
340 Assert.AreEqual (0, v.WaitingReadCount, "C4");
341 Assert.AreEqual (0, v.WaitingUpgradeCount, "C5");
342 Assert.AreEqual (0, v.WaitingWriteCount, "C6");
348 public void EnterReadLock_MultiRead ()
350 var v = new ReaderWriterLockSlim ();
353 var r = from i in Enumerable.Range (1, 30) select new Thread (() => {
355 // Just to cause some contention
360 Assert.AreEqual (10, local);
363 var threads = r.ToList ();
365 foreach (var t in threads) {
369 foreach (var t in threads) {
370 // Console.WriteLine (t.ThreadState);
376 public void TryEnterWriteLock_WhileReading ()
378 var v = new ReaderWriterLockSlim ();
379 AutoResetEvent ev = new AutoResetEvent (false);
380 AutoResetEvent ev2 = new AutoResetEvent (false);
382 Thread t1 = new Thread (() => {
392 Assert.IsFalse (v.TryEnterWriteLock (100));
396 Assert.IsTrue (v.TryEnterWriteLock (100));
400 public void EnterWriteLock_MultiRead ()
402 var v = new ReaderWriterLockSlim ();
405 int entered_count = 0;
406 const int thread_count = 10;
408 var r = from i in Enumerable.Range (1, thread_count) select new Thread (() => {
409 Interlocked.Increment (ref ready_count);
411 Interlocked.Increment (ref entered_count);
413 Assert.AreEqual (11, local);
418 var threads = r.ToList ();
419 foreach (var t in threads) {
423 while (ready_count != thread_count)
426 /* Extra up to 2s of sleep to ensure all threads got the chance to enter the lock */
427 for (int i = 0; i < 200 && v.WaitingReadCount != thread_count; ++i)
431 Assert.AreEqual (0, v.WaitingWriteCount, "in waiting write");
432 Assert.AreEqual (thread_count, v.WaitingReadCount, "in waiting read");
433 Assert.AreEqual (0, v.WaitingUpgradeCount, "in waiting upgrade");
436 foreach (var t in threads) {
437 // Console.WriteLine (t.ThreadState);
443 public void EnterWriteLock_After_ExitUpgradeableReadLock ()
445 var v = new ReaderWriterLockSlim ();
447 v.EnterUpgradeableReadLock ();
448 Assert.IsTrue (v.TryEnterWriteLock (100));
450 v.ExitUpgradeableReadLock ();
451 Assert.IsTrue (v.TryEnterWriteLock (100));
456 public void EnterWriteLockWhileInUpgradeAndOtherWaiting ()
458 var v = new ReaderWriterLockSlim ();
460 var task2 = new Task(() => {
465 var task1 = new Task(() =>
467 v.EnterUpgradeableReadLock ();
472 v.ExitUpgradeableReadLock ();
476 Assert.IsTrue (task1.Wait (500));
480 public void RecursiveReadLockTest ()
482 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
484 Assert.IsTrue (v.TryEnterReadLock (100), "#1");
485 Assert.IsTrue (v.TryEnterReadLock (100), "#2");
486 Assert.IsTrue (v.TryEnterReadLock (100), "#3");
488 Assert.AreEqual (3, v.RecursiveReadCount);
492 public void RecursiveReadPlusWriteLockTest ()
494 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
500 } catch (LockRecursionException ex) {
501 Assert.IsNotNull (ex, "#1");
506 public void RecursiveReadPlusUpgradeableLockTest ()
508 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
512 v.EnterUpgradeableReadLock ();
514 } catch (LockRecursionException ex) {
515 Assert.IsNotNull (ex, "#1");
520 public void RecursiveWriteLockTest ()
522 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
524 Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
525 Assert.IsTrue (v.TryEnterWriteLock (100), "#2");
526 Assert.IsTrue (v.TryEnterWriteLock (100), "#3");
528 Assert.AreEqual (3, v.RecursiveWriteCount);
532 public void RecursiveWritePlusReadLockTest ()
534 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
536 Assert.IsTrue (v.TryEnterWriteLock (100), "#1");
537 Assert.AreEqual (1, v.RecursiveWriteCount, "1b");
538 Assert.AreEqual (0, v.RecursiveReadCount, "1c");
540 Assert.IsTrue (v.TryEnterReadLock (100), "#2");
541 Assert.AreEqual (1, v.RecursiveWriteCount, "2b");
542 Assert.AreEqual (1, v.RecursiveReadCount, "2c");
544 Assert.IsTrue (v.TryEnterReadLock (100), "#3");
545 Assert.AreEqual (1, v.RecursiveWriteCount, "3b");
546 Assert.AreEqual (2, v.RecursiveReadCount, "3c");
549 Assert.AreEqual (1, v.RecursiveWriteCount, "4b");
550 Assert.AreEqual (1, v.RecursiveReadCount, "4c");
554 public void RecursiveUpgradeableReadLockTest ()
556 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
558 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#1");
559 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#2");
560 Assert.IsTrue (v.TryEnterUpgradeableReadLock (100), "#3");
562 Assert.AreEqual (3, v.RecursiveUpgradeCount);
566 public void RecursiveReadPropertiesTest ()
568 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
573 Assert.AreEqual (true, v.IsReadLockHeld, "#1a");
574 Assert.AreEqual (1, v.CurrentReadCount, "#2a");
575 Assert.AreEqual (2, v.RecursiveReadCount, "#3a");
578 int cReadCount = -1, rReadCount = -1;
580 Thread t = new Thread ((_) => {
581 rLock = v.IsReadLockHeld;
582 cReadCount = v.CurrentReadCount;
583 rReadCount = v.RecursiveReadCount;
589 Assert.AreEqual (false, rLock, "#1b");
590 Assert.AreEqual (1, cReadCount, "#2b");
591 Assert.AreEqual (0, rReadCount, "#3b");
595 public void RecursiveUpgradePropertiesTest ()
597 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
599 v.EnterUpgradeableReadLock ();
600 v.EnterUpgradeableReadLock ();
602 Assert.AreEqual (true, v.IsUpgradeableReadLockHeld, "#1a");
603 Assert.AreEqual (false, v.IsReadLockHeld, "#11a");
604 Assert.AreEqual (0, v.CurrentReadCount, "#2a");
605 Assert.AreEqual (2, v.RecursiveUpgradeCount, "#3a");
607 bool upLock = false, rLock = false;
608 int rCount = -1, rUCount = -1;
610 Thread t = new Thread ((_) => {
611 upLock = v.IsUpgradeableReadLockHeld;
612 rLock = v.IsReadLockHeld;
613 rCount = v.CurrentReadCount;
614 rUCount = v.RecursiveUpgradeCount;
620 Assert.AreEqual (false, upLock, "#1b");
621 Assert.AreEqual (false, rLock, "#11b");
622 Assert.AreEqual (0, rCount, "#2b");
623 Assert.AreEqual (0, rUCount, "#3b");
627 public void RecursiveWritePropertiesTest ()
629 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
634 Assert.AreEqual (true, v.IsWriteLockHeld, "#1a");
635 Assert.AreEqual (2, v.RecursiveWriteCount, "#3a");
640 Thread t = new Thread ((_) => {
641 wLock = v.IsWriteLockHeld;
642 rWrite = v.RecursiveWriteCount;
648 Assert.AreEqual (false, wLock, "#1b");
649 Assert.AreEqual (0, rWrite, "#3b");
653 public void RecursiveEnterExitReadTest ()
655 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
661 Assert.IsTrue (v.IsReadLockHeld);
662 Assert.AreEqual (3, v.RecursiveReadCount);
666 Assert.IsTrue (v.IsReadLockHeld);
667 Assert.AreEqual (2, v.RecursiveReadCount);
671 public void RecursiveEnterExitWriteTest ()
673 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
679 Assert.IsTrue (v.IsWriteLockHeld);
680 Assert.AreEqual (3, v.RecursiveWriteCount);
685 Assert.IsTrue (v.IsWriteLockHeld);
686 Assert.AreEqual (1, v.RecursiveWriteCount);
690 public void RecursiveEnterExitUpgradableTest ()
692 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
694 v.EnterUpgradeableReadLock ();
695 v.EnterUpgradeableReadLock ();
696 v.EnterUpgradeableReadLock ();
698 Assert.IsTrue (v.IsUpgradeableReadLockHeld);
699 Assert.AreEqual (3, v.RecursiveUpgradeCount);
701 v.ExitUpgradeableReadLock ();
703 Assert.IsTrue (v.IsUpgradeableReadLockHeld);
704 Assert.AreEqual (2, v.RecursiveUpgradeCount);
708 public void RecursiveWriteUpgradeReadTest ()
710 var rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
712 rwlock.EnterWriteLock ();
713 Assert.IsTrue (rwlock.IsWriteLockHeld);
714 rwlock.EnterUpgradeableReadLock ();
715 Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
716 rwlock.EnterReadLock ();
717 Assert.IsTrue (rwlock.IsReadLockHeld);
718 rwlock.ExitUpgradeableReadLock();
719 Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
720 Assert.IsTrue (rwlock.IsReadLockHeld);
721 Assert.IsTrue (rwlock.IsWriteLockHeld);
723 rwlock.ExitReadLock ();
724 Assert.IsTrue (rwlock.IsWriteLockHeld);
728 public void RecursiveWriteUpgradeTest ()
730 ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
732 rwlock.EnterWriteLock ();
733 Assert.IsTrue (rwlock.IsWriteLockHeld);
734 rwlock.EnterUpgradeableReadLock ();
735 Assert.IsTrue (rwlock.IsUpgradeableReadLockHeld);
736 rwlock.ExitUpgradeableReadLock ();
737 Assert.IsFalse (rwlock.IsUpgradeableReadLockHeld);
738 Assert.IsTrue (rwlock.IsWriteLockHeld);
739 rwlock.ExitWriteLock ();
740 Assert.IsFalse (rwlock.IsWriteLockHeld);
741 rwlock.EnterWriteLock ();
742 Assert.IsTrue (rwlock.IsWriteLockHeld);
746 public void RecursiveWriteReadAcquisitionInterleaving ()
748 var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
751 Assert.IsTrue (v.IsWriteLockHeld, "#1");
754 var t = new Thread (delegate () {
755 result = v.TryEnterReadLock (100);
759 Assert.IsFalse (result, "#2");
762 t = new Thread (delegate () {
763 result = v.TryEnterReadLock (100);
767 Assert.IsTrue (result, "#3");