Delen via


volatile (C#-referentie)

Gebruik het volatile trefwoord om aan te geven dat een veld kan worden gewijzigd door meerdere threads die tegelijkertijd worden uitgevoerd. Om prestatieredenen kunnen de compiler, het runtimesysteem en zelfs de hardware lees- en schrijfbewerkingen naar geheugenlocaties opnieuw rangschikken. Het declareren van een veld zoals volatile uitgesloten van bepaalde soorten optimalisaties. Er is geen garantie voor één totale volgorde van vluchtige schrijfbewerkingen, zoals te zien is vanuit alle threads van uitvoering. Zie de Volatile klas voor meer informatie.

Waarschuwing

Het volatile trefwoord wordt vaak verkeerd begrepen en misbruikt in multithreaded programmeren. Gebruik in de meeste scenario's veiligere en betrouwbaardere alternatieven in plaats van volatile. Moderne .NET biedt betere hulpmiddelen voor gelijktijdigheid zoals de Interlocked klasse, de lock instructie of hoger niveau synchronisatieprimitieven. Deze alternatieven bieden duidelijkere semantiek en sterkere garanties dan volatile. Overweeg om alleen in zeldzame, geavanceerde scenario's te gebruiken volatile waarin u de beperkingen volledig begrijpt en hebt gecontroleerd of dit de juiste oplossing is.

Opmerking

Op een multiprocessorsysteem garandeert een vluchtige leesbewerking niet dat de meest recente waarde wordt opgehaald die door een processor naar die geheugenlocatie wordt geschreven. Op dezelfde manier garandeert een vluchtige schrijfbewerking niet dat de geschreven waarde direct zichtbaar is voor andere processors.

De C#-taalreferentiedocumenten beschrijven de meest recent uitgebrachte versie van de C#-taal. Het bevat ook de eerste documentatie voor functies in openbare previews voor de aanstaande taalrelease.

De documentatie identificeert alle functies die voor het eerst zijn geïntroduceerd in de laatste drie versies van de taal of in de huidige openbare previews.

Aanbeveling

Raadpleeg het artikel over de versiegeschiedenis van de C#-taal om te achterhalen wanneer een functie voor het eerst is geïntroduceerd in C#.

Pas het volatile trefwoord toe op velden van deze typen:

  • Referentietypen.
  • Aanwijzertypen (in een onveilige context). Hoewel de aanwijzer zelf vluchtig kan zijn, kan het object waarnaar wordt verwezen, niet zijn. Met andere woorden, u kunt geen 'aanwijzer naar vluchtig' declareren.
  • Eenvoudige typen zoals sbyte, , byteshort, , ushort, int, , uint, , char, , , en float.bool
  • Een enum type met een van de volgende basistypen: byte, sbyte, short, ushort, , , of intuint.
  • Algemene typeparameters die als verwijzingstypen bekend zijn.
  • IntPtr en UIntPtr.

U kunt geen andere typen markeren, waaronder double en long, omdat volatile lees- en schrijfbewerkingen naar velden van deze typen niet kunnen worden gegarandeerd atomisch. Als u multithreaded toegang tot deze typen velden wilt beveiligen, gebruikt u de Interlocked klasseleden of beveiligt u de toegang met behulp van de lock instructie.

Voor de meeste multithreading-scenario's, zelfs met ondersteunde typen, gebruikt u bij voorkeur Interlocked bewerkingen, lock instructies of andere synchronisatieprimitieven in plaats van volatile. Deze alternatieven zijn minder gevoelig voor subtiele gelijktijdigheidsfouten.

U kunt het volatile trefwoord alleen toepassen op velden van een class of struct. U kunt lokale variabelen niet declareren als volatile.

Alternatieven voor vluchtig

Gebruik in de meeste gevallen een van deze veiligere alternatieven in plaats van volatile:

  • Interlocked bewerkingen: Geef atomische bewerkingen op voor numerieke typen en verwijzingstoewijzingen. Deze bewerkingen zijn over het algemeen sneller en bieden sterkere garanties dan volatile.
  • lock verklaring: Biedt wederzijdse uitsluiting en geheugenbarrières. Gebruik deze voor het beveiligen van grotere kritieke secties.
  • Volatile klasse: Biedt expliciete vluchtige lees- en schrijfbewerkingen met duidelijkere semantiek dan het volatile trefwoord.
  • Synchronisatieprimitief op hoger niveau: zoals ReaderWriterLockSlim, Semaphoreof gelijktijdige verzamelingen van System.Collections.Concurrent.

Het volatile trefwoord biedt geen atomiciteit voor andere bewerkingen dan toewijzing. Het voorkomt geen racevoorwaarden en biedt geen bestelgaranties voor andere geheugenbewerkingen. Deze beperkingen maken het ongeschikt voor de meeste gelijktijdigheidsscenario's.

In het volgende voorbeeld ziet u hoe u een variabele voor een openbaar veld declareert als volatile.

class VolatileTest
{
    public volatile int sharedStorage;

    public void Test(int i)
    {
        sharedStorage = i;
    }
}

In het volgende voorbeeld ziet u hoe een hulp- of werkthread kan worden gemaakt en gebruikt om de verwerking parallel met die van de primaire thread uit te voeren. Zie Managed Threading voor meer informatie over multithreading.

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.
}

Wanneer u de volatile wijzigingsfunctie toevoegt aan de declaratie van _shouldStop, krijgt u altijd dezelfde resultaten (vergelijkbaar met het fragment dat in de voorgaande code wordt weergegeven). Zonder die wijzigingsfunctie op het _shouldStop lid is het gedrag echter onvoorspelbaar. De DoWork methode kan de toegang tot leden optimaliseren, wat resulteert in het lezen van verouderde gegevens. Vanwege de aard van multithreaded programmeren is het aantal verlopen leesbewerkingen onvoorspelbaar. Verschillende uitvoeringen van het programma produceren enigszins verschillende resultaten.

C#-taalspecificatie

Zie de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.

Zie ook