Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
A volatile palavra-chave indica que um campo pode ser modificado por vários threads que estão sendo executados ao mesmo tempo. O compilador, o sistema de tempo de execução e até mesmo o hardware podem reorganizar leituras e gravações em locais de memória por motivos de desempenho. Os campos declarados volatile são excluídos de certos tipos de otimizações. Não há garantia de uma única ordenação total de gravações voláteis conforme observado a partir de todos os threads de execução. Para obter mais informações, consulte a classe Volatile.
Atenção
A volatile palavra-chave é muitas vezes mal compreendida e mal utilizada na programação multithreaded. Na maioria dos cenários, você deve usar 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 primitivas de sincronização de nível superior. Estas alternativas fornecem semânticas mais claras e garantias mais fortes do que volatile. Considere usar volatile apenas em cenários raros e avançados, onde você entende totalmente suas limitações e verificou que é a solução apropriada.
Observação
Em um sistema multiprocessador, uma operação de leitura volátil não garante a obtenção do 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 volatile palavra-chave pode ser aplicada a campos destes tipos:
- Tipos de referência.
- Tipos de ponteiro (num contexto inseguro). Observe que, embora o ponteiro em si possa ser volátil, o objeto para o qual ele aponta não pode. Em outras palavras, não podes declarar um "ponteiro para volátil".
- Tipos simples como
sbyte,byte,short,ushort,int,uint,char,floatebool. - Um
enumtipo com um dos seguintes tipos básicos:byte,sbyte,short,ushort,int, ouuint. - Parâmetros de tipo genéricos conhecidos por serem tipos de referência.
- IntPtr e UIntPtr.
Outros tipos, incluindo double e long, não podem ser marcados volatile porque não é possível garantir que as leituras e gravações em campos desses tipos sejam atómicas. Para proteger o acesso multi-threaded a esses tipos de campos, use os membros da classe ou proteja o acesso multi-threaded usando a Interlocked declaração.
Para a maioria dos cenários multithreaded, mesmo com tipos suportados, prefira usar Interlocked operações, lock instruções ou outras primitivas de sincronização em vez de volatile. Essas alternativas são menos propensas a bugs sutis de concorrência.
A volatile palavra-chave só pode ser aplicada a campos de a class ou struct. As variáveis locais não podem ser declaradas volatile.
Alternativas à volatilidade
Na maioria dos casos, você deve usar uma dessas alternativas mais seguras em vez de volatile:
-
Interlocked operações: Fornecer operações atômicas para tipos numéricos e atribuições de referência. Estes são geralmente mais rápidos e fornecem garantias mais fortes do que
volatile. -
lockdeclaração: Garante exclusão mútua e barreiras de memória. Use para proteger seções críticas maiores. -
Volatile class: Fornece operações explícitas de leitura e gravação voláteis com semântica mais clara do que a
volatilepalavra-chave. - Primitivas de sincronização de nível superior: como ReaderWriterLockSlim, Semaphoreou coleções simultâneas de System.Collections.Concurrent.
A palavra-chave volatile não garante atomicidade para operações além da atribuição, não impede condições de competição e não assegura garantias de ordem para outras operações de memória. Essas limitações o tornam inadequado para a maioria dos cenários de simultaneidade.
Exemplo
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 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.
}
Com o volatile modificador adicionado à declaração de _shouldStop no lugar, você sempre obterá 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 do membro, resultando na leitura de dados obsoletos. Devido à natureza da programação multi-threaded, o número de leituras obsoletas é imprevisível. Diferentes execuções do programa produzirão resultados um pouco diferentes.
Especificação da linguagem C#
Para obter mais informações, consulte a Especificação da Linguagem C# . A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.