创建任务列表,任务不执行

时间:2013-10-27 09:49:23

标签: c# multithreading asynchronous task async-await

我有一个异步方法

private async Task DoSomething(CancellationToken token)

任务列表

private List<Task> workers = new List<Task>();

我必须创建运行该方法的N个线程

public void CreateThreads(int n)
{
    tokenSource = new CancellationTokenSource();
    token = tokenSource.Token;
    for (int i = 0; i < n; i++)
    {
        workers.Add(DoSomething(token));
    }
}

但问题是那些必须在给定时间运行

public async Task StartAllWorkers()
{
    if (workers.Count > 0)
    {
        try
        {
            while (workers.Count > 0)
            {
                Task finishedWorker = await Task.WhenAny(workers.ToArray());
                workers.Remove(finishedWorker);
                finishedWorker.Dispose();
            }
            if (workers.Count == 0)
            {
                tokenSource = null;
            }
        }
        catch (OperationCanceledException)
        {
            throw;
        }
    }
}

但实际上它们在我调用CreateThreads方法(StartAllWorkers之前)时运行。 我搜索了像我这样的关键字和问题,但找不到任何关于阻止任务运行的信息。 我已经尝试了很多不同的方法,但任何可以完全解决我的问题的方法。 例如,将代码从DoSomething移动到workers.Add(new Task(async () => { }, token));会运行StartAllWorkers(),但线程永远不会真正启动。

还有另一种方法可以调用tokenSource.Cancel()

2 个答案:

答案 0 :(得分:8)

您可以将TaskCompletionSource<T>用作异步方法的一次性“信号”。

所以你要像这样创建它:

private TaskCompletionSource<object> _tcs;
public void CreateThreads(int n)
{
    _tcs = new TaskCompletionSource<object>();
    tokenSource = new CancellationTokenSource();
    token = tokenSource.Token;
    for (int i = 0; i < n; i++)
    {
        workers.Add(DoSomething(_tcs.Task, token));
    }
}

然后,当您准备好开始任务时,只需完成“开始”信号任务:

public Task StartAllWorkers()
{
    _tcs.TrySetCompleted(null);
    return Task.WhenAll(workers);
}

(上面的StartAllWorkers方法与原始方法的语法略有 :原始方法会在第一个任务取消后立即抛出取消异常;此方法将等到所有方法完成然后抛出取消异常)

然后你的DoSomething必须遵守“开始信号”:

private static async Task DoSomething(Task start, CancellationToken token)
{
    await start;
    ... // rest of your code
}

答案 1 :(得分:1)

这个想法怎么样:

不要保存任务列表,而是保留TaskReference项列表:

public class TaskReference
{
    private readonly Func<Task> _func;

    public TaskReference(Func<Task> func)
    {
        _func = func;
    }

    public async Task RunAsync()
    {
        await _func();
    }
}

添加到列表的方式如下:

taskList.Add(new TaskReference(() => DoSomething(myToken)));

执行如下:

await Task.WhenAll(taskList.Select(o => o.RunAsync()));
相关问题