6

Interlockedまず第一に、使用にまだvolatileフィールド定義が必要かどうかを調べようとしていました。それが私の本当の質問です。

しかし。生成された MSIL を分析するのが面倒なので、実際に確認することにしました。

最適化をオンにしてリリースビルドでコードが壊れるはずの場合の使用法として、MSDN の例をvolatile試しています。そして、何も壊れません。最適化をオンまたはオフにして、コードは正常に動作します (この場合、メイン スレッドは正常に終了します)。

  1. ロックなしで別のスレッドvolatileを使用してあるスレッドからフィールドに書き込み、別のスレッドから読み取る場合、フィールドにキーワードが必要ですか?Interlocked
  2. 最初の質問のコードの簡単な例はどこでvolatile違いが生じるのですか?
  3. volatileキーワードを削除してリリースでビルドしても、MSDN の例がまだ機能するのはなぜですか?

質問 1 を説明するためのコード スニペット。

class Example
{
    volatile int val;

    void Do()
    {
        Task.Run(() => { while (val == 0) Console.WriteLine("running"); });

        Thread.Sleep(1000);
        Interlocked.Increment(ref val);
        Console.WriteLine("done.");
        Console.ReadLine();
    }
}
4

2 に答える 2

2

変数が としてマークされていない場合、volatileそれを読み取るコードは、他のスレッドによって変更される可能性があることを認識できません。したがって、JIT コンパイラーは、値をレジスターに保持することが安全でない可能性があることを知りません。

volatile他のスレッドが値を変更できることを JIT コンパイラに伝える方法です。InterlockedJITer は他のコードが存在することさえ知らない可能性があるため、値を変更するときに他のスレッドが使用する可能性があることは無関係です。

JIT コンパイラーがすべてのコードを認識できるため、単純な例が機能する可能性があります。これら 2 つのコードが別々のメソッドにある場合や、まったく異なるアセンブリにある場合は、状況が大きく異なる可能性があります。

于 2013-02-04T17:12:42.400 に答える
2

まあ、私volatileは違いを生むInterlockedが役に立たないコードを生成することができました。テストするには、デバッガーなしでリリース ビルドを実行する必要があります。

public class Example
{
    private volatile int val = 0;

    public static void Main()
    {
        var example = new Example();

        Task.Run(() => Interlocked.Increment(ref example.val));

        while (example.val == 0) ;
        // this never happens if val is not volatile
        Console.WriteLine("done.");
        Console.ReadLine();
    }
}

詳細が表示されない場合は、@ JimMischelの回答にいくつかの説明があるため、受け入れます。

更新:いくつかの詳細を説明するこのブログ投稿も見つかりました。

于 2013-02-04T17:42:37.120 に答える