简体   繁体   English

为什么'await'会改变WinForms program.cs中的线程上下文

[英]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: 使用await调用异步方法的正常行为是它的上下文保持不变,如下例所示:

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. 但是当我在Winforms主控制台方法调用中使用它时,这种行为不再成立:在调用await方法之后,线程从主线程更改为工作线程。 Why is this? 为什么是这样? I would like for it to stay on the Main (UI Thread) after the await call. 我希望它在等待调用后保持在Main(UI线程)上。

    [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). 如果你想知道我想要实现什么,我试图捕获异步方法中的错误,MainAsync,而不是Main,以便我可以避免从AggregateException( https://msdn.microsoft)解开错误。 com / en-us / magazine / JJ991977.aspx ;图4)。 I also want to stay in the UI thread so I can run other Application.Run in the UI thread. 我还想留在UI线程中,这样我就可以在UI线程中运行其他Application.Run。

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. 因为Application.Run是“运行”主线程上的延续,所以一旦Application.Run返回SynchronizationContext.Current ,则为“UI线程”取消设置,因此await必须使用默认上下文,即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. 因为此时没有UI,我建议在此时进行同步等待( .Wait() )而不是await ,这将确保您仍然在以后的Application.Run调用的同一个STA线程上。

EDIT : Did not see your mention about disentangling AggregateException, all await is doing with the AggregateException is doing the equivalent of 编辑 :没有看到你提到关于解开AggregateException,所有等待是用AggregateException做的相当于

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. 这导致重新引发AggregateException的第一个异常,而不会弄乱它的堆栈跟踪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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