ReaderWriterLock.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. //
  2. // System.Threading.ReaderWriterLock.cs
  3. //
  4. // Author:
  5. // Dick Porter ([email protected])
  6. // Jackson Harper ([email protected])
  7. //
  8. // (C) Ximian, Inc. http://www.ximian.com
  9. // (C) 2004 Novell, Inc (http://www.novell.com)
  10. //
  11. namespace System.Threading
  12. {
  13. public sealed class ReaderWriterLock
  14. {
  15. private int seq_num = 1;
  16. private int state = 0;
  17. private int readers = 0;
  18. private bool writer_queued = false;
  19. private int upgrade_id = -1;
  20. private LockQueue writer_queue;
  21. public ReaderWriterLock()
  22. {
  23. }
  24. public bool IsReaderLockHeld {
  25. get {
  26. lock (this) return (state > 0);
  27. }
  28. }
  29. public bool IsWriterLockHeld {
  30. get {
  31. lock (this) return (state < 0);
  32. }
  33. }
  34. public int WriterSeqNum {
  35. get {
  36. lock (this) return seq_num;
  37. }
  38. }
  39. public void AcquireReaderLock(int millisecondsTimeout) {
  40. lock (this) {
  41. // Wait if there is a write lock
  42. readers++;
  43. if (state < 0 || writer_queued)
  44. Monitor.Wait (this, millisecondsTimeout);
  45. readers--;
  46. state++;
  47. }
  48. }
  49. public void AcquireReaderLock(TimeSpan timeout)
  50. {
  51. int ms = CheckTimeout (timeout);
  52. AcquireReaderLock ((int) timeout.TotalMilliseconds);
  53. }
  54. public void AcquireWriterLock(int millisecondsTimeout)
  55. {
  56. lock (this) {
  57. if (writer_queue == null)
  58. writer_queue = new LockQueue (this);
  59. writer_queued = true;
  60. if (state != 0) // wait while there are reader locks or another writer lock
  61. writer_queue.Wait (millisecondsTimeout);
  62. writer_queued = false;
  63. state = -1;
  64. }
  65. Interlocked.Increment (ref seq_num);
  66. }
  67. public void AcquireWriterLock(TimeSpan timeout) {
  68. int ms = CheckTimeout (timeout);
  69. AcquireWriterLock (ms);
  70. }
  71. public bool AnyWritersSince(int seqNum) {
  72. lock (this) {
  73. return (this.seq_num > seqNum);
  74. }
  75. }
  76. public void DowngradeFromWriterLock(ref LockCookie lockCookie)
  77. {
  78. lock (this) {
  79. state = 1;
  80. Monitor.Pulse (this);
  81. if (writer_queue != null)
  82. writer_queue.Pulse ();
  83. }
  84. }
  85. public LockCookie ReleaseLock()
  86. {
  87. LockCookie cookie;
  88. lock (this) {
  89. cookie = new LockCookie (Thread.CurrentThreadId, state < 0, state > 0);
  90. ReleaseWriterLock ();
  91. }
  92. return cookie;
  93. }
  94. public void ReleaseReaderLock()
  95. {
  96. lock (this) {
  97. int min_state = (upgrade_id == -1 ? 0 : 1);
  98. if (upgrade_id != -1 && upgrade_id == Thread.CurrentThreadId) {
  99. Monitor.Pulse (this);
  100. writer_queue.Pulse ();
  101. return;
  102. }
  103. if (--state == min_state && writer_queue != null)
  104. writer_queue.Pulse ();
  105. }
  106. }
  107. public void ReleaseWriterLock()
  108. {
  109. lock (this) {
  110. state = 0;
  111. if (readers > 0)
  112. Monitor.Pulse (this);
  113. else if (writer_queue != null)
  114. writer_queue.Pulse ();
  115. }
  116. }
  117. public void RestoreLock(ref LockCookie lockCookie)
  118. {
  119. lock (this) {
  120. if (lockCookie.IsWriter)
  121. AcquireWriterLock (-1);
  122. else if (lockCookie.IsReader)
  123. AcquireReaderLock (-1);
  124. }
  125. }
  126. public LockCookie UpgradeToWriterLock(int millisecondsTimeout)
  127. {
  128. LockCookie cookie;
  129. lock (this) {
  130. upgrade_id = Thread.CurrentThreadId;
  131. cookie = new LockCookie (upgrade_id, state < 0, state > 0);
  132. if (writer_queue == null)
  133. writer_queue = new LockQueue (this);
  134. writer_queued = true;
  135. if (state != 1) // wait until there is only 1 reader lock
  136. writer_queue.Wait (millisecondsTimeout);
  137. writer_queued = false;
  138. state = -1;
  139. upgrade_id = -1;
  140. }
  141. Interlocked.Increment (ref seq_num);
  142. return cookie;
  143. }
  144. public LockCookie UpgradeToWriterLock(TimeSpan timeout)
  145. {
  146. int ms = CheckTimeout (timeout);
  147. return UpgradeToWriterLock (ms);
  148. }
  149. private int CheckTimeout (TimeSpan timeout)
  150. {
  151. int ms = (int) timeout.TotalMilliseconds;
  152. if (ms < -1)
  153. throw new ArgumentOutOfRangeException ("timeout",
  154. "Number must be either non-negative or -1");
  155. return ms;
  156. }
  157. }
  158. }