我在ASP.Net应用程序中有一个可以启动不同任务的SignalR Hub
public async Task StartHeatingTask()
{
await TaskPool.Instance.TryRun<Heating>(identifier, Heating_ReportProgress);
}
...
void Heating_ReportProgress(TaskProgressStatus status, OperationProgressEventArgs[] args)
{
this.Clients.All.reportProgress(status, args);
}
我的问题是如何避免同一任务的双重执行(标识符相同)。这是我TaskPool
的当前实现,但我不确定我是否正确使用locks
和await
的组合:
public class TaskPool
{
private Dictionary<string, LongRunningJob> pool;
private object syncRoot = new object();
public static TaskPool Instance = new TaskPool();
public async Task TryRun<T>(string identifier, LongRunningJob.Progress progressHandler, bool captureContext = false)
where T : LongRunningJob, new()
{
Task worker = null;
if (!this.pool.ContainsKey(identifier))
{
lock (this.syncRoot)
{
if (!this.pool.ContainsKey(identifier))
{
LongRunningJob job = new T {Identifier = identifier};
job.ProgressEventHandler += progressHandler;
this.pool.Add(identifier, job);
worker = job.RunAsync().ContinueWith(task => { this.pool.Remove(identifier); });
}
}
if (worker != null)
{
await worker.ConfigureAwait(captureContext);
}
}
}
public bool Terminate(string identifier)
{
if (this.pool.ContainsKey(identifier))
{
lock (this.syncRoot)
{
if (this.pool.ContainsKey(identifier))
{
this.pool[identifier].Terminate();
return true;
}
}
}
return false;
}
}
我也应await
执行上次用户调用启动的相同任务。我是C# 5 Task
的新手,所以很可能我的概念根本就错了,应该完全重新设计。
答案 0 :(得分:1)
BlockingCollection怎么样? 我认为在你的情况下,它提供了你正在寻找的东西: 它是一个带有
的线程安全集合private Dictionary<string, LongRunningJob> pool;
与
BlockingCollection<T>
元素
查看this页面
中的示例您还可以使用ConcurrentQueue类进行线程安全的先进先出(FIFO)集合