/////////////////////////////////////////////////////////////////////////////// // // Queue.cs - Example of a thread safe queue class in C♯. // // ©2012, 2014, by Josh Moyer . All rights reserved. // /////////////////////////////////////////////////////////////////////////////// // Possbile work items for this release/milestone or vNext: // - Events (emtpied, filled, enqueued, dequeued, etc.) // - C++/CLI for more perf // - Generics // - Prioritization // - Support for IList, IEnumerable or other relevant interfaces using System; using System.Threading; namespace Moyer { public enum QueueStatus /// /// Enumeration of return values from instances derived from the Queue class. /// /// /// /// The last operation completed successfully. /// There was not enough memory to initialze the instance. /// The queue is empty. /// The queue is full. /// The queue was full during the last enqueue operation and overwrote the oldest item. /// The requested queue size is too small. /// Represents an unknown error or state. /// { Success = 0, Allocation, Empty, Full, Overrun, Size, Unknown } public class Queue /// /// /// A circular queue of integers of user-specified size using a /// simple array. Provides routines to initialize(), enqueue() and dequeue() /// the queue. Thread safe. /// /// /// Function members of this type will not raise exceptions due to performance reasons. Always check return values when calling function members of this type. /// /// /// /// Test Plan: /// /// /// /// /// With multiple threads of execution on the instance(s) under test: /// /// /// /// /// For initialize: /// /// Single and multiple instances. Verify that all initialize and pass the tests outlined below. /// Length < 1 items. Verify that QueueStatus.Size is returned. /// Length = UInt.Maximum items. Verify that QueueStatus.Size is returned. /// Low memory. Verify that QueueStatus.Allocation is returned. /// /// /// /// For enqueue and dequeue: /// /// Dequeue when empty. Verify that QueueStatus.Empty is returned. /// Enqueue when full. Verify that QueueStatus.Full is returned. /// Perform operation when full. Verify that QueueStatus.Full is returned. /// Perform operation when empty. Verify that QueueStatus.Empty is returned. /// Perform operation when head and tail loop across the boundaries of the array. Verify expected behaviors. /// /// /// /// /// /// { private int[] buffer; private uint head; private QueueStatus result; private bool nonCircular; private uint size; private QueueStatus state; private uint tail; private Queue(uint Size, bool NonCircular) { // initialize the data members buffer = new int[Size]; head = 0; nonCircular = NonCircular; size = Size; state = QueueStatus.Empty; tail = 0; } public static QueueStatus initialize(ref Queue queue, uint size, bool nonCircular) { // input check if (size < 1) return QueueStatus.Size; // attempt to create the queue and return try { queue = new Queue(size, nonCircular); } catch (OutOfMemoryException) { return QueueStatus.Allocation; } catch (Exception) { return QueueStatus.Unknown; } return QueueStatus.Success; } public QueueStatus enqueue(int value) { // set the default return value result = QueueStatus.Success; lock (this) { // check if queue is full if (state == QueueStatus.Full) { if (nonCircular) return QueueStatus.Full; else { head++; result = QueueStatus.Overrun; } } // set the value at tail buffer[tail] = value; // increment tail // restarting the index at the top if necessary // and checking for a full queue if (++tail == size) tail = 0; if (tail == head) state = QueueStatus.Full; else state = QueueStatus.Unknown; } // return return result; } public QueueStatus dequeue(ref int value) { // set the default return value result = QueueStatus.Success; lock (this) { // check if queue is empty if (state == QueueStatus.Empty) return QueueStatus.Empty; // set the value from head value = buffer[head]; // increment head // restarting the index at the top if necessary // and checking for an empty queue if (++head == size) head = 0; if (head == tail) state = QueueStatus.Empty; else state = QueueStatus.Unknown; } // return return result; } } }