195

I'm writing a WinForms application that transfers data to a USB HID class device. My application uses the excellent Generic HID library v6.0 which can be found here. In a nutshell, when I need to write data to the device, this is the code that gets called:

private async void RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        RequestToGetInputReport();
    }
}

When my code drops out of the while loop, I need to read some data from the device. However, the device isn't able to respond right away so I need to wait for this call to return before I continue. As it currently exists, RequestToGetInputReport() is declared like this:

private async void RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

For what it's worth, the declaration for GetInputReportViaInterruptTransfer() looks like this:

internal async Task<int> GetInputReportViaInterruptTransfer()

Unfortunately, I'm not very familiar with the workings of the new async/await technologies in .NET 4.5. I did a little reading earlier about the await keyword and that gave me the impression that the call to GetInputReportViaInterruptTransfer() inside of RequestToGetInputReport() would wait (and maybe it does?) but it doesn't seem like the call to RequestToGetInputReport() itself is waiting because I seem to be re-entering the while loop almost immediately?

Can anyone clarify the behavior that I'm seeing?

bmt22033
  • 6,880
  • 14
  • 69
  • 98

7 Answers7

297

The most important thing to know about async and await is that await doesn't wait for the associated call to complete. What await does is to return the result of the operation immediately and synchronously if the operation has already completed or, if it hasn't, to schedule a continuation to execute the remainder of the async method and then to return control to the caller. When the asynchronous operation completes, the scheduled completion will then execute.

The answer to the specific question in your question's title is to block on an async method's return value (which should be of type Task or Task<T>) by calling an appropriate Wait method:

public static async Task<Foo> GetFooAsync()
{
    // Start asynchronous operation(s) and return associated task.
    ...
}

public static Foo CallGetFooAsyncAndWaitOnResult()
{
    var task = GetFooAsync();
    task.Wait(); // Blocks current thread until GetFooAsync task completes
                 // For pedagogical use only: in general, don't do this!
    var result = task.Result;
    return result;
}

In this code snippet, CallGetFooAsyncAndWaitOnResult is a synchronous wrapper around asynchronous method GetFooAsync. However, this pattern is to be avoided for the most part since it will block a whole thread pool thread for the duration of the asynchronous operation. This an inefficient use of the various asynchronous mechanisms exposed by APIs that go to great efforts to provide them.

The answer at "await" doesn't wait for the completion of call has several, more detailed, explanations of these keywords.

Meanwhile, @Stephen Cleary's guidance about async void holds. Other nice explanations for why can be found at http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/ and https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

J A Terroba
  • 123
  • 4
Richard Cook
  • 32,523
  • 5
  • 46
  • 71
  • 25
    I find it useful to think (and talk) about `await` as an "asynchronous wait" - that is, it blocks the *method* (if necessary) but not the *thread*. So it makes sense to talk about `RequestToSendOutputReport` "waiting for" `RequestToGetInputReport` even though it's not a *blocking* wait. – Stephen Cleary Mar 01 '13 at 13:49
  • @Richard Cook - thank you very much for the additional explanation! – bmt22033 Mar 01 '13 at 14:02
  • 12
    This ought to be the accepted answer, since it more clearly answer the actual question (i.e. how to thread-wise block on an async method). – csvan Feb 18 '15 at 07:14
  • 1
    best solution is wait async till task complete is var result = Task.Run(async() => { return await yourMethod(); }).Result; – Ram ch Jun 16 '17 at 00:12
  • @StephenCleary Why did the C# team provide the `Result` property and `Wait()` method if they aren't to be used because of dead locks? – David Klempfner Nov 26 '21 at 06:44
  • 4
    @DavidKlempfner: `Wait` and `Result` were already on the `Task` type before `await` was invented. Before `await` arrived, `Task` was part of the Task Parallel Library, and primarily used for parallel programming. – Stephen Cleary Nov 26 '21 at 21:43
162

Avoid async void. Have your methods return Task instead of void. Then you can await them.

Like this:

private async Task RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        await RequestToGetInputReport();
    }
}

private async Task RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}
Jeremy
  • 3,418
  • 2
  • 32
  • 42
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 1
    Very nice, thank you. I was scratching my head on a similar issue and the difference was to change `void` to `Task` just as you had said. – Jeremy Dec 11 '14 at 20:19
  • 10
    It's a minor thing, but to follow the convention both methods should have Async added to their names, e.g. RequestToGetInputReportAsync() – tymtam Jun 08 '16 at 03:55
  • 8
    and what if the caller is the Main function? – symbiont Sep 06 '16 at 09:24
  • 21
    @symbiont: Then use `GetAwaiter().GetResult()` – Stephen Cleary Sep 06 '16 at 12:10
  • It would be so awesome if knowing what magic is done when return Task instead of void. – Ahmed Salah Dec 19 '18 at 10:21
  • 5
    @AhmedSalah The `Task` represents the execution of the method - so `return` values are placed on `Task.Result`, and exceptions are placed on `Task.Exception`. With `void`, the compiler has nowhere to place exceptions, so they are just re-raised on a thread pool thread. – Stephen Cleary Dec 19 '18 at 13:21
131

Best Solution to wait AsynMethod till complete the task is

var result = Task.Run(async() => await yourAsyncMethod()).Result;
Tomi
  • 3,370
  • 1
  • 16
  • 26
Ram ch
  • 1,633
  • 1
  • 13
  • 5
  • 30
    Or this for your async "void": Task.Run(async () => { await yourAsyncMethod(); }).Wait(); – Jiří Herník Feb 20 '18 at 23:47
  • 1
    What is the benefit of this over yourAsyncMethod().Result? – Justin J Stark Sep 14 '18 at 14:05
  • 5
    Simply accessing the .Result property doesn't actually wait until the task is finished executing. In fact, I believe it throws an exception if it is called before a task is completed. I think the advantage of wrapping this in a Task.Run() call is that, as Richard Cook mentions below, "await" does not actually wait for a task to complete, but using a .Wait() call blocks your whole thread pool. This allows you to (synchronously) run an async method on a separate thread. Slightly confusing, but there it is. – Lucas Leblanc Dec 05 '18 at 21:38
  • Quick reminder ECMA7 featurelike assync() or await wont work in pre-ECMA7 environment. – Mbotet Jul 11 '19 at 15:01
  • NEVER use this .Result, especially in Net Framework. .GetAwaiter().GetResult() is not the best, but much better option – Lightning3 Jun 04 '20 at 08:22
  • Would be a good answer if a) it mentioned that this runs yourAsyncMethod on a separate threadpool thread, and b) it Wait()ed before trying to access the result. If you can't Wait() or "await" in your current thread, threadpool can be a legitimate solution. – tekHedd Sep 30 '21 at 19:58
  • This solution perfectly work for me. – Pramod Lawate Apr 13 '22 at 12:09
  • @Lightning3 Should one still wrap the async method in a Task.Run() call? Or just go for .GetAwaiter().GetResult() without the wrapper? What would be the difference in these two approaches? Furthermore, why not Task.Run().Result? – String.Empty Sep 29 '22 at 02:32
7

just put Wait() to wait until task completed

GetInputReportViaInterruptTransfer().Wait();

Firas Nizam
  • 1,392
  • 12
  • 7
0

All of the above answers are right, you should never synchronously wait on a task ... unless you have to! Sometimes you want to call an async method inside of a interface implementation you do not control and there is no way to do "async all the way down."

Here is a little class to at least contain the damage:

public class RunSynchronous
{
    public static void Do(Func<Task> func) => Task.Run(func).GetAwaiter().GetResult();
    public static T Do<T>(Func<Task<T>> func) => Task.Run(func).GetAwaiter().GetResult();
    public static void Do(Func<ValueTask> func) => Do(() => func().AsTask());
    public static T Do<T>(Func<ValueTask<T>> func) => Do(() => func().AsTask());
}

This class uses the .GetAwaiter.GetResult pattern to actually convert async to sync. But if you do that byitself in WPF or another SynchronizationContext bound to a particular thread you deadlock. This code avoids deadlock by transferring the async operation to the threadpool which is not synchronized to a particular thread. As long as you do not go crazy and block all the threadpool threads you ought to be OK.

usage is like this

    return RunSynchronous.Do(()=>AsyncOperation(a,b,c));

will launch AsynchronousOperation(a,b,c) on the threadpool and wait for it to return. As long as you do not explicitly synchornize back to the origin thread you ought to be OK.

John Melville
  • 3,613
  • 28
  • 30
-5

The following snippet shows a way to ensure the awaited method completes before returning to the caller. HOWEVER, I wouldn't say it's good practice. Please edit my answer with explanations if you think otherwise.

public async Task AnAsyncMethodThatCompletes()
{
    await SomeAsyncMethod();
    DoSomeMoreStuff();
    await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")
Jerther
  • 5,558
  • 8
  • 40
  • 59
  • 1
    Downvoters, care to explain, like I asked in the answer? Because this works well as far as I know... – Jerther Mar 10 '16 at 13:02
  • 3
    The problem is that the only way you can do the `await` + the `Console.WriteLine` is by it becoming a `Task`, which gives up control between the two. so your 'solution' will ultimately yield a `Task`, which doesnt address the problem. Doing a [`Task.Wait` will](http://stackoverflow.com/questions/32075084/manage-update-in-application-exit/32075919#) will actually stop processing (with deadlock possibilities etc). In other words, `await` does not actually wait, it simply combines two asynchronously executable portions into a single `Task` (that someone can watch or wait for) – Ruben Bartelink May 03 '16 at 15:35
-7

Actually I found this more helpful for functions that return IAsyncAction.

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;