有一天,我试图更好地理解线程概念,所以我写了几个测试程序。其中之一是:
using System;
using System.Threading.Tasks;
class Program
{
static volatile int a = 0;
static void Main(string[] args)
{
Task[] tasks = new Task[4];
for (int h = 0; h < 20; h++)
{
a = 0;
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = new Task(() => DoStuff());
tasks[i].Start();
}
Task.WaitAll(tasks);
Console.WriteLine(a);
}
Console.ReadKey();
}
static void DoStuff()
{
for (int i = 0; i < 500000; i++)
{
a++;
}
}
}
我希望我能看到小于 2000000 的输出。我想象中的模型如下:更多线程同时读取变量 a,a 的所有本地副本都将相同,线程递增它并发生写入并且一个或多个增量以这种方式“丢失”。
虽然输出违背了这个推理。一个示例输出(来自 corei5 机器):
2000000
1497903
1026329
2000000
1281604
1395634
1417712
1397300
1396031
1285850
1092027
1068205
1091915
1300493
1357077
1133384
1485279
1290272
1048169
704754
如果我的推理是真的,我偶尔会看到 2000000,有时数字会少一些。但是我偶尔看到的是 2000000,而数字远小于 2000000。这表明幕后发生的不仅仅是几个“增量损失”,而是更多的事情正在发生。有人可以解释一下情况吗?
编辑:当我编写这个测试程序时,我完全知道如何使这个线程安全,并且我希望看到小于 2000000 的数字。让我解释一下为什么我对输出感到惊讶:首先让我们假设上面的推理是正确的。第二个假设(这很可能是我困惑的根源):如果冲突发生(并且确实发生了),那么这些冲突是随机的,我希望这些随机事件的发生在某种程度上是正态分布。在这种情况下,输出的第一行说:从 500000 次实验中,随机事件从未发生过。第二行说:随机事件至少发生了 167365 次。0 和 167365 之间的差异太大(正态分布几乎不可能)。所以案例归结为以下几点:两个假设之一(“增量损失” 模型或“有点正态分布的并行冲突”模型)不正确。哪个是,为什么?