私は次のコードを持っています:
public static System.Int32 i = 0;
static void Main(string[] args)
{
new Thread(Worker1) { IsBackground = true }.Start();
new Thread(Worker2) { IsBackground = true }.Start();
Console.WriteLine("Running... Press enter to quit");
Console.ReadLine();
}
static void Worker1(object _)
{
while (true)
{
var oldValue = i;
i++;
var newValue = i;
if (newValue < oldValue)
Console.WriteLine("{2}, i++ went backwards! oldValue={0}, newValue={1}!", oldValue, newValue, DateTime.Now.ToString("HH:MM:ss.fff"));
}
}
static void Worker2(object _)
{
while (true)
{
i++;
}
}
実行すると、次のような出力が生成されます。
17:08:17.020, i++ went backwards! oldValue=6124653, newValue=6113984!
17:08:17.057, i++ went backwards! oldValue=18764535, newValue=18752368!
17:08:17.086, i++ went backwards! oldValue=27236177, newValue=27236176!
17:08:17.087, i++ went backwards! oldValue=27550457, newValue=27535008!
17:08:17.130, i++ went backwards! oldValue=40251349, newValue=40235492!
17:08:17.137, i++ went backwards! oldValue=42339974, newValue=42323786!
17:08:17.142, i++ went backwards! oldValue=43828602, newValue=43828436!
17:08:17.149, i++ went backwards! oldValue=45969702, newValue=45959111!
17:08:17.158, i++ went backwards! oldValue=48705847, newValue=48705549!
17:08:17.230, i++ went backwards! oldValue=71199684, newValue=71199674!
注:これは、Windows7でハイパースレッディングを使用するクアッドコアi7で実行されています
私が知る限り、次のいずれかです。
Thread2は、oldValueとnewValueの読み取りの間に、iを約40億倍(完全ではありません!)インクリメントしています。上記の数字とタイミングを考えると、次の2秒間に10回宝くじに当選する可能性が高いようです。
CPUとコンパイラがいくつかの並べ替えを行っています...これは論理的な説明のようですが、実際にこれを引き起こす可能性のある一連の操作を完全に理解することはできませんか?
誰かがそれに光を当てることができますか?
質問を明確にするために:私は、教育演習の一環として、メモリオーダリングのバグを再現するコードを意図的に探しています。これを修正する方法はたくさんありますが、私は主に何が起こっているのかを分析することに興味がありました。
@Tymekは、以下に(指摘されたので、目がくらむほど明白な)答えを示しました。