/// <summary> /// Constructs a new PriorityQueue instance. /// </summary> public PriorityQueue() { peekWaitHeader = new WaitingThreadNode(); peekWaitHeader.next = peekWaitHeader; peekWaitHeader.previous = peekWaitHeader; removeWaitHeader = new WaitingThreadNode(); removeWaitHeader.next = removeWaitHeader; removeWaitHeader.previous = removeWaitHeader; waitNodeCacheHeader = new WaitingThreadNode(); Sublist sublist; for (int x = 0; x <= 20; x++) { sublist = new Sublist(); sublist.priority = x; sublistArray[x] = sublist; sublistMap.Add(x, sublist); } sublistCount = 21; highestPrioritySublist = null; defaultPrioritySublist = sublistArray[0]; }
/// <summary> /// Constructs a new DoubleEndedQueue instance /// </summary> public DoubleEndedQueue() { peekWaitHeader = new WaitingThreadNode(); peekWaitHeader.next = peekWaitHeader; peekWaitHeader.previous = peekWaitHeader; removeWaitHeader = new WaitingThreadNode(); removeWaitHeader.next = removeWaitHeader; removeWaitHeader.previous = removeWaitHeader; waitNodeCacheHeader = new WaitingThreadNode(); }
/// <summary> /// Renders this Queue incapable of accepting further input, and immediately /// returns null to any waiting threads /// </summary> public override void Close() { lock (monitor) { if (!isOpen) { return; } WaitingThreadNode node; if (peekWaitCount > 0) { lock (peekWaitHeader) { if (peekWaitCount > 0) { node = peekWaitHeader.next; while (node != peekWaitHeader) { node.valueReturned = true; node.returnValue = null; node.previous = null; node = node.next; node.previous.next = null; } peekWaitCount = 0; peekWaitHeader.next = null; Monitor.PulseAll(peekWaitHeader); } } } if (removeWaitCount > 0) { lock (removeWaitHeader) { if (removeWaitCount > 0) { node = removeWaitHeader.next; WaitingThreadNode[] nodes = new WaitingThreadNode[removeWaitCount]; for (int x = 0; x < removeWaitCount; x++) { nodes[x] = node; node.valueReturned = true; node.returnValue = null; node.previous = null; node = node.next; node.previous.next = null; } for (int x = 0; x < removeWaitCount; x++) { lock (nodes[x]) { Monitor.Pulse(nodes[x]); } } removeWaitHeader.next = removeWaitHeader; removeWaitHeader.previous = removeWaitHeader; removeWaitCount = 0; } } } } }
/// <summary> /// Removes the next (highest-priority) object from the queue, or null if /// the queue is initially empty and the specified timeout is reached without /// input /// </summary> /// <param name="_millisecondsTimeout"></param> /// <returns>The next object from the highest priority currently contained by the queue</returns> public override object Remove(int _millisecondsTimeout) { object returnValue = null; lock (monitor) { if (count > 0) { if (highestPrioritySublist != null) { returnValue = highestPrioritySublist.RemoveFirst(); if (highestPrioritySublist.count == 0) { highestPrioritySublist = null; } count--; return(returnValue); } else { Sublist sublist; for (int x = (sublistCount - 1); x >= 0; x--) { sublist = sublistArray[x]; if (sublist.count > 0) { returnValue = sublist.RemoveFirst(); if (sublist.count > 0) { highestPrioritySublist = sublist; } count--; return(returnValue); } } } } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return(null); } } WaitingThreadNode node; lock (removeWaitHeader) { peekWaitCount++; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } removeWaitHeader.previous.next = node; node.previous = removeWaitHeader.previous; removeWaitHeader.previous = node; node.next = removeWaitHeader; } lock (node) { if (!node.valueReturned) { try { Monitor.Wait(node, _millisecondsTimeout); } catch { } } } lock (removeWaitHeader) { if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return(returnValue); }
/// <summary> /// Gets the next (highest-priority) object without removing it from the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait for input if the queue is initially empty</param> /// <returns>The highest-priority object on the queue, or null if the queue is initially empty and the timeout expires</returns> public override object Peek(int _millisecondsTimeout) { lock (monitor) { if (count > 0) { if (highestPrioritySublist != null) { return(highestPrioritySublist.elements[highestPrioritySublist.startIndex]); } else { for (int x = (sublistCount - 1); x > 0; x--) { if (sublistArray[x].count > 0) { highestPrioritySublist = sublistArray[x]; return(highestPrioritySublist.elements[highestPrioritySublist.startIndex]); } } } } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return(null); } } object returnValue = null; lock (peekWaitHeader) { peekWaitCount++; WaitingThreadNode node; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } peekWaitHeader.previous.next = node; node.previous = peekWaitHeader.previous; peekWaitHeader.previous = node; node.next = peekWaitHeader; try { Monitor.Wait(peekWaitHeader, _millisecondsTimeout); } catch { } if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return(returnValue); }
/// <summary> /// Adds the specified object to the queue with the default priority /// (see the DefaultPriority property) /// </summary> /// <param name="_object">The object to add to the queue</param> public override void Add(object _object) { lock (monitor) { if (!isOpen) { throw new InvalidOperationException("This instance is closed, and cannot accept input"); } else if ((!isNullAllowed) && (_object == null)) { throw new ArgumentNullException("This instance does not allow null input"); } if (peekWaitCount > 0) { lock (peekWaitHeader) { if (peekWaitCount > 0) { WaitingThreadNode node; node = peekWaitHeader.next; while (node != peekWaitHeader) { node.valueReturned = true; node.returnValue = _object; node.previous = null; node = node.next; node.previous.next = null; } peekWaitCount = 0; peekWaitHeader.next = null; Monitor.PulseAll(peekWaitHeader); } } } if (removeWaitCount > 0) { lock (removeWaitHeader) { if (removeWaitCount > 0) { WaitingThreadNode node = removeWaitHeader.next; removeWaitHeader.next = node.next; removeWaitHeader.next.previous = removeWaitHeader; node.next = null; node.previous = null; removeWaitCount--; lock (node) { node.valueReturned = true; node.returnValue = _object; Monitor.Pulse(node); } } } } else { defaultPrioritySublist.AddLast(_object); if ((highestPrioritySublist == null) || (highestPrioritySublist.priority < defaultPriority)) { highestPrioritySublist = defaultPrioritySublist; } count++; } } }
/// <summary> /// Removes and returns the object at the back of the queue. If the queue /// is currently empty, waits the specified number of milliseconds for the next /// input to the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait</param> /// <returns>The object at the back of the queue, or null if the queue was initially empty and the timeout expired</returns> public object RemoveLast(int _millisecondsTimeout) { object returnValue = null; lock (syncObj) { if (count > 0) { returnValue = elements[endIndex--]; if (endIndex < 0) { endIndex = capacity - 1; } count--; return returnValue; } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return null; } } WaitingThreadNode node; lock (removeWaitHeader) { peekWaitCount++; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } removeWaitHeader.previous.next = node; node.previous = removeWaitHeader.previous; removeWaitHeader.previous = node; node.next = removeWaitHeader; } lock (node) { if (!node.valueReturned) { try { Monitor.Wait(node, _millisecondsTimeout); } catch { } } } lock (removeWaitHeader) { if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return returnValue; }
/// <summary> /// Gets the object at the back of the queue without removing it. If the queue /// is currently empty, waits the specified number of milliseconds for the next /// input to the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait</param> /// <returns>The object at the back of the queue, or null if the queue was initially empty and the timeout expired</returns> public object PeekLast(int _millisecondsTimeout) { lock (syncObj) { if (count > 0) { return elements[endIndex]; } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return null; } } object returnValue = null; lock (peekWaitHeader) { peekWaitCount++; WaitingThreadNode node; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } peekWaitHeader.previous.next = node; node.previous = peekWaitHeader.previous; peekWaitHeader.previous = node; node.next = peekWaitHeader; try { Monitor.Wait(peekWaitHeader, _millisecondsTimeout); } catch { } if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return returnValue; }
/// <summary> /// Renders the queue incapable of accepting further input, and immediately /// returns null to waiting threads /// </summary> public override void Close() { lock (syncObj) { if (!isOpen) { return; } WaitingThreadNode node; if (peekWaitCount > 0) { lock (peekWaitHeader) { if (peekWaitCount > 0) { node = peekWaitHeader.next; while (node != peekWaitHeader) { node.valueReturned = true; node.returnValue = null; node.previous = null; node = node.next; node.previous.next = null; } peekWaitCount = 0; peekWaitHeader.next = null; Monitor.PulseAll(peekWaitHeader); } } } if (removeWaitCount > 0) { lock (removeWaitHeader) { if (removeWaitCount > 0) { node = removeWaitHeader.next; WaitingThreadNode[] nodes = new WaitingThreadNode[removeWaitCount]; for (int x = 0; x < removeWaitCount; x++) { nodes[x] = node; node.valueReturned = true; node.returnValue = null; node.previous = null; node = node.next; node.previous.next = null; } for (int x = 0; x < removeWaitCount; x++) { lock (nodes[x]) { Monitor.Pulse(nodes[x]); } } removeWaitHeader.next = removeWaitHeader; removeWaitHeader.previous = removeWaitHeader; removeWaitCount = 0; } } } } }
/// <summary> /// Adds the specified object to the back of the queue /// </summary> /// <param name="_object">The object to add</param> public override void Add(object _object) { lock (monitor) { if (!isOpen) { throw new InvalidOperationException("This instance is closed, and cannot accept input"); } else if ((!isNullAllowed) && (_object == null)) { throw new ArgumentNullException("This instance does not allow null input"); } if (peekWaitCount > 0) { lock (peekWaitHeader) { if (peekWaitCount > 0) { WaitingThreadNode node; node = peekWaitHeader.next; while (node != peekWaitHeader) { node.valueReturned = true; node.returnValue = _object; node.previous = null; node = node.next; node.previous.next = null; } peekWaitCount = 0; peekWaitHeader.next = null; Monitor.PulseAll(peekWaitHeader); } } } if (removeWaitCount > 0) { lock (removeWaitHeader) { if (removeWaitCount > 0) { WaitingThreadNode node = removeWaitHeader.next; removeWaitHeader.next = node.next; removeWaitHeader.next.previous = removeWaitHeader; node.next = null; node.previous = null; removeWaitCount--; lock (node) { node.valueReturned = true; node.returnValue = _object; Monitor.Pulse(node); } } } } else { if (count == capacity) { IncreaseArraySize(); } if (count > 0) { endIndex++; if (endIndex == capacity) { endIndex = 0; } } elements[endIndex] = _object; count++; } } }
/// <summary> /// Removes and returns the object at the back of the queue. If the queue /// is currently empty, waits the specified number of milliseconds for the next /// input to the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait</param> /// <returns>The object at the back of the queue, or null if the queue was initially empty and the timeout expired</returns> public object RemoveLast(int _millisecondsTimeout) { object returnValue = null; lock (monitor) { if (count > 0) { returnValue = elements[endIndex--]; if (endIndex < 0) { endIndex = capacity - 1; } count--; return(returnValue); } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return(null); } } WaitingThreadNode node; lock (removeWaitHeader) { peekWaitCount++; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } removeWaitHeader.previous.next = node; node.previous = removeWaitHeader.previous; removeWaitHeader.previous = node; node.next = removeWaitHeader; } lock (node) { if (!node.valueReturned) { try { Monitor.Wait(node, _millisecondsTimeout); } catch { } } } lock (removeWaitHeader) { if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return(returnValue); }
/// <summary> /// Gets the object at the back of the queue without removing it. If the queue /// is currently empty, waits the specified number of milliseconds for the next /// input to the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait</param> /// <returns>The object at the back of the queue, or null if the queue was initially empty and the timeout expired</returns> public object PeekLast(int _millisecondsTimeout) { lock (monitor) { if (count > 0) { return(elements[endIndex]); } if ((_millisecondsTimeout <= 0) || (!isOpen)) { return(null); } } object returnValue = null; lock (peekWaitHeader) { peekWaitCount++; WaitingThreadNode node; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } peekWaitHeader.previous.next = node; node.previous = peekWaitHeader.previous; peekWaitHeader.previous = node; node.next = peekWaitHeader; try { Monitor.Wait(peekWaitHeader, _millisecondsTimeout); } catch { } if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return(returnValue); }
/// <summary> /// Removes the next (highest-priority) object from the queue, or null if /// the queue is initially empty and the specified timeout is reached without /// input /// </summary> /// <param name="_millisecondsTimeout"></param> /// <returns>The next object from the highest priority currently contained by the queue</returns> public override object Remove(int millisecondsTimeout) { object returnValue = null; lock (syncObj) { if (count > 0) { if (highestPrioritySublist != null) { returnValue = highestPrioritySublist.RemoveFirst(); if (highestPrioritySublist.count == 0) { highestPrioritySublist = null; } count--; return returnValue; } else { Sublist sublist; for (int x = (sublistCount - 1); x >= 0; x--) { sublist = sublistArray[x]; if (sublist.count > 0) { returnValue = sublist.RemoveFirst(); if (sublist.count > 0) { highestPrioritySublist = sublist; } count--; return returnValue; } } } } if ((millisecondsTimeout <= 0) || (!isOpen)) { return null; } } WaitingThreadNode node; lock (removeWaitHeader) { peekWaitCount++; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } removeWaitHeader.previous.next = node; node.previous = removeWaitHeader.previous; removeWaitHeader.previous = node; node.next = removeWaitHeader; } lock (node) { if (!node.valueReturned) { try { Monitor.Wait(node, millisecondsTimeout); } catch { } } } lock (removeWaitHeader) { if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return returnValue; }
/// <summary> /// Gets the next (highest-priority) object without removing it from the queue /// </summary> /// <param name="_millisecondsTimeout">The number of milliseconds to wait for input if the queue is initially empty</param> /// <returns>The highest-priority object on the queue, or null if the queue is initially empty and the timeout expires</returns> public override object Peek(int millisecondsTimeout) { lock (syncObj) { if (count > 0) { if (highestPrioritySublist != null) { return highestPrioritySublist.elements[highestPrioritySublist.startIndex]; } else { for (int x = (sublistCount - 1); x > 0; x--) { if (sublistArray[x].count > 0) { highestPrioritySublist = sublistArray[x]; return highestPrioritySublist.elements[highestPrioritySublist.startIndex]; } } } } if ((millisecondsTimeout <= 0) || (!isOpen)) { return null; } } object returnValue = null; lock (peekWaitHeader) { peekWaitCount++; WaitingThreadNode node; if (waitNodeCacheCount > 0) { node = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node.next; waitNodeCacheCount--; } else { node = new WaitingThreadNode(); } peekWaitHeader.previous.next = node; node.previous = peekWaitHeader.previous; peekWaitHeader.previous = node; node.next = peekWaitHeader; try { Monitor.Wait(peekWaitHeader, millisecondsTimeout); } catch { } if (node.valueReturned) { returnValue = node.returnValue; node.returnValue = null; node.valueReturned = false; } else { node.previous.next = node.next; node.next.previous = node.previous; node.previous = null; peekWaitCount--; } node.next = waitNodeCacheHeader.next; waitNodeCacheHeader.next = node; waitNodeCacheCount++; } return returnValue; }