//--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: SerialTaskQueue.cs
//
//--------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Threading.Tasks
{
/// Represents a queue of tasks to be started and executed serially.
public class SerialTaskQueue
{
/// The ordered queue of tasks to be executed. Also serves as a lock protecting all shared state.
private Queue _tasks = new Queue();
/// The task currently executing, or null if there is none.
private Task _taskInFlight;
/// Enqueues the task to be processed serially and in order.
/// The function that generates a non-started task.
public void Enqueue(Func taskGenerator) { EnqueueInternal(taskGenerator); }
/// Enqueues the non-started task to be processed serially and in order.
/// The task.
public Task Enqueue(Task task) { EnqueueInternal(task); return task; }
/// Gets a Task that represents the completion of all previously queued tasks.
public Task Completed() { return Enqueue(new Task(() => { })); }
/// Enqueues the task to be processed serially and in order.
/// The task or functino that generates a task.
/// The task must not be started and must only be started by this instance.
private void EnqueueInternal(object taskOrFunction)
{
// Validate the task
if (taskOrFunction == null) throw new ArgumentNullException("task");
lock(_tasks)
{
// If there is currently no task in flight, we'll start this one
if (_taskInFlight == null) StartTask_CallUnderLock(taskOrFunction);
// Otherwise, just queue the task to be started later
else _tasks.Enqueue(taskOrFunction);
}
}
/// Called when a Task completes to potentially start the next in the queue.
/// The task that completed.
private void OnTaskCompletion(Task ignored)
{
lock (_tasks)
{
// The task completed, so nothing is currently in flight.
// If there are any tasks in the queue, start the next one.
_taskInFlight = null;
if (_tasks.Count > 0) StartTask_CallUnderLock(_tasks.Dequeue());
}
}
/// Starts the provided task (or function that returns a task).
/// The next task or function that returns a task.
private void StartTask_CallUnderLock(object nextItem)
{
Task next = nextItem as Task;
if (next == null) next = ((Func)nextItem)();
if (next.Status == TaskStatus.Created) next.Start();
_taskInFlight = next;
next.ContinueWith(OnTaskCompletion);
}
}
}