Semaphore.cs 3.4 KB

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