Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Ключевое volatile слово указывает, что поле может быть изменено несколькими потоками, выполняющимися одновременно. Компилятор, система выполнения и даже оборудование могут переупорядочивать операции чтения и записи в расположение памяти для повышения производительности. Объявленные volatile поля исключаются из определенных типов оптимизаций. Нет никакой гарантии единого общей упорядочения переменных записей, как показано во всех потоках выполнения. Дополнительные сведения см. в Volatile классе.
Осторожность
Ключевое volatile слово часто неправильно понимается и неправильно используется в многопоточности программирования. В большинстве случаев вместо volatile следует использовать более безопасные и надежные альтернативы. Современная платформа .NET обеспечивает лучшие средства параллелизма, такие как Interlocked класс, lock оператор или примитивы синхронизации более высокого уровня. Эти альтернативные варианты обеспечивают более четкую семантику и более надежные гарантии, чем volatile. Рассмотрите возможность использования volatile только в редких сложных сценариях, где вы полностью понимаете его ограничения и проверили, что это подходящее решение.
Замечание
В многопроцессорной системе переменная операция чтения не гарантирует получение последнего значения, записанного в это расположение памяти любым процессором. Аналогичным образом переменная операция записи не гарантирует, что записанное значение будет немедленно видно другим процессорам.
Ключевое volatile слово можно применить к полям следующих типов:
- Ссылочные типы.
- Типы указателей (в небезопасном контексте). Обратите внимание, что хотя сам указатель может быть переменным, объект, на который он указывает, не может. Другими словами, нельзя объявить "указатель на переменную".
- Простые типы, такие как
sbyte,byte,short,ushort,int,uint,char,floatиbool. - Тип
enumс одним из следующих базовых типов:byte,sbyte,short, ,ushortintилиuint. - Параметры универсального типа, известные как ссылочные типы.
- IntPtr и UIntPtr.
Другие типы, включая double и long, не могут быть помечены volatile , так как операции чтения и записи в поля этих типов не могут быть атомарными. Чтобы обеспечить многопоточную защиту доступа к этим типам полей, используйте Interlocked члены класса или защитите доступ с помощью оператора lock.
Для большинства многопоточных сценариев, даже с поддерживаемыми типами, предпочитайте использовать Interlocked операции, lock операторы или другие примитивы синхронизации вместо volatile. Эти альтернативные варианты менее подвержены тонким ошибкам параллелизма.
Ключевое volatile слово может применяться только к полям class или struct. Локальные переменные нельзя объявить volatile.
Альтернативы ключевому слову volatile
В большинстве случаев следует использовать одну из этих безопасных альтернатив вместо volatileследующих:
-
Interlocked операции: предоставление атомарных операций для числовых типов и ссылочных назначений. Как правило, они быстрее и обеспечивают более надежные гарантии, чем
volatile. -
lockоператор: обеспечивает взаимное исключение и барьеры памяти. Используйте для защиты более крупных критических разделов. -
Volatile класс: предоставляет явные переменные операции чтения и записи с более четкой семантикой, чем ключевое
volatileслово. - Примитивы синхронизации более высокого уровня: например ReaderWriterLockSlim, Semaphoreили параллельные коллекции из System.Collections.Concurrent.
Ключевое 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#.