简体   繁体   中英

WinRT synchronising async calls across threads

I'm having an issue with a WinRT project. Currently the execution on the program is running on two threads. One thread executes the main application and the other handles the UI side of things. At the moment, I'm having an issue calling a function from the main thread to execute on the UI thread, waiting for a reply and then continuing execution on the main thread... let me show you some code as an example.

public async void SignOut(Action onSuccess, Action onFailure)
{
    bool success = false;
    bool wait = true;

    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        await SignOutAsync();
        success = true;
        wait = false;
    });

    while (wait) { }

    if (success)
    {
        onSuccess();
    }
    else
    {
        onFailure();
    }
}

So this code is doing what I want it to do but it's obviously not the right way to go about it with the busy waiting and all of that. The problem is that if I move the OnSuccess/OnFailure execution into the RunAsync lambda then there is an error on the callback about invalid memory because the execution is on a different thread. Currently the problem I'm facing is that I can't remove the busy wait without screwing up the order of execution. Ideally I want to wait for the entire RunAsync lambda to finish execution on the UI thread and then return to the main thread to run the success/fail callbacks.

It appears at the moment that as soon as I hit the await SignOutAsync() part of the RunAsync lambda the RunAsync task marks itself as complete and returns to the Success/Failure check before the SignOutAsync method has any result. I believe this is due to the nested async methods and that you can't really await on the RunAsync call and then again on the async lambda within it.

Any advice would be greatly appreciated.

Currently the execution on the program is running on two threads. One thread executes the main application and the other handles the UI side of things.

This is not ideal. If at all possible, structure your code so that you only have one "special" thread (the UI thread). async allows your UI thread to remain responsive without requiring a second "special" thread.

At the moment, I'm having an issue calling a function from the main thread to execute on the UI thread, waiting for a reply and then continuing execution on the main thread.

Again, a better design is to have your program logic provide "services" to the UI, instead of the other way around. So, do your best to redesign the calls so that the UI is driving the program logic and not the opposite.

That said, if you absolutely must have a single "special" background thread, you can use the AsyncContextThread type from my AsyncEx library . AsyncContextThread understands asynchronous methods, so you can do this:

public async Task SignOutAsync(Action onSuccess, Action onFailure)
{
    try
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => SignOutAsync());
        onSuccess();
    }
    catch
    {
        onFailure();
    }
}

However, I would be embarrassed to put this code into production; anything that uses Dispatcher is a code smell. Even though I wrote the AsyncContextThread type, I can't recommend it for Windows Store projects. A far better design is to structure the code so that the program logic never calls back into the UI.

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