C# 向现有WaitAll添加更多任务
假设我有一个C# 向现有WaitAll添加更多任务,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,假设我有一个Tasks的集合,我将在上面WaitAll()。 假设,在它们全部完成之前,我想向集合中添加更多的任务,并且我想继续等待,直到它们全部完成。我可能会在结束前增加更多的任务,等等 我可以用第三方物流吗?还是我必须手动滚动我自己的线程管理?(恶心!) WaitAll()作用于Task[]所以我不能只打开一个列表,我调用.ToArray()打开,因为这样等待就不会知道添加了什么新任务了 关于WaitAny()的类似问题也适用。以下是WaitAll的一个解决方案: 假设您有以下列表来保存任务
Task
s的集合,我将在上面WaitAll()
。
假设,在它们全部完成之前,我想向集合中添加更多的任务,并且我想继续等待,直到它们全部完成。我可能会在结束前增加更多的任务,等等
我可以用第三方物流吗?还是我必须手动滚动我自己的线程管理?(恶心!)
WaitAll()
作用于Task[]
所以我不能只打开一个列表
,我调用.ToArray()
打开,因为这样等待就不会知道添加了什么新任务了
关于
WaitAny()
的类似问题也适用。以下是WaitAll
的一个解决方案:
假设您有以下列表来保存任务:
List<Task> tasks = new List<Task>();
只需确保在向列表中添加任务时锁定列表,如下所示:
lock (tasks)
{
tasks.Add(...
}
顺便问一下,您为什么要同步等待任务而不是异步等待任务(您使用的是
WaitAll
而不是whalll
)?如果您想同步等待某个任务,然后再等待其他任务,您需要取消原来的等待并启动一个新的等待。按照开始时的等待方式进行初始等待,然后当需要添加更多任务时,将其添加到当前任务列表中,并发出取消信号,从而重新启动等待
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();
}
}
}
}
公共类mutableTaskWater
{
私有列表_tasks=新列表();
私有取消令牌源;
公共可数任务
{
得到
{
锁定(_任务)
{
return_tasks.ToArray();
}
}
}
公共void WaitAll(IEnumerable任务)
{
WaitMoreTasks(任务);
做
{
尝试
{
_cts=新的CancellationTokenSource();
Task.WaitAll(_tasks.ToArray(),_cts.Token);
}
捕获(操作取消异常)
{
//重新开始并等待新任务
}
}
while(_cts.iscancellationrequest);
}
public void WaitAny(IEnumerable任务)
{
WaitMoreTasks(任务);
做
{
尝试
{
_cts=新的CancellationTokenSource();
Task.WaitAny(_tasks.ToArray(),_cts.Token);
}
捕获(操作取消异常)
{
//重新开始并等待新任务
}
}
while(_cts.iscancellationrequest);
}
公共任务(IEnumerable任务)
{
锁定(_任务)
{
_tasks.AddRange(任务);
如果(_cts!=null)
{
//用更新的任务列表发出等待重新启动的信号
_cts.Cancel();
}
}
}
}
当然,如果你长时间添加任务,并且最初有一些短期任务,你仍然需要处理WaitAll场景中的种族条件。e、 g.如果我的初始任务列表在5秒后完成,我不能在10秒后将新任务添加到等待列表中,因为我已经在等待了。Re wait/When,因为这是在升级庞大的传统代码库的核心线程(替换
QueueUserWorkItem
+ManualResetEvent
-基于信号量)让异步和/或回调扩展到整个代码库的其余部分是站不住脚的。
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();
}
}
}
}