等待无ConfigureAwait(假)将继续在不同的线程 [英] await without ConfigureAwait(false) continues on a different thread

查看:158
本文介绍了等待无ConfigureAwait(假)将继续在不同的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WinForms应用程序,而我有一些code,需要在UI线程上运行。然而,code后等待运行在不同的线程。

 保护覆盖异步无效OnHandleCreated(EventArgs的发送)
{
    base.OnHandleCreated(E);    //这将运行在UI线程上。
    mainContainer.Controls.Clear();    VAR的结果=等待DoSomethingAsync();    //这也需要在UI线程上运行,但事实并非如此。
    //相反,它抛出一个异常:
    //跨线程操作无效:控制'mainContainer上从比它创建的线程以外的线程访问
    mainContainer.Controls.Add(新控制());
}

我也试过明确加入 ConfigureAwait(真),但它并没有区别。我的理解是,如果我忽略 ConfigureAwait(假),那么继续要原来的线程上运行。这是不正确在某些情况下?

我也注意到,如果我在的await前添加控件到集合,然后延续神奇运行在正确的线程。

 保护覆盖异步无效OnHandleCreated(EventArgs的发送)
{
    base.OnHandleCreated(E);    //这将运行在UI线程上。
    mainContainer.Controls.Add(新控制());
    mainContainer.Controls.Clear();    VAR的结果=等待DoSomethingAsync();    //这个现在还运行在UI线程上。为什么?
    mainContainer.Controls.Add(新控制());
}

我的问题是:


  1. 为什么会出现这种情况?

  2. 如何说服延续(最好没有做增加了控制和消除它的劈我)在UI线程上运行?

有关参考,在这里是 DoSomethingAsync 的重要组成部分。它使用提交的RestSharp HTTP请求。​​

 保护异步任务DoSomethingAsync()
{
    IRestRequest请求= CreateRestRequest();    //我在这里等待来自RestSharp的响应。
    //客户端是一个IRestClient实例。
    //我试图删除ConfigureAwait(假)的一部分,但它并没有区别。
    VAR响应=等待Client.ExecuteTaskAsync(要求).ConfigureAwait(假);    如果(response.ResponseStatus == ResponseStatus.Error)
        抛出新的异常(response.ErrorMessage ??请求未成功完成。);    如果(response.Status code> =的HTTPStatus code.BadRequest)
        抛出新的异常(服务器错误回答:+ response.Status code);    //我在这里做响应的一些处理;为简洁起见省略。
    //没有更多的等待着。
}


解决方案

<击>看来有些奇怪与 OnHandleCreated 发生。我的解决方案是使用的OnLoad 来代替。我是pretty满意这个解决方案,因为实在没有理由使用 OnHandleCreated 在我的处境。

我仍然好奇,为什么发生这种情况,因此,如果有人知道,随意张贴另一个答案。

编辑:

我发现真正的问题所在:原来,我打电话 Form.ShowDialog() ConfigureAwait(假)。因此,被正在兴建的UI线程的形式,但后来我打电话的ShowDialog 在非UI线程。我很惊讶,这个工作的。

我已经删除了 ConfigureAwait(假)所以现在的ShowDialog 获取调用在UI线程上。

I have a WinForms app, and I have some code that needs to run on the UI thread. However, the code after the await runs on a different thread.

protected override async void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);

    // This runs on the UI thread.
    mainContainer.Controls.Clear();

    var result = await DoSomethingAsync();

    // This also needs to run on the UI thread, but it does not.
    // Instead it throws an exception:
    // "Cross-thread operation not valid: Control 'mainContainer' accessed from a thread other than the thread it was created on"
    mainContainer.Controls.Add(new Control());
}

I also tried explicitly adding ConfigureAwait(true), but it makes no difference. My understanding was that if I omit ConfigureAwait(false), then the continuation should run on the original thread. Is this incorrect in some situations?

I've also noticed that if I add a control to the collection before the await, then the continuation magically runs on the correct thread.

protected override async void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);

    // This runs on the UI thread.
    mainContainer.Controls.Add(new Control());
    mainContainer.Controls.Clear();

    var result = await DoSomethingAsync();

    // This also runs on the UI thread now. Why?
    mainContainer.Controls.Add(new Control());
}

My question is:

  1. Why is this happening?
  2. How do I convince the continuation to run on the UI thread (ideally without doing my hack of adding a control and removing it)?

For reference, here are the important parts of DoSomethingAsync. It submits an HTTP request using RestSharp.

protected async Task DoSomethingAsync()
{
    IRestRequest request = CreateRestRequest();

    // Here I await the response from RestSharp.
    // Client is an IRestClient instance.
    // I have tried removing the ConfigureAwait(false) part, but it makes no difference.
    var response = await Client.ExecuteTaskAsync(request).ConfigureAwait(false);

    if (response.ResponseStatus == ResponseStatus.Error)
        throw new Exception(response.ErrorMessage ?? "The request did not complete successfully.");

    if (response.StatusCode >= HttpStatusCode.BadRequest)
        throw new Exception("Server responded with an error: " + response.StatusCode);

    // I also do some processing of the response here; omitted for brevity.
    // There are no more awaits.
}

解决方案

It appears that something strange is happening with OnHandleCreated. My solution was to use OnLoad instead. I'm pretty happy with this solution because there is really no reason to use OnHandleCreated in my situation.

I'm still curious as to why this is happening, so if anyone knows, feel free to post another answer.

Edit:

I found the real problem: it turns out that I was calling Form.ShowDialog() after a ConfigureAwait(false). As such, the form was being constructed on the UI thread, but then I was calling ShowDialog on a non-UI thread. I'm surprised that this worked at all.

I've removed the ConfigureAwait(false) so now ShowDialog is getting called on the UI thread.

这篇关于等待无ConfigureAwait(假)将继续在不同的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆