0

I'm trying to implement a timeout pattern for an awaitable task as described here: https://stackoverflow.com/a/11191070

However, I am getting unexpected results. I've written a small console app to demonstrate (bottom of this post). These are the scenarios and results I get:

Scenario 1
DelayTask  Thread.Sleep(10000);
ActualTask Thread.Sleep(100);
Invoked with await Task.WhenAny(...
Result: THEN clause invoked  CORRECT

Scenario 2
DelayTask  Thread.Sleep(100);
ActualTask Thread.Sleep(10000);
Invoked with await Task.WhenAny(...
Result: THEN clause invoked  INCORRECT

Scenario 3
DelayTask  Thread.Sleep(10000);
ActualTask Thread.Sleep(100);
Invoked WITHOUT await: Task.WhenAny(...
Result: ELSE clause invoked  INCORRECT

Scenario 4
DelayTask  Thread.Sleep(100);
ActualTask Thread.Sleep(10000);
Invoked WITHOUT await: Task.WhenAny(...
Result: ELSE clause invoked  CORRECT

Can anyone shed any light as to why this is not functioning as expected. TIA!

   class Program
    {

        static void Main(string[] args)
        {
            Run();
        }

        private static async void   Run()
        {
            var _cancelWorkTokenSource = new CancellationTokenSource();
            var task = ActualTask(_cancelWorkTokenSource.Token);
            var delayTask = DelayTask(_cancelWorkTokenSource.Token);

            if (await Task.WhenAny(task, delayTask) == task)
            {
                Console.WriteLine("Task Succeeded in time."); 
            }
            else
            {
                Console.WriteLine("Task exceeded time limit");
            };

            Console.ReadLine();
        }

        private static async Task DelayTask(CancellationToken cancelToken)
        {
            Thread.Sleep(10000);
        }

        private static async Task ActualTask(CancellationToken cancelToken)
        {
            Thread.Sleep(100);
        }
    }
gilpach
  • 1,367
  • 3
  • 16
  • 34
  • 2
    FYI - in your shared answer you should notice that this line `Task.WhenAny(task, Task.Delay(timeout))` uses `Task.Delay` for the "wait" part and not `Thread.Sleep` as you are doing. – Rand Random May 22 '20 at 16:24

1 Answers1

6

Because your dummy methods are implemented incorrectly. Change Thread.Sleep to await Task.Delay:

private static async Task DelayTask(CancellationToken cancelToken)
{
    await Task.Delay(10000);
}

 private static async Task ActualTask(CancellationToken cancelToken)
 {
    await Task.Delay(100);
 }

What is happening right now in your code:

  1. var task = ActualTask(_cancelWorkTokenSource.Token) blocks current thread for 10000 milliseconds and returns completed Task
  2. After that var delayTask = DelayTask(_cancelWorkTokenSource.Token); blocks current thread for 100 milliseconds and returns completed task
  3. await Task.WhenAny(task, delayTask) selects first of them cause both are completed

Add to your code Console.WriteLine(task.IsCompleted); and Console.WriteLine(delayTask.IsCompleted); after corresponding variables initialization to check it.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132