PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/Interlace/Logging/SynchronisedQueue.cs

https://bitbucket.org/VahidN/interlace
C# | 152 lines | 87 code | 28 blank | 37 comment | 16 complexity | adf027140b82fb133676756483a11372 MD5 | raw file
  1. #region Using Directives and Copyright Notice
  2. // Copyright (c) 2007-2010, Computer Consultancy Pty Ltd
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of the Computer Consultancy Pty Ltd nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. // ARE DISCLAIMED. IN NO EVENT SHALL COMPUTER CONSULTANCY PTY LTD BE LIABLE
  20. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  26. // DAMAGE.
  27. using System.Collections;
  28. using System.Threading;
  29. #endregion
  30. namespace Interlace.Logging
  31. {
  32. /// <summary>
  33. /// A thread safe queue (for multiple producers and comsumers) that blocks consumers
  34. /// on an empty queue and blocks producers on a full queue.
  35. /// </summary>
  36. /// <remarks>
  37. /// This class is an implementation of the "Producer-Consumer with Binary Semaphores" from:
  38. ///
  39. /// M. Ben-Ari. Principles of Concurrent and Distributed Programming. 1990.
  40. ///
  41. /// Windows NT auto-reset events are used rather than binary semaphores (they are equivalent)
  42. /// because .NET did not in early versions include semaphores or binary semaphores.
  43. /// </remarks>
  44. public class SynchronisedQueue
  45. {
  46. object[] _circularBuffer;
  47. AutoResetEvent _notEmpty = new AutoResetEvent(false);
  48. AutoResetEvent _notFull = new AutoResetEvent(false);
  49. int _inPointer = 0;
  50. int _outPointer = 0;
  51. int _count = 0;
  52. object _countLock = new object();
  53. int _enqueueCount = 0;
  54. int _dequeueCount = 0;
  55. ManualResetEvent _shutdownQueueEvent = new ManualResetEvent(false);
  56. object _enqueueLock = new object();
  57. object _dequeueLock = new object();
  58. public SynchronisedQueue(int capacity)
  59. {
  60. _circularBuffer = new object[capacity];
  61. }
  62. public int Capacity
  63. {
  64. get { return _circularBuffer.Length; }
  65. }
  66. public void Shutdown()
  67. {
  68. _shutdownQueueEvent.Set();
  69. }
  70. public void Enqueue(object value, int timeout)
  71. {
  72. lock (_enqueueLock)
  73. {
  74. if (_enqueueCount == _circularBuffer.Length)
  75. {
  76. int waitResult = WaitHandle.WaitAny(new WaitHandle[] { _notFull, _shutdownQueueEvent }, timeout, false);
  77. if (waitResult == WaitHandle.WaitTimeout)
  78. {
  79. throw new SynchronisedQueueTimeoutException();
  80. }
  81. if (waitResult == 1)
  82. {
  83. throw new SynchronisedQueueShutdownException();
  84. }
  85. }
  86. _circularBuffer[_inPointer] = value;
  87. lock (_countLock)
  88. {
  89. _count += 1;
  90. _enqueueCount = _count;
  91. }
  92. if (_enqueueCount == 1) _notEmpty.Set();
  93. _inPointer = (_inPointer + 1) % _circularBuffer.Length;
  94. }
  95. }
  96. public object Dequeue(int timeout)
  97. {
  98. lock (_dequeueLock)
  99. {
  100. if (_dequeueCount == 0)
  101. {
  102. int waitResult = WaitHandle.WaitAny(new WaitHandle[] { _notEmpty, _shutdownQueueEvent }, timeout, false);
  103. if (waitResult == WaitHandle.WaitTimeout)
  104. {
  105. throw new SynchronisedQueueTimeoutException();
  106. }
  107. if (waitResult == 1)
  108. {
  109. throw new SynchronisedQueueShutdownException();
  110. }
  111. }
  112. object value = _circularBuffer[_outPointer];
  113. lock (_countLock)
  114. {
  115. _count -= 1;
  116. _dequeueCount = _count;
  117. }
  118. if (_dequeueCount == _circularBuffer.Length - 1) _notFull.Set();
  119. _outPointer = (_outPointer + 1) % _circularBuffer.Length;
  120. return value;
  121. }
  122. }
  123. }
  124. }