我以为我对这个主题了解很多,但以下内容让我感到困惑。我知道在我运行它的特定 PC 上,“_x++”被转换为三个汇编指令(将值从内存移动到寄存器,在寄存器中递增,写回内存)。那么,为什么在地球上,当锁定到单个 CPU 时,增加值的线程不会在增加值的确切时间被抢占,但仍然在寄存器中并且没有写回内存?有人知道这个问题的答案吗?我猜这完全靠运气,但我无法完全证明这一点。
通过在 VS 的反汇编窗口中设置断点inc eax
,然后在调试器中执行几个步骤,我能够使正确的结果消失,但这不是证据。不是一个坚实的。
[此代码故意不是线程安全的。这不是生产代码,它用于教育目的。我正试图深入研究这个主题。当然,如果没有缓存线,我们会得到很多,但仍然—— 三个指令,甚至没有一个未命中,这很奇怪!这是一个 4 核 CPU,x64。]
{
private static int NumberOfThreads = 2;
private const long IncrementIterations = 1000000000;
private static int _x;
static void Main(string[] args)
{
Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)1;
Console.WriteLine("Hit Enter");
Console.ReadLine();
while (true)
{
var barrier = new Barrier(NumberOfThreads);
_x = 0;
var threads = new List<Thread>();
for (int i = 0; i < NumberOfThreads; i++)
{
var thread = new Thread(
delegate()
{
barrier.SignalAndWait();
for (int j = 0; j < IncrementIterations; j++)
{
_x++;
}
});
thread.Start();
threads.Add(thread);
}
BlockUntilAllThreadsQuit(threads);
Console.WriteLine(_x);
Console.WriteLine("Actual increments: " + (IncrementIterations * NumberOfThreads));
if (_x != (IncrementIterations * NumberOfThreads))
{
Console.WriteLine("Observed: " + _x);
break;
}
}
Console.ReadLine();
}
private static void BlockUntilAllThreadsQuit(IEnumerable<Thread> threadsToWaitFor)
{
foreach (var thread in threadsToWaitFor)
{
thread.Join();
}
}
}