/* * Copyright (c) 2006-2014, openmetaverse.org * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the openmetaverse.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Threading; using OpenMetaverse; namespace OpenMetaverse { /// /// Same as Queue except Dequeue function blocks until there is an object to return. /// Note: This class does not need to be synchronized /// public class BlockingQueue : Queue { private object SyncRoot; private bool open; /// /// Create new BlockingQueue. /// /// The System.Collections.ICollection to copy elements from public BlockingQueue(IEnumerable col) : base(col) { SyncRoot = new object(); open = true; } /// /// Create new BlockingQueue. /// /// The initial number of elements that the queue can contain public BlockingQueue(int capacity) : base(capacity) { SyncRoot = new object(); open = true; } /// /// Create new BlockingQueue. /// public BlockingQueue() : base() { SyncRoot = new object(); open = true; } /// /// BlockingQueue Destructor (Close queue, resume any waiting thread). /// ~BlockingQueue() { Close(); } /// /// Remove all objects from the Queue. /// public new void Clear() { lock (SyncRoot) { base.Clear(); } } /// /// Remove all objects from the Queue, resume all dequeue threads. /// public void Close() { lock (SyncRoot) { open = false; base.Clear(); Monitor.PulseAll(SyncRoot); // resume any waiting threads } } /// /// Removes and returns the object at the beginning of the Queue. /// /// Object in queue. public new T Dequeue() { return Dequeue(Timeout.Infinite); } /// /// Removes and returns the object at the beginning of the Queue. /// /// time to wait before returning /// Object in queue. public T Dequeue(TimeSpan timeout) { return Dequeue(timeout.Milliseconds); } /// /// Removes and returns the object at the beginning of the Queue. /// /// time to wait before returning (in milliseconds) /// Object in queue. public T Dequeue(int timeout) { lock (SyncRoot) { while (open && (base.Count == 0)) { if (!Monitor.Wait(SyncRoot, timeout)) throw new InvalidOperationException("Timeout"); } if (open) return base.Dequeue(); else throw new InvalidOperationException("Queue Closed"); } } public bool Dequeue(int timeout, ref T obj) { lock (SyncRoot) { while (open && (base.Count == 0)) { if (!Monitor.Wait(SyncRoot, timeout)) return false; } if (open) { obj = base.Dequeue(); return true; } else { obj = default(T); return false; } } } /// /// Adds an object to the end of the Queue /// /// Object to put in queue public new void Enqueue(T obj) { lock (SyncRoot) { base.Enqueue(obj); Monitor.Pulse(SyncRoot); } } /// /// Open Queue. /// public void Open() { lock (SyncRoot) { open = true; } } /// /// Gets flag indicating if queue has been closed. /// public bool Closed { get { return !open; } } } }