Was ist der Unterschied zwischen einem statischen globalen und einem statischen flüchtigen Variable?

StackOverflow https://stackoverflow.com/questions/346306

Frage

Ich habe eine statische globale Variable und eine statische volatile Variable in Dateigültigkeitsbereich verwendet wird,

beide werden von einer ISR und einer Hauptschleife und Hauptschleife überprüft den Wert der Variablen aktualisiert.

hier bei der Optimierung weder die globalen Variable noch die flüchtigen Variable optimiert. Anstatt also eine flüchtige Variable verwendet eine globale Variable löst das Problem.

So ist es gut, globalen Variable zu verwenden, anstatt von flüchtigem?

Jeder besonderer Grund statische volatil zu verwenden ??

Jedes Beispiel Programm würde spürbar sein.

Vielen Dank im Voraus ..

War es hilfreich?

Lösung

Sie sind verschiedene Dinge. Ich bin kein Experte in volatiler Semantik. Aber ich denke, es macht Sinn, was hier beschrieben wird.

Globale

Globale bedeuten nur die Kennung in Frage zu Datei-Gültigkeitsbereich deklariert wird. Es gibt verschiedene Bereiche, genannt Funktion (wobei goto-Etiketten definiert sind), fi le (wobei globals befinden), Block (wo normale lokale Variablen befinden), und Funktionsprototyp (wo Funktionsparameter befinden). Dieses Konzept nur existieren, um die Sichtbarkeit von Identifikatoren zu strukturieren. Es hat nichts mit Optimierungen zu tun hat.

Static

static ist eine Speicherdauer (wir werden nicht zu dieser hier) und eine Möglichkeit, einen Namen in der Datei Umfang interne Bindung erklärt zu geben. Dies kann für Funktionen oder Objekte nur innerhalb einer Übersetzungseinheit erforderlich erfolgen. Ein typisches Beispiel wäre eine help Funktion sein, die akzeptierten Parameter auszudrucken, und die nur von der main Funktion definiert in der gleichen .c-Datei bezeichnet.

6.2.2 / 2 in einem C99-Entwurf:

  

Wenn die Deklaration eines fi le Umfang   Kennung für ein Objekt oder eine Funktion   enthält die Speicherklasse spezifischen ER   statisch, weist die interne Kennung   Verknüpfung.

Interne Verknüpfung bedeutet, dass die Kennung außerhalb der aktuellen Übersetzungseinheit nicht sichtbar ist (wie die help Funktion von oben).

Volatile

Flüchtige ist eine andere Sache: ( 6.7.3 / 6 )

  

Ein Objekt, das flüchtige-quali fi zierte hat   Typ kann in einer Weise modifiziert werden nicht bekannt   die Umsetzung oder andere   unbekannte Nebenwirkungen. daher ist jede   Expression unter Bezugnahme auf ein solches Objekt   ist streng bewertet werden gemäß   die Regeln der abstrakten Maschine,   wie in 5.1.2.3 beschrieben. Außerdem,   den Wert bei jedem Sequenzpunkt letzten   in dem Objekt gespeichert wird zustimmen   dass durch die abstrakten vorgeschrieben   Maschine, mit Ausnahme des Ande des ED   unbekannte Faktoren erwähnt   zuvor.

Die Norm stellt ein hervorragendes Beispiel für ein Beispiel, wo volatile überflüssig wäre ( 5.1.2.3/8 ):

  

Eine Implementierung könnte de fi nieren eines   Eins-zu-Eins-Entsprechung zwischen   abstrakt und tatsächliche Semantik: bei   jeder Sequenzpunkt, die Werte von   die tatsächlichen Objekte würden zustimmen   diejenigen spezi fi zierten von der abstrakten   Semantik. Das Schlüsselwort volatile   wäre dann überflüssig.

Sequence Punkte sind Punkte, bei denen die Wirkung von Nebenwirkungen in Bezug auf die abstrakte Maschine abgeschlossen sind (das heißt äußeren Bedingungen wie Speicherzellenwerte sind nicht enthalten). Zwischen dem rechten und der linken Seite von && und || nach ; und von einem Funktionsaufruf zurückkehrt sind Sequenzpunkte zum Beispiel.

Die abstrakte Semantik ist, was der Compiler nicht sieht nur die Folge von Codes innerhalb eines bestimmten Programms ableiten kann. Auswirkungen von Optimierungen sind hier irrelevant. tatsächliche Semantik enthält die Auswirkung von Nebenwirkungen erfolgt durch, um Objekte zu schreiben (zB Wechsel von Speicherzellen). ein Objekts als flüchtiges Qualifikations bedeutet ein immer den Wert eines Objektes wird direkt aus dem Speicher ( „wie durch die unbekannten Faktoren modifizierte“). Die Norm legt keine Fäden überall erwähnen, und wenn Sie in der Größenordnung von Änderungen oder auf der Unteilbarkeit der Operationen verlassen müssen, sollten Sie plattformabhängige Weise verwenden, um sicherzustellen.

Für einen einfachen Überblick zu verstehen, hat Intel einen großen Artikel über das hier .

Was soll ich jetzt tun?

Halten Sie Ihre Datei-Umfang (global) Daten als flüchtig erklärt. Globale Daten an sich nicht die Variablenwert bedeuten wird gleich dem Wert sim Speicher Tored. Und statisch nicht nur Ihre Objekte lokal auf die aktuelle Übersetzungseinheit (die aktuellen .c Dateien und alle anderen Dateien # include'ed durch sie) machen.

Andere Tipps

Lassen Sie mich zunächst erwähnen, dass eine statische globale Variable, das gleiche wie eine globale Variable ist, mit der Ausnahme, dass Sie die Variable auf den Umfang der Datei begrenzen. D. h Sie können diese globale Variable in anderen Dateien über das extern Schlüsselwort verwenden.

So können Sie Ihre Frage auf globale Variablen vs flüchtigen Variablen reduzieren.

Jetzt auf volatile:

Wie const, volatile ist ein Typ Modifikator.

Das volatile Schlüsselwort erstellt wurde Compiler-Optimierungen zu verhindern, dass Code falsch machen kann, insbesondere, wenn es asynchrone Ereignisse.

Objekte als volatile erklären möglicherweise nicht in bestimmten Optimierungen verwendet werden.

Das System liest immer den aktuellen wahren Wert eines flüchtigen Objekts an dem Punkt, es verwendet wird, auch wenn eine vorherige Anweisung für einen Wert von demselben Objekt gefragt. Außerdem wird der Wert des Objekts geschrieben sofort auf Zuordnung. Das heißt, es gibt keine Zwischenspeicherung eines flüchtigen Variable in ein CPU-Register.

Dr. Jobb das hat einen großen Artikel auf volatile .

Hier ist ein Beispiel aus dem Dr. Jobb des Artikel:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

Wenn der Compiler sieht, dass Sleep() ist ein externer Anruf, wird es, dass Sleep() annehmen kann unmöglich die Variable Flag_ Wert ändern. So kann der Compiler speichert den Wert von flag_ in einem Register. Und in diesem Fall wird es sich nie ändern. Aber wenn ein anderer Thread Anrufe aufzuwecken, ist der erste Thread lesen noch aus dem Register der CPU. Wait() wird nie aufwachen.

Warum also nicht einfach nie Cache-Variablen in die Register und das Problem vollständig vermeiden? Es stellt sich heraus, dass diese Optimierung wirklich können Sie insgesamt eine Menge Zeit sparen. So C / C ++ können Sie explizit über das volatile Schlüsselwort deaktivieren.

Die Tatsache, über diesem flag_ war eine Membervariable, und nicht eine globale Variable (noch statisch global) keine Rolle spielt. Die Erklärung nach dem Beispiel gibt die richtige Argumentation, auch wenn Sie mit globalen Variablen (und statischen globalen Variablen) zu tun hat.

Ein verbreiteter Irrtum ist, dass eine Variable volatile erklärt ausreicht Thread-Sicherheit zu gewährleisten. Operationen auf die Variable noch nicht atomar, obwohl sie in den Registern nicht „zwischengespeichert“ werden

flüchtig mit Zeigern:

Flüchtige mit Zeigern, funktioniert wie const mit Zeigern.

Eine Variable vom Typ volatile int * bedeutet, dass die Variable, die der Zeiger zeigt zu flüchtig ist.

Eine Variable vom Typ int * volatile bedeutet, dass der Zeiger selbst flüchtig ist.

Das „flüchtig“ Schlüsselwort schlägt den Compiler nicht bestimmte Optimierungen auf Code zu tun, dass die Variable beteiligt ist; wenn Sie nur eine globale Variable verwenden, nichts hindert den Compiler zu Unrecht Ihren Code zu optimieren.

Beispiel:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

Ohne „flüchtig“, der erste Schreib optimiert werden kann.

Das Schlüsselwort volatile teilt den Compiler, um sicherzustellen, dass Variable wird nicht zwischengespeichert werden. Alle Zugriffe auf es in einer konsistenten Art und Weise vorgenommen werden muß einen konsistenten Wert zwischen allen Threads haben. Wenn der Wert der Variablen von einem anderen Thread geändert werden soll, während Sie eine Schleife Prüfung auf Veränderung haben, möchten Sie die Variable volatil sein, da es keine Garantie dafür gibt, dass ein regulärer Variablenwert wird nicht an einem bestimmten Punkt und die Schleife zwischengespeichert werden wird nur annehmen, dass es gleich bleibt.

Flüchtige Variablen auf Wikipedia

Sie können nicht in verschiedenen in der aktuellen Umgebung, aber subtile Veränderungen könnten das Verhalten beeinflussen.

  • Verschiedene Hardware (mehr Prozessoren, verschiedene Speicherarchitektur)
  • Eine neue Version des Compilers mit einem besseren Optimierung.
  • Random Variation Timing zwischen Threads. nur ein Problem kann einmal in 10 Millionen auftreten.
  • Verschiedene Compiler Optimierungseinstellungen.

Es ist viel sicherer auf lange Sicht der richtigen Multithreading-Konstrukte von Anfang an zu verwenden, auch wenn die Dinge scheinen, ohne sie jetzt zu arbeiten.

Natürlich, wenn Ihr Programm ist nicht multi-threaded dann spielt es keine Rolle.

I +1 friol Antwort. Ich möchte einige Präzisierungen hinzufügen, wie es scheint eine Menge Verwirrungen in verschiedenen Antworten auf sein. C ist flüchtig ist nicht Java flüchtigen

So zuerst, Compiler kann eine Menge Optimierungen tut auf, basierend auf dem Datenfluss des Programms, flüchtig in C verhindert, dass macht es sicher, dass es jedes Mal, Lade- / Speicher an den Ort, der Sie wirklich (anstelle der Verwendung von Registern des Wisch aus zB). Es ist nützlich, wenn Sie einen Memory Mapped IO-Port haben, wie friol des aufgezeigt.

Volatile in C hat nichts mit Hardware-Caches oder Multithreading zu tun. Es macht Sie keine Speicher Zäune, und Sie haben absolut keine Garantie, in der Größenordnung von Operationen, wenn zwei Threads, es zu tun zugreift. Java flüchtiges Schlüsselwort tut genau das, obwohl:. Einsetzen von Speichern Zäunen bei Bedarf

volatile Variable bedeutet, daß der Wert assinged es nicht konstant ist, das heißt, wenn eine Funktion ein flüchtiges Variable „a = 10“ und die Funktion enthält, ist die Zugabe von 1 in jedem Aufruf dieser Funktion, dann wird es immer dann aktualisierte Wert zurück. { volatile int a=10; a++; } wenn die obige Funktion aufgerufen wird immer wieder dann die Variable a auf 10 nicht neu initialisiert wird, wird es immer den aktualisierten Wert zeigen, bis das Programm ausgeführt wird. 1. Ausgang = 10 dann 11 dann 12 und so weiter.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top