volatile (C# リファレンス)volatile (C# Reference)

volatile キーワードは、同時に実行されている複数のスレッドによって、フィールドが変更される可能性があることを示します。The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. コンパイラ、ランタイム システム、さらにはハードウェアで、パフォーマンスを上げる目的でメモリの読み書き場所を再配置するかもしれません。The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. volatile が宣言されているフィールドはこのような最適化の対象になりません。Fields that are declared volatile are not subject to these optimizations. volatile 修飾子を追加することで、すべてのスレッドによって、他のスレッドにより実行される volatile 書き込みがその実行順序どおりに観察されます。Adding the volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order in which they were performed. 全ての実行スレッドから見たvolatile 書き込みの全体的順序が単一である保証はありません。There is no guarantee of a single total ordering of volatile writes as seen from all threads of execution.

volatile キーワードは次の型のフィールドに使用できます。The volatile keyword can be applied to fields of these types:

  • 参照型。Reference types.
  • ポインター型 (unsafe コンテキスト内)。Pointer types (in an unsafe context). ポインター自体は volatile にできますが、ポインターが指しているオブジェクトは volatile にできません。Note that although the pointer itself can be volatile, the object that it points to cannot. つまり、"volatile を指すポインター" は宣言できません。In other words, you cannot declare a "pointer to volatile."
  • sbytebyteshortushortintuintcharfloatbool など、単純型。Simple types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.
  • 基本型が bytesbyteshortushortintuint のいずれかの enum 型。An enum type with one of the following base types: byte, sbyte, short, ushort, int, or uint.
  • 参照型であることが判明しているジェネリック型パラメーター。Generic type parameters known to be reference types.
  • IntPtr および UIntPtrIntPtr and UIntPtr.

doublelong など、その他の型には volatile を指定できません。そのような型のフィールドに対する読み書きはアトミックになるとは限らないためです。Other types, including double and long, cannot be marked volatile because reads and writes to fields of those types cannot be guaranteed to be atomic. そのような型のフィールドへのマルチスレッド アクセスを保護するために、Interlocked クラス メンバーを使用するか、lock ステートメントでアクセスを保護します。To protect multi-threaded access to those types of fields, use the Interlocked class members or protect access using the lock statement.

volatile キーワードは class または struct のフィールドにのみ適用できます。The volatile keyword can only be applied to fields of a class or struct. ローカル変数を volatile として宣言することはできません。Local variables cannot be declared volatile.

Example

次の例は、public のフィールド変数を volatile として宣言する方法を示しています。The following example shows how to declare a public field variable as volatile.

class VolatileTest
{
    public volatile int sharedStorage;

    public void Test(int _i)
    {
        sharedStorage = _i;
    }
}

次の例は、補助スレッドつまりワーカー スレッドを作成および使用して、プライマリ スレッドとの並行処理を実行する方法を示しています。The following example demonstrates how an auxiliary or worker thread can be created and used to perform processing in parallel with that of the primary thread. マルチスレッドについて詳しくは、「マネージド スレッド処理」をご覧ください。For more information about multithreading, see Managed Threading.

public class Worker
{
    // This method is called when the thread is started.
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("Worker thread: working...");
        }
        Console.WriteLine("Worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Keyword volatile is used as a hint to the compiler that this data
    // member is accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    public static void Main()
    {
        // Create the worker thread object. This does not start the thread.
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // Start the worker thread.
        workerThread.Start();
        Console.WriteLine("Main thread: starting worker thread...");

        // Loop until the worker thread activates.
        while (!workerThread.IsAlive)
            ;

        // Put the main thread to sleep for 1 millisecond to
        // allow the worker thread to do some work.
        Thread.Sleep(1);

        // Request that the worker thread stop itself.
        workerObject.RequestStop();

        // Use the Thread.Join method to block the current thread 
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("Main thread: worker thread has terminated.");
    }
    // Sample output:
    // Main thread: starting worker thread...
    // Worker thread: working...
    // Worker thread: working...
    // Worker thread: working...
    // Worker thread: working...
    // Worker thread: working...
    // Worker thread: working...
    // Worker thread: terminating gracefully.
    // Main thread: worker thread has terminated.
}

volatile 修飾子を _shouldStop の宣言に追加することで、(前述のコードにある抜粋に似た) 同じ結果が常に得られます。With the volatile modifier added to the declaration of _shouldStop in place, you'll always get the same results (similar to the excerpt shown in the preceding code). しかしながら、この修飾子が _shouldStop メンバーになければ、動作は予測できません。However, without that modifier on the _shouldStop member, the behavior is unpredictable. DoWork メソッドでメンバー アクセスが最適化されることがありますが、古いデータが読み取られます。The DoWork method may optimize the member access, resulting in reading stale data. マルチスレッド プログラミングの性質上、古い読み取りの数は予測できません。Because of the nature of multi-threaded programming, the number of stale reads is unpredictable. プログラムを実行するたびに若干異なる結果が得られます。Different runs of the program will produce somewhat different results.

C# 言語仕様C# language specification

詳細については、「C# 言語の仕様」を参照してください。For more information, see the C# Language Specification. 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。The language specification is the definitive source for C# syntax and usage.

関連項目See also