c# - 在控制台应用程序中使用 WindowsFormsSynchronizationContext 时异步/等待死锁

标签 c# async-await

作为学习练习,我尝试重现在普通 Windows 窗体中发生的异步/等待死锁,但使用控制台应用程序。我希望下面的代码会导致这种情况发生,事实确实如此。但使用await时也会意外发生死锁。

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
static class Program
{
    static async Task Main(string[] args)
    {
        // no deadlocks when this line is commented out (as expected)
        SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); 
        Console.WriteLine("before");
        //DoAsync().Wait(); // deadlock expected...and occurs
        await DoAsync(); // deadlock not expected...but also occurs???
        Console.WriteLine("after");
    }
    static async Task DoAsync()
    {
        await Task.Delay(100);
    }
}

我很好奇是否有人知道为什么会发生这种情况?

最佳答案

发生这种情况是因为 WindowsFormsSynchronizationContext取决于标准 Windows 消息循环的存在。控制台应用程序不会启动此类循环,因此不会处理发布到 WindowsFormsSynchronizationContext 的消息,不会调用任务继续,因此程序会在第一个 await 处挂起>。您可以通过查询 bool 属性 Application.MessageLoop 来确认消息循环不存在。 .

Gets a value indicating whether a message loop exists on this thread.

要使WindowsFormsSynchronizationContext发挥作用,您必须启动消息循环。可以这样完成:

static void Main(string[] args)
{
    EventHandler idleHandler = null;
    idleHandler = async (sender, e) =>
    {
        Application.Idle -= idleHandler;
        await MyMain(args);
        Application.ExitThread();
    };
    Application.Idle += idleHandler;
    Application.Run();
}

MyMain 方法是您当前的 Main 方法,已重命名。

<小时/>

更新:实际上是Application.Run方法会在当前线程中自动安装 WindowsFormsSynchronizationContext,因此您不必显式执行此操作。如果您希望阻止此自动安装,请配置属性 WindowsFormsSynchronizationContext.AutoInstall在调用 Application.Run 之前。

The AutoInstall property determines whether the WindowsFormsSynchronizationContext is installed when a control is created, or when a message loop is started.

关于c# - 在控制台应用程序中使用 WindowsFormsSynchronizationContext 时异步/等待死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58960005/

相关文章:

c# - 如何检测用户何时从 Visual Studio 运行或何时是常规运行的服务

javascript - 使用 Node js Await/Async 函数

python - 如何在Python3中将异步生成器流转换为类似文件的对象?

javascript - Sequelize 等待直到循环

C# I/O 异步 (copyAsync) : how to avoid file fragmentation?

c# - ListView.SelectedItems[0] 选择错误

c# - ValidationMessage 和 ValidationMessageFor 之间的区别

c# - 在 Razor 中更改标题并添加 Facebook OG 元数据

c# - 方向确定算法混合左右

c# - 异步/等待中的多个查询(错误 : IEnumerable does not contain ToListAsync())