Doug
Doug

Reputation: 6518

Task.Await within loop not acting as intended

I have a class that awaits an asynchronous thread to return. What I do is launch a while loop and check every second where it's at.

public class AsychronousThingy
{
   public bool IsComplete{get;private set;}
   public string Result {get;private set;}
   public void StartDoingThings(){
       IsComplete = false;
       // kick of an asynchronous thread to do stuff...
   }
   private void OnComplete(){
       IsComplete = true;
       Result = "magical result";
   }
}
public class ActionExecutor{
    public async Task<CustomThingyTaskResult> DoStuff(){
        var thing = new AsychronousThingy();
        thing.StartDoingThings();

        // this returns instantly...?
        while(!thing.IsComplete){
             await Task.Delay(1000);
        }

        // do stuff once the 'thing' is complete.
        return new CustomThingyTaskResult(thing.Result);
    }
}
class Program{
    public static void Main(){
         var exec = new ActionExecutor();
         var returnValue = await exec.DoStuff();
    }
}

I'm unsure why it is returning instantly. Is this an issue - can you not use Task.Delay inside a loop? Odd.

I am sure that this is returning before it is complete as when I console.writeline from the OnComplete event of my async class it actually completes after my main method has finished.

Upvotes: 0

Views: 856

Answers (2)

Norfolc
Norfolc

Reputation: 458

Your Main() function is void. As a result, after first hit to actual async action (in your example it is await Task.Delay(1000)) it returns control to its caller. So, you can change the signature of Main() function as follows:

public static async Task Main() {...}

And then await on it.

Or, as alternative, you may not use async keyword on it and use old Wait/Result:

public static void Main()
{
...
var returnValue = exec.DoStuff().Result;
// Or, if there is a SynchronizationContext
returnValue = Task.Run(() => exec.DoStuff()).Result; // This may prevent dead locks that can occur in previous line
}

Upvotes: 1

Alexander Gessler
Alexander Gessler

Reputation: 46607

Because DoStuff() is async, it finishes asynchronously when called. This explains why the main method has already returned when the asynchronous action completes. However, since DoStuff returns void, you cannot await it as you would normally do. You can change the return type to Task though, and then await it.

There is nothing wrong about awaiting in a loop, except that it is more efficient to use events (or other synchronization mechanisms). Also, AsynchronousThingy could likely be formulated in terms of a Task as well :-)

Upvotes: 3

Related Questions