public class AsyncWorkQueue<T>
{
private Queue<T> _queue; //internal queue.
private int _max_concurrent; //maximum concurrent async work items.
private int _concurrent; //current number of concurrent tasks.
private int _completed; //current number of completed work items.
public delegate void QueueCompletedHandler();
public delegate void ItemDequeuedHandler(T obj);
public event QueueCompletedHandler OnQueueCompleted; //event fired when the _concurrent field hits zero (after at least 1 item has been added to the queue)
public event ItemDequeuedHandler OnItemDequeued; //event fired when a new item is dequeued.
public bool IsBusy { get; private set; } //whether the queue is currently processing async items.
//Create a new AsyncWorkQueue, sets the maximum number of concurrent items
//as well as the dequeue handler (when a new item is ready to be worked on)
public AsyncWorkQueue(int concurrent_items, ItemDequeuedHandler dequeueHandler)
{
this._max_concurrent = concurrent_items;
this._concurrent = 0;
this._completed = 0;
this._queue = new Queue<T>();
this.IsBusy = false;
this.OnItemDequeued = dequeueHandler;
}
//Called when an item has finished being worked on. This is the responsibility of the developer
//to call this whenever their async operation finishes.
public void ItemCompleted()
{
this._concurrent--;
this._completed++;
if (this._concurrent == 0)
{
this.IsBusy = false;
if (this.OnQueueCompleted != null)
this.OnQueueCompleted();
}
else
{
this.QueueAltered();
}
}
// Add another item to the queue.
public void Enqueue(T obj)
{
if (obj != null)
{
this._queue.Enqueue(obj);
this.QueueAltered();
}
}
//handle concurrency.
private void QueueAltered()
{
if (this._concurrent < this._max_concurrent && this._queue.Count > 0)
{
this.IsBusy = true;
this._concurrent++;
T item = this._queue.Dequeue();
if (this.OnItemDequeued != null)
this.OnItemDequeued(item);
}
}
}