/// Version 1.0.0 /// Last modified 23.5.2014 /// /// Copyright (C) 2014 Veli-Mikko Puupponen /// /// Halyri-system is a prototype emergency call system. Its purpose is to /// demonstrate the use of the advanced capabilities available in the current /// generation smartphones in facilitating the emergency service dispatcher's /// capability to determine the nature of the emergency and to dispatch help. /// /// For more information, see the README file of this package. /// /// The MIT License (MIT) /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to /// deal in the Software without restriction, including without limitation the /// rights to use, copy, modify, merge, publish, distribute, sublicense, /// and/or sell copies of the Software, and to permit persons to whom the /// Software is furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING /// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS /// IN THE SOFTWARE. /// using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SimpleUdpMediaClient.Collections { /// Veli-Mikko Puupponen /// /// The class is a thread-safe blocking queue that has a defined, finite length. /// /// The type of the elements in the queue. public class BlockingQueue { private Queue elementQueue; private int capacity = 30; private AutoResetEvent hasDataEvent; private AutoResetEvent hasSpaceEvent; private Object operationLock; private Object EnqueueLock; private Object DequeueLock; /// /// The function initializes a new blocking queue that has /// the default length of 30 elements. /// public BlockingQueue() : this(30) { } /// /// The function initializes a blocking queue with the specified /// length. /// /// The length of the queue. public BlockingQueue(int capacity) { this.capacity = capacity; elementQueue = new Queue(capacity); operationLock = new Object(); EnqueueLock = new Object(); DequeueLock = new Object(); hasDataEvent = new AutoResetEvent(false); hasSpaceEvent = new AutoResetEvent(false); } /// /// The function enqueues the element. If the queue is full, the /// operation will block until free space becomes /// available. /// /// The element to be enqueued. public void Enqueue(T element) { bool queueFull = false; Monitor.Enter(EnqueueLock); Monitor.Enter(operationLock); try { if (elementQueue.Count < capacity) { elementQueue.Enqueue(element); hasDataEvent.Set(); } else { hasSpaceEvent.Reset(); queueFull = true; Monitor.Exit(operationLock); hasSpaceEvent.WaitOne(); elementQueue.Enqueue(element); hasDataEvent.Set(); } } finally { if (!queueFull) Monitor.Exit(operationLock); Monitor.Exit(EnqueueLock); } } /// /// The function tries to enqueue the element. If the operation succeeds /// without blocking, it returns true. Otherwise it return /// false. /// /// The element to be enqueued. /// True, if the element was successfully enqueued, otherwise false. public bool Offer(T element) { bool success = false; if (Monitor.TryEnter(EnqueueLock)) { try { if (Monitor.TryEnter(operationLock)) { try { if (elementQueue.Count < capacity) { elementQueue.Enqueue(element); hasDataEvent.Set(); success = true; } } finally { Monitor.Exit(operationLock); } } } finally { Monitor.Exit(EnqueueLock); } } return success; } /// /// The function dequeues and returns the last element from /// the end of the queue. The opeartion will block /// if the queue is empty. /// /// The last element in the queue. public T Dequeue() { bool QueueEmpty = false; T data; Monitor.Enter(DequeueLock); Monitor.Enter(operationLock); try { if (elementQueue.Count > 0) { data = elementQueue.Dequeue(); hasSpaceEvent.Set(); } else { hasSpaceEvent.Set(); hasDataEvent.Reset(); QueueEmpty = true; Monitor.Exit(operationLock); hasDataEvent.WaitOne(); data = elementQueue.Dequeue(); hasSpaceEvent.Set(); } } finally { if (!QueueEmpty) Monitor.Exit(operationLock); Monitor.Exit(DequeueLock); } return data; } /// /// The function tries to dequeue the last element from /// the end of the queue. If operation succeeds /// without blocking, it returns true. Otherwise it /// returns false. /// /// The last element in the queue. /// True, if the opeation succeeds, otherwise false. public bool Peek(out T element) { bool success = false; element = default(T); if (Monitor.TryEnter(DequeueLock)) { try { if (Monitor.TryEnter(operationLock)) { try { if (elementQueue.Count > 0) { element = elementQueue.Dequeue(); hasSpaceEvent.Set(); success = true; } } finally { Monitor.Exit(operationLock); } } } finally { Monitor.Exit(DequeueLock); } } return success; } /// /// The function gets the count of elements in the queue. /// /// The number of elements in this queue. public int Count() { Monitor.Enter(operationLock); try { return elementQueue.Count; } finally { Monitor.Exit(operationLock); } } } }