如果您想同步等待某件事,然后再等待其他事情,则需要取消原始等待并开始新的等待。原始的等待是什么时候开始,然后当你需要添加更多的任务时,将它们添加到当前的任务列表中,并发出取消消息以重新开始等待。
public class MutableTaskWaiter
{
private List<Task> _tasks = new List<Task>();
private CancellationTokenSource _cts;
public IEnumerable<Task> Tasks
{
get
{
lock (_tasks)
{
return _tasks.ToArray();
}
}
}
public void WaitAll(IEnumerable<Task> tasks)
{
WaitMoreTasks(tasks);
do
{
try
{
_cts = new CancellationTokenSource();
Task.WaitAll(_tasks.ToArray(), _cts.Token);
}
catch (OperationCanceledException)
{
// start over and wait for new tasks
}
}
while (_cts.IsCancellationRequested);
}
public void WaitAny(IEnumerable<Task> tasks)
{
WaitMoreTasks(tasks);
do
{
try
{
_cts = new CancellationTokenSource();
Task.WaitAny(_tasks.ToArray(), _cts.Token);
}
catch (OperationCanceledException)
{
// start over and wait for new tasks
}
}
while (_cts.IsCancellationRequested);
}
public void WaitMoreTasks(IEnumerable<Task> tasks)
{
lock (_tasks)
{
_tasks.AddRange(tasks);
if (_cts != null)
{
// signal the wait to restart with the updated task list
_cts.Cancel();
}
}
}
}
当然,你仍然将不得不对付在为WaitAll比赛条件scenarithat拿出如果你很长一段时间增加的任务,你有一些短暂的任务原本。例如如果我的初始任务列表在5秒后完成,我无法在10秒后将新任务添加到等待列表中,因为我已经完成了等待。
重新等待/何时,因为这是在一个巨大的遗留代码库的核心中升级线程(取代QueueUserWorkItem +基于ManualResetEvent的信号量)并且具有异步和/或回调,它遍布整个代码库的其余部分将是站不住脚的。 – Brondahl