【问题标题】:Creating a control in an async task causes a deadlock在异步任务中创建控件会导致死锁
【发布时间】:2013-06-28 22:12:59
【问题描述】:

预期的结果是:

一些任务 主异步 主要

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
        Console.WriteLine("Main");
        Console.ReadLine();
    }

    async static Task MainAsync()
    {
        await Task.Run(() => SomeTask());
        Console.WriteLine("MainAsync");
    }

    static async Task SomeTask()
    {
        TextBox tb = new TextBox();
        await Task.Delay(100);
        Console.WriteLine("SomeTask");
    }
}

但是,实际上并没有调用任何 Console.Writeline。

即使我编写一个 windows 窗体应用程序也会发生同样的事情,它显然有一个 win32 消息循环。

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

    protected async override void OnLoad(EventArgs e)
    {
        await MainAsync();
        MessageBox.Show("Done!");
        base.OnLoad(e);
    }

    async static Task MainAsync()
    {
        await Task.Run(() => SomeTask());

    static async Task SomeTask()
    {
        TextBox tb = new TextBox();
        await Task.Delay(100);
    }
}

MessageBox 永远不会出现。

【问题讨论】:

  • 猜测一下,创建控件会启动同步上下文,但没有活动的消息循环;这意味着它永远不会处理来自同步上下文的消息;同步上下文是......棘手

标签: c# asynchronous controls deadlock async-await


【解决方案1】:

马克是正确的;现代 Windows 窗体控件在创建时将在其当前线程上建立一个 WinForms SynchronizationContext

因此,SomeTask 会将其继续调度到 Win32 消息循环上,但没有线程处理该消息循环(例如,Application.Run)。

【讨论】:

  • 更新后的代码呢?明明确实有win32消息循环,那为什么不行呢?
  • 您仍在 另一个(非 UI)线程上创建控件,该线程没有 Win32 消息循环。
猜你喜欢
  • 2016-02-10
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
  • 2021-09-18
相关资源
最近更新 更多