简体   繁体   中英

How do I call asynchronous method returning void from synchronous method in C# and be sure async method is finished?

I have searched StackOverflow and not found a definitive answer to my particular situation. I have a method:

public async Task InitializeMachine()
{
    await DoSomeWork1();
    // other stuff
    await DoSomeWork2();
    // other stuff
}

Notice the signature it returns is Task , not Task<T> . It would be difficult (if not impossible to rewrite all the methods like this. I would like to call this method from a synchronous method AND have it wait for the InitializeMachine method to completely finish. Again, it would be hard to change it into an async method (I'll describe why below for those interested). I have looked at some related questions and references such as:

https://msdn.microsoft.com/en-us/magazine/mt238404.aspx and

await works but calling task.Result hangs/deadlocks and

How to call asynchronous method from synchronous method in C#?

The answers seem to be old (perhaps there is a newer better way?) and at least in many cases, they seem to depend on the async method returning Task<T> , not just Task . I have

void Initialize()
{
    //InitializeMachine(); // Perfectly legal, but will return at first await
     //return Task.Run(() => InitializeMachine()).GetAwaiter().GetResult();  // can't get this to compile. My typo? Or because it's Task not Task<T> ? This is the "Thread Pool Hack" in first reference above by Stephen Cleary
     var task = Task.Run(() => InitializeMachine()); // these 2 lines work!
        task.Wait();  // but see heated argument in 2nd reference in the answer by Herman Schoenfeld. Is it safe?
        Task task = Task.Run(async () => await InitializeMachine()); // also works. Comes from 3rd reference by author "Tohid"

}

Can someone tell me which method I should be using and why? As I said, I tried to do the research but found myself a little lost on all the arguments as to why there could be a potential deadlock and other problems. Adding to my confusion was all the disagreements. Surely by 2018 there is a definitive way?

Thanks, Dave

PS For those who care, I'm playing with the SMC state machine library. See: https://sourceforge.net/projects/smc/ Briefly, state machine code is automatically generated from a text file. BUT the code generated is synchronous methods. Yes, I could hack the generated code (but it will get overwritten) or rethink the entire problem (perhaps InitializeMachine should be not by asynch), but my question would remain nonetheless. It seems to me there are times where synchronous methods need to call async ones and they should wait until the async method is complete!

You should be using this:

InitializeMachine().GetAwaiter().GetResult();

This will ensure that any exception raised at InitializeMachine is not wrapped into an AggregateException . Note that the return statement is not needed since you aren't returning anything ( void method).

Edit
Since you are using WPF, it would be better if you just kept the async-all-the-way-down pattern:

public async void InitializeMachineAsync()
{
    await DoSomeWork1().ConfigureAwait(false);
    await DoSomeWork2().ConfigureAwait(false);
}

InitializeMachineAsync can be any event (like Window_Load )

the simplest thing to do is

InitializeMachine().Wait();

there are some considerations around exception handling

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM