将更多任务添加到现有WaitAll

时间:2016-04-14 20:03:34

标签: c# multithreading task-parallel-library

假设我有Task的集合,我将WaitAll()打开。{1}}。 假设在他们全部完成之前,我想在该集合中添加更多任务,我希望等待继续等待,直到他们全部完成。我可能会在结束之前添加更多任务等等。

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

WaitAll()Task[]采取行动,因此我不能只打开List<Task>我打电话给.ToArray(),因为等待不会知道任何新任务那些被添加?

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

2 个答案:

答案 0 :(得分: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)?

答案 1 :(得分: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中的竞争条件。例如如果我的初始任务列表在5秒后完成,我不能在10秒后将新任务添加到等待列表中,因为我已经等待了。