私はこの件について多くのことを知っていると思っていましたが、次のことが私を困惑させます。これを実行する特定の PC では、「_x++」が 3 つのアセンブリ命令 (メモリからレジスタに値を移動、レジスタをインクリメント、メモリに書き戻す) に変換されることがわかっています。では、一体なぜ、単一の CPU にロックされている場合、値をインクリメントするスレッドは、値がインクリメントされる正確な時間にプリエンプトされず、レジスタ内にあり、メモリに書き戻されないのでしょうか? 誰もこれに対する答えを知っていますか? これは完全に運が良かったと推測していますが、正確に証明することはできません。
VS の逆アセンブリ ウィンドウでブレーク ポイントを設定し、デバッガーでいくつかの手順を実行することで、正しい結果を消すことができましたがinc eax
、それは証拠ではありません。しっかりしたものではありません。
[このコードは意図的にスレッドセーフではありません。これは製品コードではなく、教育目的に使用されます。テーマを深く掘り下げようとしています。もちろん、キャッシュ ラインが見えなくなると、多くの情報が得られますが、それでも 3 つの命令があり、1 つのミスもありません。これは奇妙なことです。これは 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();
}
}
}