【发布时间】:2015-12-10 02:25:03
【问题描述】:
看这段代码:
public class SharedData
{
public int Value { get; set; }
}
void button1_Click(object sender, EventArgs e)
{
AAA();
}
async Task BBB(SharedData data)
{
await Task.Delay(TimeSpan.FromSeconds(1));
MessageBox.Show(data.Value.ToString()); //<---- I always see 0 here,
data.Value = data.Value + 1;
}
async Task<int> AAA()
{
SharedData data = new SharedData();
var task1 = BBB(data);
var task2 = BBB(data);
var task3 = BBB(data);
await Task.WhenAll(task1, task2, task3);
MessageBox.Show(data.Value.ToString()); //<--- this does show 3
return data.Value;
}
这是一个 GUI(Windows 窗体)应用程序,这意味着只有一个线程执行每一行代码。
所有BBB(data) 调用都非常快速地调用,无需等待。
每个 BBB 调用都进入 BBB method ,看到 await 没有完成并返回(到 AAA)。
现在,当一秒钟(大约)过去时,所有的继续都发生在 GUI 线程中。
问题
Continuations 不会同时发生,因为它是一个 GUI 线程。 所以之前的声明:
data.Value = data.Value + 1;
一定发生过。
换句话说,
我知道所有 BBBs 都使用相同的初始值 data 调用,但延续不会同时发生
GUI 线程必须最终运行:
继续#1
MessageBox.Show(data.Value.ToString());
data.Value = data.Value + 1; //So this basically should do 0-->1
....
继续#2
MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
data.Value = data.Value + 1;
....
继续#3
MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
data.Value = data.Value + 1;
看起来延续计划不是作为一个整体而是作为共享量子?
【问题讨论】:
-
@Eser 我不明白,每个延续都有自己的 gui 线程。这里没有个其他线程。为什么要锁?这不是(!)在线程池线程中运行,这意味着没有要保留的上下文(并且每个延续都可以在另一个线程池线程中运行)..
-
更改
BBB以接受并使用延迟值:async Task BBB(SharedData data, int delay),然后传递不同的值而不是相同的1。想知道为什么现在您一次看到三个消息框,而不是一次看到一个? :) -
@Noseratio 是的,我很想知道 :-) 你能解释一下吗? This code 一起显示 3 个 MSgBox,而不是一次显示 1 个(如我的示例中所示)。你能解释一下为什么吗?
-
将此归咎于底层 Win32
MessageBoxAPI。如果您使用Form.ShowDialog,您会看到所有 3 个框都按照正确的 1-2-3 顺序排列。使用MessageBox,其他两个框仍然存在,只是不可见。他们确实已经开始了他们的嵌套模式消息循环,一个又一个,因为await Task.Delay(1000)延续仍然被抽。嵌套消息循环开始,由赢得比赛的任何延续引起,因此显示窗口的代码在该消息循环终止之前不会启动。 -
Royi,@StephenCleary 的answer 比我上面的评论更详细地解释了它。
标签: c# .net winforms async-await