194 lines
5.9 KiB
C#
194 lines
5.9 KiB
C#
/*
|
|
* Copyright (c) 2006-2016, openmetaverse.co
|
|
* 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.co 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;
|
|
|
|
namespace OpenMetaverse
|
|
{
|
|
/// <summary>
|
|
/// Same as Queue except Dequeue function blocks until there is an object to return.
|
|
/// Note: This class does not need to be synchronized
|
|
/// </summary>
|
|
public class BlockingQueue<T> : Queue<T>
|
|
{
|
|
private readonly object _syncRoot;
|
|
private bool _open;
|
|
|
|
/// <summary>
|
|
/// Create new BlockingQueue.
|
|
/// </summary>
|
|
/// <param name="col">The System.Collections.ICollection to copy elements from</param>
|
|
public BlockingQueue(IEnumerable<T> col)
|
|
: base(col)
|
|
{
|
|
_syncRoot = new object();
|
|
_open = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create new BlockingQueue.
|
|
/// </summary>
|
|
/// <param name="capacity">The initial number of elements that the queue can contain</param>
|
|
public BlockingQueue(int capacity)
|
|
: base(capacity)
|
|
{
|
|
_syncRoot = new object();
|
|
_open = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create new BlockingQueue.
|
|
/// </summary>
|
|
public BlockingQueue()
|
|
: base()
|
|
{
|
|
_syncRoot = new object();
|
|
_open = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// BlockingQueue Destructor (Close queue, resume any waiting thread).
|
|
/// </summary>
|
|
~BlockingQueue()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove all objects from the Queue.
|
|
/// </summary>
|
|
public new void Clear()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
base.Clear();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove all objects from the Queue, resume all dequeue threads.
|
|
/// </summary>
|
|
public void Close()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
_open = false;
|
|
base.Clear();
|
|
Monitor.PulseAll(_syncRoot); // resume any waiting threads
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and returns the object at the beginning of the Queue.
|
|
/// </summary>
|
|
/// <returns>Object in queue.</returns>
|
|
public new T Dequeue()
|
|
{
|
|
return Dequeue(Timeout.Infinite);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and returns the object at the beginning of the Queue.
|
|
/// </summary>
|
|
/// <param name="timeout">time to wait before returning</param>
|
|
/// <returns>Object in queue.</returns>
|
|
public T Dequeue(TimeSpan timeout)
|
|
{
|
|
return Dequeue(timeout.Milliseconds);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and returns the object at the beginning of the Queue.
|
|
/// </summary>
|
|
/// <param name="timeout">time to wait before returning (in milliseconds)</param>
|
|
/// <returns>Object in queue.</returns>
|
|
public T Dequeue(int timeout)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
while (_open && (Count == 0))
|
|
{
|
|
if (!Monitor.Wait(_syncRoot, timeout))
|
|
throw new InvalidOperationException("Timeout");
|
|
}
|
|
if (_open)
|
|
return base.Dequeue();
|
|
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;
|
|
}
|
|
obj = default(T);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds an object to the end of the Queue
|
|
/// </summary>
|
|
/// <param name="obj">Object to put in queue</param>
|
|
public new void Enqueue(T obj)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
base.Enqueue(obj);
|
|
Monitor.Pulse(_syncRoot);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open Queue.
|
|
/// </summary>
|
|
public void Open()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
_open = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets flag indicating if queue has been closed.
|
|
/// </summary>
|
|
public bool Closed => !_open;
|
|
}
|
|
}
|