volatile (Справочник по C#)
Ключевое слово volatile
означает, что поле может изменить несколько потоков, выполняемых одновременно. Компилятор, среда выполнения или даже аппаратное обеспечение могут изменять порядок операций чтения и записи в расположения в памяти для повышения производительности. Поля, которые объявлены volatile
, исключаются из некоторых типов оптимизации. Нет никакой гарантии единого общего порядка временных записей во всех потоках выполнения. Дополнительные сведения см. в описании класса Volatile.
Примечание
В многопроцессорной системе переменные операции чтения не гарантируют получения последнего значения, записанного в эту область памяти любым из процессоров. Аналогичным образом, операция записи не гарантирует, что записываемое значение будет сразу отображаться для других процессоров.
Ключевое слово volatile
может применяться к полям следующих типов:
- Ссылочные типы.
- Типы указателей (в небезопасном контексте). Несмотря на то, что сам указатель может быть изменяемым, объект, на который он указывает, должен быть постоянным. Другими словами, объявить указатель на изменяемый объект невозможно.
- Простые типы, например
sbyte
,byte
,short
,ushort
,int
,uint
,char
,float
иbool
. - Тип
enum
с одним из следующих базовых типов:byte
,sbyte
,short
,ushort
,int
илиuint
. - Параметры универсального типа называются ссылочными типами.
- IntPtr и UIntPtr.
Другие типы, включая double
и long
, нельзя снабдить модификатором volatile
, потому что для них не гарантируется атомарность операций чтения и записи. Чтобы защитить многопотоковый доступ к полям таких типов, используйте члены класса Interlocked или защиту доступа с помощью инструкции lock
.
Ключевое слово volatile
можно применять только к полям class
или struct
. Локальные переменные не могут объявляться как volatile
.
Пример
В следующем примере показано, как объявить переменную поля открытого типа volatile
.
class VolatileTest
{
public volatile int sharedStorage;
public void Test(int i)
{
sharedStorage = i;
}
}
Следующий пример демонстрирует создание вспомогательного или рабочего потока и его применение для выполнения обработки параллельно с обработкой основного потока. Дополнительные сведения о многопоточности см. в разделе Управляемая поточность.
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
, вы всегда получите одинаковые результаты (как показано в приведенном выше фрагменте кода). Но если член _shouldStop
не имеет этого модификатора, поведение будет непредсказуемым. Метод DoWork
может оптимизировать доступ к членам, что приведет к чтению устаревших данных. В условиях многопоточного программирования невозможно прогнозировать число операций чтения устаревших данных. При каждом запуске программы результаты могут отличаться.
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.