简体   繁体   中英

Why does 'await' change the thread context in WinForms program.cs

The normal behavior of using await to call an asynchronous method is that its context stays the same as shown in the example below:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void Form1_Load(object sender, EventArgs e)
    {
        //main thread here
        await SampleAsync();
        //stays as main thread
        var g = 10;
    }

    static async Task SampleAsync()
    {
        await Task.Delay(1000);
    }
}

But when I use this in the Winforms Main console method call, this behavior is no longer true: After calling the await method, the thread change from the main thread to the worker thread. Why is this? I would like for it to stay on the Main (UI Thread) after the await call.

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        MainAsync().Wait();
    }

    static async Task MainAsync()
    {
        Application.Run(new Form1());
        //Main Thread here
        await Task.Delay(1000);
        //Why does it turn in to worker thread here? ConfigureAwait(false) is not used here?!
        var g = 5;
        //Run other Application.Run() if certain conditions apply; but I need to be in the Main Thread.
    }

In case you are wondering what I am trying to achieve, I am trying to catch the errors in the async method, MainAsync, rather than Main so that I can avoid having to disentangle errors from the AggregateException ( https://msdn.microsoft.com/en-us/magazine/JJ991977.aspx ; Figure4). I also want to stay in the UI thread so I can run other Application.Run in the UI thread.

Because Application.Run is what "Runs" the continuation on the main thread, once Application.Run returned SynchronizationContext.Current was unset for the "UI Thread" therefor the await had to use the default context which is the ThreadPool.

Because you have no UI at that point I would recommend doing a synchronous wait ( .Wait() ) instead of a await at that point, that will make sure you are still on the same STA thread for your later Application.Run calls.

EDIT : Did not see your mention about disentangling AggregateException, all await is doing with the AggregateException is doing the equivalent of

catch(AggregateException ex)
{
    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}

Which causes the first exception of the AggregateException to be re-raised without messing up it's stack trace.

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