SemaphoreLight.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System;
  2. using System.Threading;
  3. namespace Renci.SshNet.Common
  4. {
  5. /// <summary>
  6. /// Light implementation of SemaphoreSlim.
  7. /// </summary>
  8. public class SemaphoreLight
  9. {
  10. private readonly object _lock = new object();
  11. private int _currentCount;
  12. /// <summary>
  13. /// Initializes a new instance of the <see cref="SemaphoreLight"/> class, specifying
  14. /// the initial number of requests that can be granted concurrently.
  15. /// </summary>
  16. /// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently.</param>
  17. /// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCount"/> is a negative number.</exception>
  18. public SemaphoreLight(int initialCount)
  19. {
  20. if (initialCount < 0 )
  21. throw new ArgumentOutOfRangeException("initialCount", "The value cannot be negative.");
  22. _currentCount = initialCount;
  23. }
  24. /// <summary>
  25. /// Gets the current count of the <see cref="SemaphoreLight"/>.
  26. /// </summary>
  27. public int CurrentCount { get { return _currentCount; } }
  28. /// <summary>
  29. /// Exits the <see cref="SemaphoreLight"/> once.
  30. /// </summary>
  31. /// <returns>The previous count of the <see cref="SemaphoreLight"/>.</returns>
  32. public int Release()
  33. {
  34. return Release(1);
  35. }
  36. /// <summary>
  37. /// Exits the <see cref="SemaphoreLight"/> a specified number of times.
  38. /// </summary>
  39. /// <param name="releaseCount">The number of times to exit the semaphore.</param>
  40. /// <returns>The previous count of the <see cref="SemaphoreLight"/>.</returns>
  41. public int Release(int releaseCount)
  42. {
  43. var oldCount = _currentCount;
  44. lock (_lock)
  45. {
  46. _currentCount += releaseCount;
  47. Monitor.Pulse(_lock);
  48. }
  49. return oldCount;
  50. }
  51. /// <summary>
  52. /// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>.
  53. /// </summary>
  54. public void Wait()
  55. {
  56. lock (_lock)
  57. {
  58. while (_currentCount < 1)
  59. {
  60. Monitor.Wait(_lock);
  61. }
  62. _currentCount--;
  63. Monitor.Pulse(_lock);
  64. }
  65. }
  66. /// <summary>
  67. /// Blocks the current thread until it can either enter the <see cref="SemaphoreLight"/>,
  68. /// or until the specified timeout has expired.
  69. /// </summary>
  70. /// <param name="timeout"></param>
  71. /// <returns></returns>
  72. public bool Wait(TimeSpan timeout)
  73. {
  74. var timeoutInMilliseconds = timeout.TotalMilliseconds;
  75. if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue)
  76. throw new ArgumentOutOfRangeException("timeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
  77. lock (_lock)
  78. {
  79. if (timeoutInMilliseconds == -1)
  80. {
  81. while (_currentCount < 1)
  82. Monitor.Wait(_lock);
  83. }
  84. else
  85. {
  86. if (_currentCount < 1)
  87. {
  88. var remainingTimeInMilliseconds = (int) timeoutInMilliseconds;
  89. var startTicks = Environment.TickCount;
  90. while (_currentCount < 1)
  91. {
  92. if (!Monitor.Wait(_lock, remainingTimeInMilliseconds))
  93. {
  94. return false;
  95. }
  96. var elapsed = Environment.TickCount - startTicks;
  97. remainingTimeInMilliseconds -= elapsed;
  98. if (remainingTimeInMilliseconds < 0)
  99. return false;
  100. }
  101. }
  102. }
  103. _currentCount--;
  104. Monitor.Pulse(_lock);
  105. return true;
  106. }
  107. }
  108. }
  109. }