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.
Use a volatile palavra-chave para indicar que um campo pode ser modificado por múltiplas threads que estão a executar ao mesmo tempo. Por razões de desempenho, o compilador, o sistema de execução e até o hardware podem reorganizar leituras e escritas para locais de memória. Declarar um campo como volatile exclui-lo de certos tipos de otimizações. Não há garantia de uma única ordem total de escritas voláteis, como se vê em 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, use alternativas mais seguras e fiá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
Num sistema multiprocessador, uma operação de leitura volátil não garante obter o valor mais recente escrito nessa localização de memória por qualquer processador. De forma semelhante, uma operação de escrita volátil não garante que o valor escrito seja imediatamente visível para outros processadores.
A referência da linguagem C# documenta a versão mais recentemente lançada da linguagem C#. Contém também documentação inicial para funcionalidades em versões preliminares públicas para a próxima versão da linguagem.
A documentação identifica qualquer funcionalidade introduzida pela primeira vez nas últimas três versões da língua ou em pré-visualizações públicas atuais.
Sugestão
Para saber quando uma funcionalidade foi introduzida pela primeira vez em C#, consulte o artigo sobre o histórico de versões da linguagem C#.
Aplique a volatile palavra-chave a campos destes tipos:
- Tipos de referência.
- Tipos de ponteiro (num contexto inseguro). Embora o próprio ponteiro possa ser volátil, o objeto para o qual aponta não pode ser. Ou seja, não se pode declarar um "indicador de 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.
Não podes marcar outros tipos, incluindo double e long, porque volatile as leituras e escritas em campos desses tipos não podem ser garantidas como atómicas. Para proteger o acesso multithread a esses tipos de campos, use os Interlocked membros da classe ou proteja o acesso usando a lock instruçã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.
Só pode aplicar a volatile palavra-chave aos campos de a class ou struct. Não podes declarar variáveis locais como volatile.
Alternativas à volatilidade
Na maioria dos casos, utilize uma destas 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. Estas operações são geralmente mais rápidas e oferecem garantias mais fortes do que
volatile. -
lockdeclaração: Garante exclusão mútua e barreiras de memória. Use-o para proteger secçõ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 volatile palavra-chave não fornece atomicidade para operações para além da atribuição. Não previne condições de corrida, nem garante 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 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.
}
Quando adiciona o volatile modificador à declaração de _shouldStop, obtém sempre os mesmos resultados (semelhantes ao excerto 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 dos membros, resultando na leitura de dados obsoletos. Devido à natureza da programação multithread, o número de leituras obsoletas é imprevisível. Diferentes sequências do programa produzem resultados algo distintos.
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#.