Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Use a volatile palavra-chave para indicar que um campo pode ser modificado por vários threads que estão sendo executados ao mesmo tempo. Por motivos de desempenho, o compilador, o sistema de runtime e até mesmo o hardware podem reorganizar leituras e gravações em locais de memória. Declarar um campo como volatile o exclui de determinados tipos de otimizações. Não há garantia de uma única ordenação total de gravações voláteis, como visto em todos os threads de execução. Para obter mais informações, consulte a classe Volatile.
Cuidado
A volatile palavra-chave geralmente é mal compreendida e mal utilizada na programação multithreaded. Na maioria dos cenários, use alternativas mais seguras e confiáveis em vez de volatile. O .NET moderno fornece melhores ferramentas de simultaneidade, como a Interlocked classe, a lock instrução ou os primitivos de sincronização de nível superior. Essas alternativas fornecem semântica mais clara e garantias mais fortes do que volatile. Considere usar volatile apenas em cenários avançados raros em que você entenda completamente suas limitações e tenha verificado que é a solução apropriada.
Observação
Em um sistema multiprocessador, uma operação de leitura volátil não garante obter o valor mais recente gravado nesse local de memória por qualquer processador. Da mesma forma, uma operação de gravação volátil não garante que o valor gravado seja imediatamente visível para outros processadores.
A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento do idioma.
A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.
Dica
Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.
Aplique a volatile palavra-chave a campos destes tipos:
- Tipos de referência.
- Tipos de ponteiro (em um contexto não seguro). Embora o ponteiro em si possa ser volátil, o objeto ao qual ele aponta não pode ser. Em outras palavras, você não pode declarar um "ponteiro para volátil".
- Tipos simples, como
sbyte,byte,short,ushort,int, ,uint,char, ,floatebool. - Um
enumtipo com um dos seguintes tipos base:byte, ,sbyte,short,ushort, ,intouuint. - Parâmetros de tipo genérico conhecidos como tipos de referência.
- IntPtr e UIntPtr.
Você não pode marcar outros tipos, incluindo double e long, como volatile porque leituras e gravações em campos desses tipos não podem ser garantidos como atômicos. Para proteger o acesso multithread a esses tipos de campos, use os membros da classe ou proteja o Interlocked acesso usando a lock instrução.
Para a maioria dos cenários multithread, mesmo com tipos suportados, prefira usar operações Interlocked, instruções lock ou outros primitivos de sincronização em vez de volatile. Essas alternativas são menos propensas a bugs sutis de concorrência.
Você só pode aplicar a volatile palavra-chave a campos de um class ou struct. Você não pode declarar variáveis locais como volatile.
Alternativas a voláteis
Na maioria dos casos, use uma destas alternativas mais seguras em vez de volatile:
-
Interlocked operações: forneça operações atômicas para tipos numéricos e atribuições de referência. Essas operações geralmente são mais rápidas e fornecem garantias mais fortes do que
volatile. -
lockinstrução: Fornece exclusão mútua e barreiras de memória. Use-o para proteger seções críticas maiores. -
Volatile classe: fornece operações de leitura e gravação voláteis explícitas com semântica mais clara do que a
volatilepalavra-chave. - Primitivos de sincronização de nível superior: como ReaderWriterLockSlim, Semaphoreou coleções simultâneas de System.Collections.Concurrent.
A volatile palavra-chave não fornece atomicidade para operações que não sejam atribuição. Ele não impede condições de corrida e não fornece garantias de ordenação para outras operações de memória. Essas limitações o tornam inadequado para a maioria dos cenários de simultaneidade.
O exemplo a seguir mostra como declarar uma variável de campo público como volatile.
class VolatileTest
{
public volatile int sharedStorage;
public void Test(int i)
{
sharedStorage = i;
}
}
O exemplo a seguir demonstra como um thread auxiliar ou de trabalho pode ser criado e usado para executar o processamento em paralelo com o do thread primário. Para obter mais informações sobre multithreading, consulte 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.
}
Ao adicionar o volatile modificador à declaração de _shouldStop, você sempre obtém os mesmos resultados (semelhante ao trecho mostrado no código anterior). No entanto, sem esse modificador no _shouldStop membro, o comportamento é imprevisível. O DoWork método pode otimizar o acesso ao membro, resultando na leitura de dados obsoletos. Devido à natureza da programação multithreaded, o número de leituras obsoletas é imprevisível. Diferentes execuções do programa produzem resultados um pouco diferentes.
Especificação da linguagem C#
Para obter mais informações, consulte a Especificação da Linguagem C# . A especificação de idioma é a fonte definitiva para a sintaxe e o uso de C#.