我创建了一个类,允许异步顺序执行任务,使用 ThreadPool 作为执行方式。这个想法是我将有多个实例在后台运行串行任务,但我不想为每个实例都有一个单独的专用线程。我想检查的是这个类是否真的是线程安全的。它相当简短,所以我想我应该由这里的专家运行它,以防我遗漏一些明显的东西。我省略了一些针对不同 Action 类型的便捷重载。
/// <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);
}
}
}
}
更新:我修改了代码以修复 Simon 友善指出的主要错误。这现在通过了单元测试,但我仍然欢迎观察。
最佳答案
不要这样做。 (或者至少避免构建自己的东西。)
使用 System.Threading.Tasks东西(.NET 4.0 中的新功能)。创建您的 Task [](大小取决于您想要的并行任务的数量)并让他们从 BlockingCollection 中读取工作项在等待 CancellationToken 时.您的 WaitForAll
实现将触发您的 token ,并调用 Task.WaitAll(Task[])它将阻塞,直到您完成所有任务。
关于c# - 串行任务执行器;这个线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3670914/