volátil (Referência C#)
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 como visto em todos os threads de execução. Para obter mais informações, consulte a Volatile classe.
Nota
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 (em um 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, você não pode declarar um "ponteiro para volátil".
- Tipos simples como
sbyte
, , ,short
,ushort
,int
uint
,char
,float
, ebool
byte
. - Um
enum
tipo 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 Interlocked acesso usando a lock
instrução.
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
.
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#.