Semaphore.Xna.cs 4.3 KB

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