volatile (C#-Referenz)

Das Schlüsselwort volatile gibt an, dass ein Feld von mehreren Threads geändert werden kann, die zur gleichen Zeit ausgeführt werden. Der Compiler, das Runtimesystem und sogar die Hardware können aus Leistungsgründen die Lese- und Schreibvorgänge in den Speicherorten neu anordnen. Felder, die als volatile deklariert sind, sind von bestimmten Optimierungsarten ausgeschlossen. Es gibt keine Garantie für eine einzelne Gesamtsortierung von volatile-Schreibvorgängen aus der Sicht aller ausgeführten Threads. Weitere Informationen finden Sie in den Ausführungen zur Volatile-Klasse.

Hinweis

In einem Multiprozessorsystem garantiert ein flüchtiger Lesevorgang nicht, dass der neueste von einem Prozessor in diesen Speicherort geschriebene Wert erhalten wird. Ebenso garantiert ein flüchtiger Schreibvorgang nicht, dass der geschriebene Wert für andere Prozessoren sofort sichtbar ist.

Das Schlüsselwort volatile kann auf Felder der folgenden Typen angewendet werden:

  • Verweistypen.
  • Zeigertypen (in unsicherem Kontext). Beachten Sie, dass der Zeiger selbst als „volatile“ deklariert sein kann, das Objekt, auf das er zeigt aber nicht. Anders ausgedrückt können Sie keinen „Zeiger auf ‚volatile‘“ deklarieren.
  • Einfacher Typen wie sbyte, byte, short, ushort, int, uint, char, float und bool.
  • Ein enum-Typ mit einem der folgenden Basistypen: byte, sbyte, short, ushort, int oder uint.
  • Generische Typparameter, die als Verweistypen bekannt sind.
  • IntPtr und UIntPtr.

Andere Typen, einschließlich double und long, können nicht mit volatile markiert werden, da Lese- und Schreibvorgänge in die Felder dieser Typen nicht unbedingt atomar sind. Um den Multithreadzugriff auf diese Feldtypen zu schützen, verwenden Sie die Klassenmitglieder Interlocked oder schützen Sie den Zugriff mit der Anweisung lock.

Das Schlüsselwort volatile kann nur auf Felder einer class oder struct angewendet werden. Lokale Variablen können nicht als volatile deklariert werden.

Beispiel

Im folgenden Beispiel wird die Deklaration einer öffentlichen Feldvariable als volatile dargestellt.

class VolatileTest
{
    public volatile int sharedStorage;

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

Im folgenden Beispiel wird veranschaulicht, wie ein Hilfs- oder Arbeitsthread erstellt wird und für das Ausführen der Verarbeitung parallel mit dem primären Thread verwendet werden kann. Weitere Informationen zum Multithreading finden Sie unter Verwaltetes 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.
}

Wenn der volatile-Modifizierer der Deklaration von _shouldStop hinzugefügt wird, erhalten Sie immer die gleichen Ergebnisse (ähnlich dem Auszug aus dem vorhergehenden Code). Ohne diesen Modifizierer für das _shouldStop-Mitglied ist das Verhalten unvorhersehbar. Die DoWork-Methode kann den Mitgliederzugriff optimieren, was zum Lesen veralteter Daten führt. Aufgrund der Natur der Multithreadprogrammierung ist die Anzahl der veraltete Lesevorgänge unvorhersehbar. Verschiedene Programmläufe führen zu etwas unterschiedlichen Ergebnissen.

C#-Sprachspezifikation

Weitere Informationen erhalten Sie unter C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.

Siehe auch