Sdílet prostřednictvím


volatile (Referenční dokumentace jazyka C#)

volatile Klíčové slovo použijte k označení, že pole může být změněno více vlákny, která se spouští současně. Z důvodů výkonu může kompilátor, systém runtime a dokonce i hardware změnit uspořádání čtení a zápisů do umístění paměti. Deklarování pole, které volatile je vyloučeno z určitých druhů optimalizací. Neexistuje žádná záruka jednoho celkového pořadí nestálých zápisů, jak je vidět ze všech vláken provádění. Další informace najdete ve třídě Volatile.

Upozornění

Klíčové volatile slovo je často špatně pochopeno a zneužito při vícevláknovém programování. Ve většině scénářů používejte bezpečnější a spolehlivější alternativy místo volatile. Moderní .NET poskytuje lepší nástroje souběžnosti, jako je Interlocked třída, lock příkaz nebo primitiva synchronizace vyšší úrovně. Tyto alternativy poskytují jasnější sémantiku a silnější záruky než volatile. Zvažte použití volatile pouze ve výjimečných pokročilých scénářích, ve kterých plně rozumíte jeho omezením a ověřili jste, že se jedná o vhodné řešení.

Poznámka:

V multiprocesorovém systému neručí operace nestálého čtení za účelem získání nejnovější hodnoty zapsané do umístění v paměti jakýmkoli procesorem. Podobně nestálá operace zápisu nezaručuje, že hodnota zapsaná je okamžitě viditelná pro ostatní procesory.

Referenční dokumentace jazyka C# dokumentuje naposledy vydané verze jazyka C#. Obsahuje také počáteční dokumentaci k funkcím ve verzi Public Preview pro nadcházející jazykovou verzi.

Dokumentace identifikuje všechny funkce, které byly poprvé představeny v posledních třech verzích jazyka nebo v aktuálních verzích Public Preview.

Návod

Informace o tom, kdy byla funkce poprvé představena v jazyce C#, najdete v článku o historii verzí jazyka C#.

Použití klíčového volatile slova u polí těchto typů:

  • Odkazové typy.
  • Typy ukazatelů (v nebezpečném kontextu). I když samotný ukazatel může být nestálý, objekt, na který odkazuje, nemůže být. Jinými slovy, nemůžete deklarovat "ukazatel na těkavý".
  • Jednoduché typy jako sbyte, , byte, short, ushortintuintchar, float, a .bool
  • Typ enum s jedním z následujících základních typů: byte, sbyte, shortushort, , int, nebo uint.
  • Parametry obecného typu známé jako odkazové typy.
  • IntPtr a UIntPtr.

Nemůžete označit jiné typy, včetně double a long, protože volatile čtení a zápisy do polí těchto typů nemůže být zaručeno atomické. Pokud chcete chránit vícevláknový přístup k těmto typům polí, použijte Interlocked členy třídy nebo pomocí příkazu lock chraňte přístup.

U většiny scénářů s více vlákny, i s podporovanými typy, preferujte použití Interlocked operací, lock příkazů nebo jiných primitiv synchronizace místo volatile. Tyto alternativy jsou méně náchylné k drobným chybám souběžnosti.

Klíčové slovo můžete použít volatile pouze u polí nebo classstruct. Nemůžete deklarovat místní proměnné jako volatile.

Alternativy k nestálé

Ve většině případů použijte jednu z těchto bezpečnějších alternativ místo volatile:

  • Interlocked operace: Poskytují atomické operace pro číselné typy a přiřazování odkazů. Tyto operace jsou obecně rychlejší a poskytují silnější záruky než volatile.
  • lock příkaz: Poskytuje vzájemné vyloučení a paměťové bariéry. Použijte ho k ochraně větších důležitých oddílů.
  • Volatile třída: Poskytuje explicitní operace čtení a zápisu pro volatile s jasnější sémantikou než volatile klíčové slovo.
  • Primitivy synchronizace vyšší úrovně: například ReaderWriterLockSlim, Semaphorenebo souběžné kolekce z System.Collections.Concurrent.

Klíčové volatile slovo neposkytuje atomicitu pro operace jiné než přiřazení. Nezabrání podmínkám časování a neposkytuje záruky řazení pro jiné operace s pamětí. Díky těmto omezením není vhodná pro většinu scénářů souběžnosti.

Následující příklad ukazuje, jak deklarovat proměnnou veřejného pole jako volatile.

class VolatileTest
{
    public volatile int sharedStorage;

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

Následující příklad ukazuje, jak lze vytvořit pomocné nebo pracovní vlákno a použít k provádění zpracování paralelně s primárním vláknem. Další informace o multithreadingu naleznete v tématu Spravované vlákno.

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

Když přidáte volatile modifikátor do deklarace _shouldStop, vždy získáte stejné výsledky (podobně jako výňatek zobrazený v předchozím kódu). Bez tohoto modifikátoru u člena _shouldStop je však chování nepředvídatelné. Metoda DoWork může optimalizovat přístup členů, což vede ke čtení zastaralých dat. Vzhledem k povaze vícevláknového programování je počet zastaralých čtení nepředvídatelný. Různé běhy programu vytvářejí poněkud odlišné výsledky.

Specifikace jazyka C#

Další informace najdete ve specifikaci jazyka C#. Specifikace jazyka je konečným zdrojem syntaxe a použití jazyka C#.

Viz také