Semaphore.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. #if SILVERLIGHT
  3. using System;
  4. namespace System.Threading
  5. {
  6. //Monitor based implementation of Semaphore
  7. //that mimicks the .NET Semaphore class (System.Threading.Semaphore)
  8. internal sealed class Semaphore : IDisposable
  9. {
  10. private int m_currentCount;
  11. private int m_maximumCount;
  12. private object m_lockObject;
  13. private bool m_disposed;
  14. public Semaphore(int initialCount, int maximumCount)
  15. {
  16. if (initialCount < 0)
  17. {
  18. throw new ArgumentOutOfRangeException("initialCount", "Non-negative number required.");
  19. }
  20. if (maximumCount < 1)
  21. {
  22. throw new ArgumentOutOfRangeException("maximumCount", "Positive number required.");
  23. }
  24. if (initialCount > maximumCount)
  25. {
  26. throw new ArgumentException("Initial count must be smaller than maximum");
  27. }
  28. m_currentCount = initialCount;
  29. m_maximumCount = maximumCount;
  30. m_lockObject = new object();
  31. }
  32. public int Release()
  33. {
  34. return this.Release(1);
  35. }
  36. public int Release(int releaseCount)
  37. {
  38. if (releaseCount < 1)
  39. {
  40. throw new ArgumentOutOfRangeException("releaseCount", "Positive number required.");
  41. }
  42. if (m_disposed)
  43. {
  44. throw new ObjectDisposedException("Semaphore");
  45. }
  46. var oldCount = default(int);
  47. lock (m_lockObject)
  48. {
  49. oldCount = m_currentCount;
  50. if (releaseCount + m_currentCount > m_maximumCount)
  51. {
  52. throw new ArgumentOutOfRangeException("releaseCount", "Amount of releases would overflow maximum");
  53. }
  54. m_currentCount += releaseCount;
  55. //PulseAll makes sure all waiting threads get queued for acquiring the lock
  56. //Pulse would only queue one thread.
  57. Monitor.PulseAll(m_lockObject);
  58. }
  59. return oldCount;
  60. }
  61. public bool WaitOne()
  62. {
  63. return WaitOne(Timeout.Infinite);
  64. }
  65. public bool WaitOne(int millisecondsTimeout)
  66. {
  67. if (m_disposed)
  68. {
  69. throw new ObjectDisposedException("Semaphore");
  70. }
  71. lock (m_lockObject)
  72. {
  73. while (m_currentCount == 0)
  74. {
  75. if (!Monitor.Wait(m_lockObject, millisecondsTimeout))
  76. {
  77. return false;
  78. }
  79. }
  80. m_currentCount--;
  81. return true;
  82. }
  83. }
  84. public bool WaitOne(TimeSpan timeout)
  85. {
  86. return WaitOne((int)timeout.TotalMilliseconds);
  87. }
  88. public void Close()
  89. {
  90. Dispose();
  91. }
  92. public void Dispose()
  93. {
  94. //the .NET CLR semaphore does not release waits upon dispose
  95. //so we don't do that either.
  96. m_disposed = true;
  97. m_lockObject = null;
  98. }
  99. }
  100. }
  101. #endif