2016-04-14 39 views
2

假设我有一个Task s的集合,我将在WaitAll()上。 假设在他们完成之前,我想为该集合添加更多任务,并且我希望等待直到他们全部完成了。我可能会在结束之前添加更多任务等。等等。将进一步的任务添加到现有的WaitAll

我可以使用TPL来实现吗?或者我将不得不手动推出我自己的线程管理? (呸!)

WaitAll()作用Task[],所以我不能只是有一个List<Task>,我呼吁.ToArray(),因为那样的话等待不会知道被添加任何新的任务?

关于WaitAny()的类似问题也适用。

回答

1

这里是WaitAll一个解决方案:

假设您有以下列表保存的任务:

List<Task> tasks = new List<Task>(); 

这里是你如何可以等待他们:

while (true) 
{ 
    Task[] my_tasks; 

    lock (tasks) 
    { 
     my_tasks = tasks.ToArray(); //take snapshot 
     tasks.Clear(); //clear list 
    } 

    if (my_tasks.Length == 0) 
     break; 

    Task.WaitAll(my_tasks); 
} 

只需确保在将任务添加到列表中时锁定在列表上:

lock (tasks) 
{ 
    tasks.Add(... 
} 

顺便说一下,是否有一个原因,你为什么同步等待任务而不是异步(你正在使用WaitAll而不是WhenAll)?

+0

重新等待/何时,因为这是在一个巨大的遗留代码库的核心中升级线程(取代QueueUserWorkItem +基于ManualResetEvent的信号量)并且具有异步和/或回调,它遍布整个代码库的其余部分将是站不住脚的。 – Brondahl

0

如果您想同步等待某件事,然后再等待其他事情,则需要取消原始等待并开始新的等待。原始的等待是什么时候开始,然后当你需要添加更多的任务时,将它们添加到当前的任务列表中,并发出取消消息以重新开始等待。

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秒后将新任务添加到等待列表中,因为我已经完成了等待。

相关问题