Home > Software engineering >  WaitAny and WaitAll waiting algorithms under the hood (order of check tasks)
WaitAny and WaitAll waiting algorithms under the hood (order of check tasks)

Time:04-12

I need to understand in general/simple terms the algorithm for waiting for completion of tasks for wait methods (Task.WaitAny and Task.WaitAll). I don't know the language well enough to dig into the source code. I tried, but I got completely confused. I got to the point where both methods can call method AddCompletionAction.

For me, this is redundant information and I expect to get a simple answer according to the algorithm.

Question. How, in general terms, is the completion of tasks checked in the specified methods?

For example:

WaitAny checks IsCompleted of each task with a delay in time and when IsCompleted of any task is true, the method exits.

WaitAll checks IsCompleted of each task with a delay in time and when IsCompleted is true then this task is excluded from the following checks. Or WaitAll checks IsCompleted of conditionally first task, and until IsCompleted false, the others task will not be checked.

These are all my guesses and it's hard for me to figure out the source code of the framework. The answer is needed in simple words, as I wrote. There is no need to describe the operation of the entire method, affect the cancellation token, and so on. Interested only order of check tasks.

CodePudding user response:

The basic premise is that both methods cycle through the list of Tasks and assign a completion trigger to each Task - it keeps a count of how many items hit the completion trigger.

This is where you hit the difference between the two - if it's WaitAny then the first time that completion trigger is hit (i.e. whichever Task just so happens to finish quickest); it returns and goes back to whatever method called the WaitAny.

WaitAll only returns once the count of the completed Tasks matches the count of the original Tasks passed in to the method.

You've got your wires crossed - it's not intermittently checking for completion; it's waiting for it. Similar to in racing, it's not that the finish line intermittently checks for things crossing it - there's a beam across it, when someone crosses the line, they break the beam and the beam being broken triggers the lap/race completion process.

CodePudding user response:

I'll attempt to answer your question with simple code instead of simple words. Here is how the two methods WaitAny and WaitAll could be implemented by someone who understood the basic mechanism, but who also had a total indifference for getting the details correctly:

// For demonstration purposes only. This code is rubbish.
static Task MyWaitAny(params Task[] tasks)
{
    var tcs = new TaskCompletionSource<Task>();
    foreach (var task in tasks)
    {
        task.ContinueWith(t => tcs.SetResult(t));
    }
    return tcs.Task.Result;
}

// For demonstration purposes only. This code is rubbish.
static void MyWaitAll(params Task[] tasks)
{
    var tcs = new TaskCompletionSource();
    int completedCount = 0;
    foreach (var task in tasks)
    {
        task.ContinueWith(t =>
        {
            completedCount  ;
            if (completedCount == tasks.Length) tcs.SetResult();
        });
    }
    tcs.Task.Wait();
}

The MyWaitAny starts by creating a TaskCompletionSource<Task>. This is the mechanism that will propagate the Task that completed first. Then a continuation is attached to each Task in the tasks. This continuation just completes immediately the TaskCompletionSource<Task>. Finally the Task property of the TaskCompletionSource<Task> is waited by invoking the Result.

The MyWaitAll starts by creating a TaskCompletionSource. This mechanism will not propagate anything. It is created just for the purpose of waiting its Task property. Then a continuation is attached to each Task in the tasks. This continuation increments a counter, and when the counter reaches the tasks.Length it means that all tasks are completed, and so the TaskCompletionSource is completed too. Finally the Task property of the TaskCompletionSource is waited by invoking the Wait.

Note: be aware that the code above is so far away from being production-ready, that it's not even funny. If you have any temptation about fixing it, please don't. You might be able to fix half a dozen problems, and many other problems will be still there.

CodePudding user response:

Since the official Microsoft Docs for both waitAll and waitAny doesn't explicitly mention the order. You shouldn't be reliant on that in anyway. In other words, the framework implementation of this can change, and this will not be considered a breaking change.

I know you mentioned you need the answer in simple terms but here it goes: You can find the source code for it here. It looks like it's using a signaling mechanism, rather than periodically checking isCompleted as you mention in your question

  • Related