【问题标题】:Async Await UI Deadlock异步等待 UI 死锁
【发布时间】:2015-07-10 22:17:00
【问题描述】:

我有一个基本类,用于显示带有异步延迟的淡入(和淡出)通知,以尝试保持 UI 响应。

 public partial class Notification : Form
{
    public Notification(string message)
    {
        InitializeComponent();
        txtNotification.Text = message;
    }

    async new public void Show()
    {
        FadeIn();
        await Task.Delay(7000);
        FadeOut();
    }

    async void FadeIn()
    {
        Opacity = 0;
        base.Show();
        while (Opacity < 1.0)
        {
            await Task.Delay(50);
            Opacity += 0.05;
        }
        Opacity = 1;
    }

    async void FadeOut()
    {
        while (Opacity > 0.0)
        {
            await Task.Delay(50);
            Opacity -= 0.05;
        }
        Opacity = 0;
        Hide();
    }
}

我还有一个 UI 事件处理程序想要执行一些繁重的工作,然后显示通知。

async public void MyHandler(args)
{
    await Task.Run(() => 
    {
            System.Diagnostics.Debug.WriteLine("Do something!");
    });
    new Notification("Work completed!").Show();
}

我在通知 FadeIn 'await Task.Delay(50)' 期间遇到了死锁。我是这个 async await malarkey 的新手,但据我了解,我不能简单地 ConfigureAwait,因为我需要在 UI 线程上淡入通知,并且我正在使用 async 并等待“一直向下”。如果我只是删除事件处理程序中完成工作的行,那么就没有死锁,但我正在等待它完成,所以不明白为什么我会陷入死锁。我肯定在这里误解了什么?

根据要求,我现在删除了 async void 并减少了代码:

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

    async Task FadeIn()
    {
        Opacity = 0;
        base.Show();
        while (Opacity < 1.0)
        {
            await Task.Delay(50);
            Opacity += 0.05;
        }
    }
}

我发现该问题不会在 WinForm 应用程序中重现,但会按照 Outlook 插件中的说明重现。为了更加简单,我现在使用 AddIn StartUp 事件,以下代码显示通知没有问题

    async private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {            
        await new Notification().FadeIn();
    }

但是正如我之前描述的那样,这段代码会导致挂起/死锁

    async private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        await Task.Run(() =>
       {
           System.Diagnostics.Debug.WriteLine("Do something!");
       });
        await new Notification().FadeIn();
    }

我新建了一个AddIn,没有其他代码,所以我认为问题一定是Outlook。(?)

【问题讨论】:

  • 这里没有任何东西可以导致死锁。这真的是你正在运行的吗?
  • 你可能不应该这样做async void FadeOut()。请改用async Task FadeOut()
  • @YuvalItzchakov 这与我正在运行的非常接近。通知类是准确的。该处理程序是一个功能区 xml 控件处理程序。也许这不是死锁,但执行在“等待 Task.Delay(50);”处无限期结束/挂起在 FadeIn 中,除非我立即删除 'new Notification("Work completed!").Show();' 之前的行。
  • 1) 避免使用async void。 2) 请发布一个最小的、可重现的示例。
  • @RussellHorwood:尝试将其添加为ThisAddIn_Startup 的第一行:SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

标签: c# multithreading asynchronous async-await


【解决方案1】:

@StephenCleary 提供了解决方案。在有问题的代码之前添加以下行。

SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 2021-09-18
    • 2018-08-26
    • 1970-01-01
    相关资源
    最近更新 更多