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 гарантирует, что все потоки будут видеть временные записи, выполняемые другим потоком, в порядке их выполнения.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. Нет никакой гарантии единого общего прядка временных записей во всех потоках выполнения.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.
  • Типы указателей (в небезопасном контексте).Pointer types (in an unsafe context). Несмотря на то, что сам указатель может быть изменяемым, объект, на который он указывает, должен быть постоянным.Note that although the pointer itself can be volatile, the object that it points to cannot. Другими словами, объявить указатель на изменяемый объект невозможно.In other words, you cannot declare a "pointer to volatile."
  • Простые типы, например sbyte, byte, short, ushort, int, uint, char, float и bool.Simple types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.
  • Тип enum с одним из следующих базовых типов: byte, sbyte, short, ushort, int или uint.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 и UIntPtr.IntPtr and UIntPtr.

Другие типы, включая double и long, нельзя снабдить модификатором 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

В следующем примере показано, как объявить переменную поля открытого типа 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()
    {
        bool work = false;
        while (!_shouldStop)
        {
            work = !work; // simulate some work
        }
        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 500 milliseconds to
        // allow the worker thread to do some work.
        Thread.Sleep(500);

        // 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: 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