Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Utilisez le volatile mot clé pour indiquer qu’un champ peut être modifié par plusieurs threads qui s’exécutent en même temps. Pour des raisons de performances, le compilateur, le système d’exécution et même le matériel peuvent réorganiser les lectures et les écritures dans les emplacements de mémoire. La déclaration d’un champ comme volatile l’exclut de certains types d’optimisations. Il n’existe aucune garantie d’un ordre total unique d’écritures volatiles, comme indiqué à partir de tous les threads d’exécution. Pour plus d'informations, consultez la classe Volatile.
Avertissement
Le mot clé volatile est souvent incompris et mal utilisé dans la programmation multithread. Dans la plupart des scénarios, utilisez des alternatives plus sûres et plus fiables au lieu de volatile. Le .NET moderne fournit de meilleurs outils d’accès concurrentiel comme la Interlocked classe, l’instruction lock ou les primitives de synchronisation de niveau supérieur. Ces alternatives offrent une sémantique plus claire et des garanties plus fortes que volatile. Envisagez d’utiliser volatile uniquement dans des scénarios rares et avancés où vous comprenez pleinement ses limitations et que vous avez vérifié qu’il s’agit de la solution appropriée.
Remarque
Sur un système multiprocesseur, une opération de lecture volatile ne garantit pas d’obtenir la dernière valeur écrite à cet emplacement de mémoire par n’importe quel processeur. De même, une opération d’écriture volatile ne garantit pas que la valeur écrite est immédiatement visible par d’autres processeurs.
La documentation de référence du langage C# décrit la version la plus récente du langage C#. Il contient également la documentation initiale des fonctionnalités dans les préversions publiques pour la prochaine version du langage.
La documentation identifie toute fonctionnalité introduite en premier dans les trois dernières versions de la langue ou dans les préversions publiques actuelles.
Conseil / Astuce
Pour savoir quand une fonctionnalité a été introduite en C#, consultez l’article sur l’historique des versions du langage C#.
Appliquez le volatile mot clé aux champs de ces types :
- Types de référence.
- Types de pointeurs (dans un contexte non sécurisé). Bien que le pointeur lui-même puisse être volatile, l’objet auquel il pointe ne peut pas être. En d’autres termes, vous ne pouvez pas déclarer de « pointeur vers volatile ».
- Types simples tels que
sbyte,byteshortushort,intuintcharfloatet .bool - Type
enumavec l’un des types de base suivants :byte, ,sbyteshort,ushort,int, ouuint. - Paramètres de type générique connus pour être des types de référence.
- IntPtr et UIntPtr.
Vous ne pouvez pas marquer d’autres types, y compris double et long, comme étant donné que volatile les lectures et les écritures dans les champs de ces types ne peuvent pas être garanties comme atomiques. Pour protéger l’accès multithread à ces types de champs, utilisez les Interlocked membres de la classe ou protégez l’accès à l’aide de l’instruction lock .
Pour la plupart des scénarios multithreads, même avec des types pris en charge, préférez utiliser les opérations Interlocked, les instructions lock ou d’autres primitives de synchronisation au lieu de volatile. Ces alternatives sont moins sujettes à des bogues de concurrence subtils.
Vous ne pouvez appliquer le volatile mot clé qu’aux champs d’un class ou struct. Vous ne pouvez pas déclarer de variables locales en tant que volatile.
Alternatives à volatile
Dans la plupart des cas, utilisez l’une de ces alternatives plus sûres au lieu de volatile:
-
Interlocked opérations : fournissez des opérations atomiques pour les types numériques et les affectations de référence. Ces opérations sont généralement plus rapides et offrent des garanties plus fortes que
volatile. -
lockstatement : fournit des barrières mutuelles d’exclusion et de mémoire. Utilisez-la pour protéger des sections critiques plus grandes. -
Volatile classe : fournit des opérations de lecture et d’écriture volatiles explicites avec une sémantique plus claire que le
volatilemot clé. - Primitives de synchronisation de niveau supérieur : telles que ReaderWriterLockSlim, Semaphoreou collections simultanées à partir de System.Collections.Concurrent.
Le volatile mot clé ne fournit pas d’atomicité pour les opérations autres que l’affectation. Elle n’empêche pas les conditions de concurrence et ne fournit pas de garanties de classement pour d’autres opérations de mémoire. Ces limitations ne conviennent pas à la plupart des scénarios d’accès concurrentiel.
L’exemple suivant montre comment déclarer une variable de champ public en tant que volatile.
class VolatileTest
{
public volatile int sharedStorage;
public void Test(int i)
{
sharedStorage = i;
}
}
L’exemple suivant montre comment un thread auxiliaire ou worker peut être créé et utilisé pour effectuer le traitement en parallèle avec celui du thread principal. Pour plus d’informations sur la multithreading, consultez 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.
}
Lorsque vous ajoutez le volatile modificateur à la déclaration de _shouldStop, vous obtenez toujours les mêmes résultats (similaires à l’extrait affiché dans le code précédent). Toutefois, sans ce modificateur sur le _shouldStop membre, le comportement est imprévisible. La DoWork méthode peut optimiser l’accès aux membres, ce qui entraîne la lecture des données obsolètes. En raison de la nature de la programmation multithread, le nombre de lectures obsolètes est imprévisible. Différentes exécutions du programme produisent des résultats légèrement différents.
Spécification du langage C#
Pour plus d'informations, voir la spécification du langage C#. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.