How to make sure that the task is running and run it safely, if not?

I get IEnumerable<Task> tasks from somewhere that I do not control. I do not know if tasks are created manually using new Task , Task.Run or if they are the result of calling the async method of the async Task DoSomethingAsync() .

If I do await Task.WhenAll(tasks) , I risk hanging endlessly because maybe one or more tasks are not starting.

I cannot do tasks.ForEach(t => t.Start()) because then I will get an InvalidOperationException. "Start cannot be called into the promise style task" if it is called by calling the async method (already running).

I cannot do await Task.WhenAll(tasks.Select(t => Task.Run(async () => await t))) , because every t still does not start, just waiting for it.

I believe the solution has something to do with checking each Status and Start() task based on this, but I also assume that it can be tricky, as this status can change at any time, right? If this is still the way, what statuses would be correct for verification, and what kind of threading problems should I bother with?

Example of a non-working example:

 //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 

An example of a working case:

 //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"); 
+5
source share
1 answer

If for some reason you cannot change the code so as not to return unarmored tasks, you can check the Status and run the task if it has Created status:

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

All other task statuses indicate that the task is completed, started or scheduled, so you do not need to run tasks in these statuses.

Of course, theoretically, this introduces a race condition, because the task can be started right between your check and the Start call, but, as Servy correctly pointed out in the comments, if there was ever a race condition here, it means the other side (which created this task) is also trying to launch it. Even if you are handling an exception ( InvalidOperationException ), the other side is unlikely to do this, and therefore will get an exception when trying to run its own task. Therefore, only one side (either you or the code that created this task) should try to run it.

However, itโ€™s much better than doing this to ensure that you never succeed in completing a non-standard task, because itโ€™s just a bad design to return such tasks to external code, at least without explicitly indicating that (although it is for some use cases it is normal to use a non-standard task inside).

+3
source

Source: https://habr.com/ru/post/1273843/


All Articles