Async-await无法正确恢复上下文 [英] Async-await does not recover context correctly
问题描述
我有一个简单的winforms应用程序,它有一个初始化部分,对UI没有任何了解。此初始化运行异步。以下结构显示初始化部分:
$
I've a simple winforms application that has an initialization part that doen't know anything about UI. This initialization runs async. The following contruct shows that initialization part:
[STAThread]
private static void Main()
{
var main = new Form1();
using (var mre = new ManualResetEventSlim())
{
Initialization().ContinueWith(_ => mre.Set());
while (!mre.Wait(TimeSpan.FromMilliseconds(25)))
{
Application.DoEvents();
}
}
Application.Run(main);
}
private static async Task Initialization()
{
await Task.Delay(100);
}
我们必须等到初始化才能显示主窗口。我不知道在主要等待异步操作的更好方法 - 欢迎提示。
之后我创建了一个包含以下代码的表单: br $>
We have to wait until initialization before the main window is shown. I don't know a better way to wait for an async operation in main - hints are welcome.
After that I created a form that contains the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
// Thread.CurrentThread.ManagedThreadId == 1;
await Task.Delay(500);
// Thread.CurrentThread.ManagedThreadId != 1 !!!!!!!
}
}
这就是全部。该表单上没有控件。
问题是Form1_Load开始使用主线程的线程1(如预期的那样)。等待该延迟后,上下文无法正确恢复。等待Task.Delay(100)后运行代码的线程;不是主线。这会导致问题
通过访问该表单中包含的控件。
指定ConfigureAwait(true)将无法解决问题。
如何避免这种情况并强制等待按预期恢复主线程的上下文?
如果我们不出现问题更改以下内容之一:
不要等待使用此hacky构造的异步操作。但是我们需要等待初始化。
在等待构造之后创建Form1的实例。
问题是在Application.Run之前调用Application.DoEvents() (...)。
程序中强制解决该问题的代码可以简化为:
That's all. There are no controls on that form.
The Problem is that Form1_Load starts using thread 1 (as expected) which is the main thread. After await for that delay the context is not restored correctly. The thread running code after await Task.Delay(100); is not the main thread. That causes problems
by accessing controls contained on that form.
Specifying ConfigureAwait(true) will not solve the problem.
How can I avoid that and force await to restore the context as expected to the main thread?
The Problem does not appear if we change one of the following things:
Do not wait for an async operation using this hacky construct. But we need to wait for our initialization.
Create the instance of Form1 after that waiting construct.
The problem is a call of Application.DoEvents() before Application.Run(...).
The code in Program that forces that problem can be simplyfied to:
[STAThread]
private static void Main()
{
var main = new Form1();
Application.DoEvents();
Application.Run(main);
}
初始化()上的简单Wait()将导致死锁。
A simple Wait() on Initialization() will result in a deadlock.
推荐答案
如果
初始化不需要表格,然后尝试这个顺序:
If Initialization does not need the form, then try this order:
初始化()。等待();
Initialization().Wait();
var main =
new Form1();
Application.Run(main);
Application.Run( main );
否则请考虑以下代码:
  
var main =
new Form1();
Task.Run(初始化).Wait();
Task.Run( Initialization ).Wait();
Application.Run(main);
Application.Run( main );
这篇关于Async-await无法正确恢复上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!