Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Ключевое слово 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#.