如何确保任务启动并安全启动它,如果没有?

时间:2017-12-04 13:47:18

标签: c# asynchronous async-await task

我从某个我无法控制的地方得到IEnumerable<Task> tasks。我不知道是否使用new TaskTask.Run手动创建任务,或者他们是否是异步方法调用async Task DoSomethingAsync()的结果。

如果我await Task.WhenAll(tasks),我冒着无限期挂起的风险,因为可能没有启动一项或多项任务。

我不能tasks.ForEach(t => t.Start()),因为那时我会得到一个InvalidOperationException&#34;可能不会在promise风格的任务上调用Start&#34;如果是来自异步方法调用(已经启动)。

我无法await Task.WhenAll(tasks.Select(t => Task.Run(async () => await t))),因为每个t仍然无法等待它开始。

我认为该解决方案与基于此检查每个任务StatusStart()有关,但我也认为它可能很棘手,因为该状态可能会随之改变时间,对吗?如果这仍然是要走的路,那么检查哪些状态是正确的,我应该担心哪些线程问题?

非工作案例:

//making an IEnumerable as an example, remember I don't control this part
Task t = new Task( () => Console.WriteLine("started"));
IEnumerable<Task> tasks = new[] {t};

//here I receive the tasks
await Task.WhenAll(tasks);//waits forever because t is not started

工作案例:

//calls the async function, starting it.
Task t = DoSomethingAsync();
IEnumerable<Task> tasks = new[] {t};

//here I receive the tasks and it will complete because the task is already started
await Task.WhenAll(tasks);

async Task DoSomethingAsync() => Console.WriteLine("started");

1 个答案:

答案 0 :(得分:5)

如果由于某种原因您无法将代码更改为不返回未启动的任务,则可以检查Status并启动任务,如果它具有Created状态:

if (task.Status == TaskStatus.Created)
   task.Start();

所有其他任务状态表明任务已完成,正在运行或正在安排,因此您无需在该状态下启动任务。

当然,理论上这会引入竞争条件,因为任务可以在你的支票和Start电话之间开始,但正如Servy在评论中正确指出的那样 - 如果这里有竞争条件 - 这意味着另一个派对(创建该任务)试图启动它。即使您处理异常(InvalidOperationException) - 另一方也不太可能这样做,因此在尝试启动自己的任务时会出现异常。所以只有一方(你或者创建该任务的代码)应该尝试启动它。

这就是说 - 比这样做要好得多,以确保你可能永远不会在第一时间得到未启动的任务,因为将这些任务返回到外部代码只是糟​​糕的设计,至少没有明确指出(虽然它是用于某些用途)可以在内部使用未启动的任务。