Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Usare la volatile parola chiave per indicare che un campo può essere modificato da più thread in esecuzione contemporaneamente. Per motivi di prestazioni, il compilatore, il sistema di runtime e persino l'hardware potrebbero riorganizzare le letture e le scritture in posizioni di memoria. La dichiarazione di un campo come volatile la esclude da determinati tipi di ottimizzazioni. Non esiste alcuna garanzia di un singolo ordinamento totale di scritture volatili, come illustrato da tutti i thread di esecuzione. Per altre informazioni, vedere la classe Volatile.
Attenzione
La volatile parola chiave è spesso fraintesa e usata impropriamente nella programmazione multithreaded. Nella maggior parte degli scenari, usare alternative più sicure e affidabili anziché volatile. .NET moderno offre strumenti di concorrenza migliori, ad esempio la Interlocked classe, l'istruzione lock o le primitive di sincronizzazione di livello superiore. Queste alternative offrono una semantica più chiara e garanzie più efficaci rispetto a volatile. Prendere in considerazione l'uso volatile solo in scenari rari e avanzati in cui si conoscono appieno le limitazioni e si è verificato che sia la soluzione appropriata.
Annotazioni
In un sistema multiprocessore, un'operazione di lettura volatile non garantisce di ottenere il valore più recente scritto in tale posizione di memoria da qualsiasi processore. Analogamente, un'operazione di scrittura volatile non garantisce che il valore scritto sia immediatamente visibile ad altri processori.
Il riferimento al linguaggio C# documenta la versione rilasciata più di recente del linguaggio C#. Contiene anche la documentazione iniziale per le funzionalità nelle versioni di anteprima pubblica per la prossima versione del linguaggio di programmazione.
La documentazione identifica tutte le funzionalità introdotte nelle ultime tre versioni della lingua o nelle anteprime pubbliche correnti.
Suggerimento
Per trovare quando una funzionalità è stata introdotta per la prima volta in C#, vedere l'articolo sulla cronologia delle versioni del linguaggio C#.
Applicare la volatile parola chiave ai campi di questi tipi:
- Tipi di riferimento.
- Tipi di puntatore (in un contesto non sicuro). Anche se il puntatore stesso può essere volatile, l'oggetto a cui punta non può essere. In altre parole, non è possibile dichiarare un "puntatore a volatile".
- Tipi semplici, come
sbyte,byte,short,ushort,int,uint,char,floatebool. - Tipo
enumcon uno dei tipi di base seguenti:byte,sbyte,short,ushortint, ouint. - Parametri di tipo generico noti come tipi di riferimento.
- IntPtr e UIntPtr.
Non è possibile contrassegnare altri tipi, tra cui double e long, perché volatile le operazioni di lettura e scrittura nei campi di tali tipi non possono essere garantite come atomiche. Per proteggere l'accesso multithreading a tali tipi di campi, usare i membri della Interlocked classe o proteggere l'accesso usando l'istruzione lock .
Per la maggior parte degli scenari multithreading, anche con tipi supportati, preferire l'uso di Interlocked operazioni, lock istruzioni o altre primitive di volatile sincronizzazione anziché. Queste alternative sono meno soggette a bug di concorrenza sottili.
È possibile applicare la volatile parola chiave solo ai campi di un class oggetto o struct. Non è possibile dichiarare variabili locali come volatile.
Alternative a volatile
Nella maggior parte dei casi, usare una di queste alternative più sicure anziché volatile:
-
Interlocked operazioni: fornire operazioni atomiche per tipi numerici e assegnazioni di riferimento. Queste operazioni sono in genere più veloci e offrono garanzie più efficaci rispetto a
volatile. -
lockistruzione: Fornisce l'esclusione reciproca e le barriere di memoria. Usarlo per proteggere sezioni critiche più grandi. -
Volatile classe: fornisce operazioni di lettura e scrittura volatili esplicite con semantica più chiara rispetto alla
volatileparola chiave . - Primitive di sincronizzazione di livello superiore: ad ReaderWriterLockSlimesempio , Semaphoreo raccolte simultanee da System.Collections.Concurrent.
La volatile parola chiave non fornisce atomicità per le operazioni diverse dall'assegnazione. Non impedisce le race condition e non fornisce garanzie di ordinamento per altre operazioni di memoria. Queste limitazioni lo rendono non adatto per la maggior parte degli scenari di concorrenza.
Nell'esempio seguente viene illustrato come dichiarare una variabile di campo pubblico come volatile.
class VolatileTest
{
public volatile int sharedStorage;
public void Test(int i)
{
sharedStorage = i;
}
}
Nell'esempio seguente viene illustrato come creare e usare un thread ausiliario o di lavoro per eseguire l'elaborazione in parallelo con quella del thread primario. Per ulteriori informazioni sul multithreading, vedere Threading gestito da .NET.
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 si aggiunge il volatile modificatore alla dichiarazione di _shouldStop, si ottengono sempre gli stessi risultati (analogamente all'estratto illustrato nel codice precedente). Tuttavia, senza tale modificatore sul _shouldStop membro, il comportamento è imprevedibile. Il DoWork metodo potrebbe ottimizzare l'accesso ai membri, generando la lettura di dati non aggiornati. A causa della natura della programmazione multithreading, il numero di letture non aggiornati è imprevedibile. Diverse esecuzioni del programma producono risultati leggermente diversi.
Specificazione del linguaggio C#
Per altre informazioni, vedere la specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.