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

Dav*_* S. 5 c# asynchronous task async-await

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

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

我不能这样做tasks.ForEach(t => t.Start()),因为那样我将得到一个InvalidOperationException"如果它来自一个异步方法调用(已经启动),则可能无法在promise风格的任务上调用".

我不能这样做,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
Run Code Online (Sandbox Code Playgroud)

工作案例示例:

//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");
Run Code Online (Sandbox Code Playgroud)

Evk*_*Evk 5

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

if (task.Status == TaskStatus.Created)
   task.Start();
Run Code Online (Sandbox Code Playgroud)

所有其他任务状态均指示任务已完成,正在运行或正在计划中,因此您无需在该状态下启动任务。

当然,从理论上讲,这会引入竞争条件,因为可以在您的检查和Start通话之间立即开始任务,但是正如Servy在评论中正确指出的(如果此处存在竞争条件),这意味着(创建该任务的)另一方是试图启动它。即使您处理了例外(InvalidOperationException),另一方也不太可能这样做,因此在尝试开始自己的任务时也会获得例外。因此,只有一方(您或创建该任务的代码)应尝试启动它。

就是说-比这样做要好得多,因为要确保您永远不会遇到未启动的任务,因为将此类任务返回到外部代码是很糟糕的设计,至少没有明确指出(虽然在某些用例中可以在内部使用未启动的任务)。

  • 如果您担心别人要启动它的竞争状况,则意味着*其他人也在尝试启动任务*,而他们*不应*尝试启动它,那么您需要修复或*您*不应尝试启动它,因为其他人正在启动它。 (4认同)