gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 02:32:20 27 4
gpt4 key购买 nike

作为学习练习,我尝试重现在普通 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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com