How to wait for async method to complete?

C#AsynchronousAsync Await

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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 https://stackoverflow.com/questions/12235967/await-doesnt-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

Solution 2 - C#

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();
}

Solution 3 - C#

Best Solution to wait AsynMethod till complete the task is

var result = Task.Run(async() => await yourAsyncMethod()).Result;

Solution 4 - C#

just put Wait() to wait until task completed

GetInputReportViaInterruptTransfer().Wait();

Solution 5 - C#

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.

Solution 6 - C#

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.")

Solution 7 - C#

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionbmt22033View Question on Stackoverflow
Solution 1 - C#Richard CookView Answer on Stackoverflow
Solution 2 - C#Stephen ClearyView Answer on Stackoverflow
Solution 3 - C#Ram chView Answer on Stackoverflow
Solution 4 - C#Firas NizamView Answer on Stackoverflow
Solution 5 - C#John MelvilleView Answer on Stackoverflow
Solution 6 - C#JertherView Answer on Stackoverflow
Solution 7 - C#Barış TanyeriView Answer on Stackoverflow