У меня есть класс, который я создал, чтобы разрешить асинхронное последовательное выполнение задач, используя ThreadPool в качестве средства выполнения.Идея состоит в том, что у меня будет несколько экземпляров, выполняющих последовательные задачи в фоновом режиме, но я не хочу иметь отдельный выделенный поток для каждого экземпляра.Я хотел бы проверить, действительно ли этот класс поточно-ориентирован.Это довольно кратко, поэтому я подумал, что я буду управлять этим здесь экспертами, на случай, если я упущу что-то очевидное.Я пропустил несколько вспомогательных перегрузок для различных типов действий.
/// <summary>
/// This class wraps ThreadPool.QueueUserWorkItem, but providing guaranteed ordering of queued tasks for this instance.
/// Only one task in the queue will execute at a time, with the order of execution matching the order of addition.
/// This is designed as a lighter-weight alternative to using a dedicated Thread for processing of sequential tasks.
/// </summary>
public sealed class SerialAsyncTasker
{
private readonly Queue<Action> mTasks = new Queue<Action>();
private bool mTaskExecuting;
/// <summary>
/// Queue a new task for asynchronous execution on the thread pool.
/// </summary>
/// <param name="task">Task to execute</param>
public void QueueTask(Action task)
{
if (task == null) throw new ArgumentNullException("task");
lock (mTasks)
{
bool isFirstTask = (mTasks.Count == 0);
mTasks.Enqueue(task);
//Only start executing the task if this is the first task
//Additional tasks will be executed normally as part of sequencing
if (isFirstTask && !mTaskExecuting)
RunNextTask();
}
}
/// <summary>
/// Clear all queued tasks. Any task currently executing will continue to execute.
/// </summary>
public void Clear()
{
lock (mTasks)
{
mTasks.Clear();
}
}
/// <summary>
/// Wait until all currently queued tasks have completed executing.
/// If no tasks are queued, this method will return immediately.
/// This method does not prevent the race condition of a second thread
/// queueing a task while one thread is entering the wait;
/// if this is required, it must be synchronized externally.
/// </summary>
public void WaitUntilAllComplete()
{
lock (mTasks)
{
while (mTasks.Count > 0 || mTaskExecuting)
Monitor.Wait(mTasks);
}
}
private void RunTask(Object state)
{
var task = (Action)state;
task();
mTaskExecuting = false;
RunNextTask();
}
private void RunNextTask()
{
lock (mTasks)
{
if (mTasks.Count > 0)
{
mTaskExecuting = true;
var task = mTasks.Dequeue();
ThreadPool.QueueUserWorkItem(RunTask, task);
}
else
{
//If anybody is waiting for tasks to be complete, let them know
Monitor.PulseAll(mTasks);
}
}
}
}
ОБНОВЛЕНИЕ: я исправил код, чтобы исправить основные ошибки, любезно указанные Симоном.Сейчас он проходит модульные тесты, но я все еще приветствую наблюдения.