Semaphore.Xna.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. #if NO_SEMAPHORE && (XNA || NETCF)
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Threading;
  8. namespace System.Reactive.Threading
  9. {
  10. //Monitor based implementation of Semaphore
  11. //that mimicks the .NET Semaphore class (System.Threading.Semaphore)
  12. internal sealed class Semaphore : IDisposable
  13. {
  14. private int m_currentCount;
  15. private readonly int m_maximumCount;
  16. private readonly object m_lockObject;
  17. private bool m_disposed;
  18. private readonly List<ManualResetEvent> m_waiting;
  19. public Semaphore(int initialCount, int maximumCount)
  20. {
  21. if (initialCount < 0)
  22. {
  23. throw new ArgumentOutOfRangeException("initialCount", "Non-negative number required.");
  24. }
  25. if (maximumCount < 1)
  26. {
  27. throw new ArgumentOutOfRangeException("maximumCount", "Positive number required.");
  28. }
  29. if (initialCount > maximumCount)
  30. {
  31. throw new ArgumentException("Initial count must be smaller than maximum");
  32. }
  33. m_waiting = new List<ManualResetEvent>();
  34. m_currentCount = initialCount;
  35. m_maximumCount = maximumCount;
  36. m_lockObject = new object();
  37. }
  38. public int Release()
  39. {
  40. return this.Release(1);
  41. }
  42. public int Release(int releaseCount)
  43. {
  44. if (releaseCount < 1)
  45. {
  46. throw new ArgumentOutOfRangeException("releaseCount", "Positive number required.");
  47. }
  48. if (m_disposed)
  49. {
  50. throw new ObjectDisposedException("Semaphore");
  51. }
  52. var oldCount = default(int);
  53. var toBeReleased = new List<ManualResetEvent>();
  54. lock (m_lockObject)
  55. {
  56. oldCount = m_currentCount;
  57. if (releaseCount + m_currentCount > m_maximumCount)
  58. {
  59. throw new ArgumentOutOfRangeException("releaseCount", "Amount of releases would overflow maximum");
  60. }
  61. var waiting = m_waiting.ToArray();
  62. var left = Math.Max(0, releaseCount - waiting.Length);
  63. for (var i = 0; i < releaseCount && i < m_waiting.Count; i++)
  64. {
  65. toBeReleased.Add(waiting[i]);
  66. m_waiting.RemoveAt(0);
  67. }
  68. m_currentCount += left;
  69. }
  70. foreach(var release in toBeReleased)
  71. {
  72. release.Set();
  73. }
  74. return oldCount;
  75. }
  76. public bool WaitOne()
  77. {
  78. return WaitOne(Timeout.Infinite);
  79. }
  80. public bool WaitOne(int millisecondsTimeout)
  81. {
  82. if (m_disposed)
  83. {
  84. throw new ObjectDisposedException("Semaphore");
  85. }
  86. var manualResetEvent = default(ManualResetEvent);
  87. lock (m_lockObject)
  88. {
  89. if (m_currentCount == 0)
  90. {
  91. manualResetEvent = new ManualResetEvent(false);
  92. m_waiting.Add(manualResetEvent);
  93. }
  94. else
  95. {
  96. m_currentCount--;
  97. return true;
  98. }
  99. }
  100. #if XNA_31_ZUNE || NETCF35
  101. if (!manualResetEvent.WaitOne(millisecondsTimeout, false))
  102. #else
  103. if (!manualResetEvent.WaitOne(millisecondsTimeout))
  104. #endif
  105. {
  106. lock(m_lockObject)
  107. {
  108. m_waiting.Remove(manualResetEvent);
  109. }
  110. return false;
  111. }
  112. return true;
  113. }
  114. public bool WaitOne(TimeSpan timeout)
  115. {
  116. return WaitOne((int)timeout.TotalMilliseconds);
  117. }
  118. public void Close()
  119. {
  120. Dispose();
  121. }
  122. public void Dispose()
  123. {
  124. //the .NET CLR semaphore does not release waits upon dispose
  125. //so we don't do that either.
  126. m_disposed = true;
  127. }
  128. }
  129. }
  130. #endif