-1

This question answers how we can asynchronously wait for a task to finish with a timeout.

I have written a similar async method as shown below, which checks if the current value is greater that some defined threshold value.

public async Task<bool> FindThreshold(CancellationTokenSource cts)
{            
    await Task.Run(()=> { 
        if (this.currentValue >= this.ThresholdValue) {
            this.ThresholdFound = true; 
        } else { 
            this.ThresholdFound = false; 
        } 
    });
    if (ThresholdFound)
        return true;
    else
        return false;
}

Based on the similar solution given I am calling the function as shown below,

var found = await FindThresholdAsyncAsync(cts);
if (await Task.WhenAny(task, Task.Delay(
    TimeSpan.FromMilliseconds(Convert.ToDouble(timeout)*1000),
    cts.Token) == found)
{
    await found;
}

The error message says that Operator "==" cannot be applied to operands of the type 'Task' and 'bool'. I do understand that Task.Delay returns a task but I couldn't figure out why it is working in case of the solution mentioned here. Clearly, I am missing something so any insights would be really helpful.

Community
  • 1
  • 1
kosol
  • 31
  • 4

1 Answers1

1

You mustn't await the result of FindThreshold. Task.WhenAny takes a list of task and returns the first one to end. You must compare that to the task returned by FindThreshold to know whether it timed out. Then you can retrieve the result.

var task = FindThreshold(cts);
if (await Task.WhenAny(task, Task.Delay(
    TimeSpan.FromMilliseconds(Convert.ToDouble(timeout)*1000),
    cts.Token)) == task)
{
    var found = task.Result; // No need to await because we know the task is completed
}
else
{
    // Timeout
}
Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94
  • since FindThreshold has a return type of Task it still complains at the usage of '==' saying cannot convert from 'bool' to System.Threading.Task.Task. Also, I was using the await keyword since according to this solution [link](http://stackoverflow.com/questions/23272911/is-it-possible-to-use-taskbool-in-if-conditions) I have to await the FindThreshold method since I am returning Task and not bool. – kosol Nov 01 '16 at 22:49
  • Well that's the point. You don't await because you need a Task for the comparison and not a bool. Only after the check, you await (or call `.Result`) to get the bool. Try the code in my answer, you won't have the error – Kevin Gosse Nov 01 '16 at 22:58
  • @kosol Actually it was missing a parenthesis. Fixed. – Kevin Gosse Nov 01 '16 at 23:02
  • I feel so stupid that even i missed that in my code. It is very clear to me now. Thank you for your time. – kosol Nov 01 '16 at 23:29
  • i forgot to mention that according to the article here [link](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) one should avoid using task.result since it blocks the async code. So would using task.result a good idea in my case ? – kosol Nov 01 '16 at 23:38
  • @kosol In your case we already know that the task is completed, so `.Result` won't block. In fact, the `await` keyword has a special optimization for this case where it checks whether the task is already completed and just calls `.Result` (actually, it calls `GetAwaiter().GetResult()` but that's pretty much the same thing). So by using `.Result` instead of `await`, we have the same behavior but we're avoiding the extra bit of plumbing – Kevin Gosse Nov 02 '16 at 07:11
  • 1
    @KooKiz: I still prefer `await` over `Result` even if the task is already completed for two reasons: 1) `Result` wraps exceptions in an `AggregateException`, which complicates error handling; and 2) `await` is more resilient to future code changes (i.e., the genius down the hall changes the method so that the task is no longer guaranteed to be complete at that point). – Stephen Cleary Nov 02 '16 at 11:17