Was bewirkt das Schlüsselwot "volatile"?



  • Siehe Titel.
    Ich habe das schon öfters gesehen, hab aber nie verstanden, was es bewirkt.



  • volatile sagt dem compiler, dass eine variable sich jederzeit ändern kann(threads usw), er wird diese variable also net rausoptimieren.



  • otze schrieb:

    volatile sagt dem compiler, dass eine variable sich jederzeit ändern kann(threads usw), er wird diese variable also net rausoptimieren.

    Ach deswegen wird es bei inline assembly benutzt! Jetzt!


  • Mod

    voli schrieb:

    otze schrieb:

    volatile sagt dem compiler, dass eine variable sich jederzeit ändern kann(threads usw), er wird diese variable also net rausoptimieren.

    Ach deswegen wird es bei inline assembly benutzt! Jetzt!

    volatile ist weitgehend nutzlos wenn es um threads geht - und im zusammenhang mit inline-assembler (ich nehme an es bezieht sich auf gcc) hat es auch eine etwas andere bedeutung.

    volatile sorgt dafür, dass alle lese- und schreiboperation auf allen volatile deklarierten variablen in genau der reihenfolge geschehen, in der sie dem programmablauf nach vorgeshen sind. lese- und schreiboperation auf volatiles ind beobachbares verhalten und setzen somit die as-if regel, die dem compiler sonst viele freiräume einräumt, diesbezgl. ausser kraft. beispiel:

    int* p = get_ptr();
    *p = 1;
    *p = 2;
    *p = 3;
    

    der compiler darf daraus

    int* p = get_ptr();
    *p = 3;
    

    machen. dagegen bewirkt

    volatile int* p = get_ptr();
    *p = 1;
    *p = 2;
    *p = 3;
    

    dass tatsächlich genau 3 schreiboperationen über diesen pointer ausgeführt werden. das ist z.b. sehr zweckmässig, wenn man mit memory-mapped IO zu tun hat. für thread synchronisation ist volatile dagegen weitestgehend nutzlos, was dort gebraucht wird, sind memory barriers - wollte man dafür volatile einsetzen, müsste alles und jede entität volatile sein - das ist naturgemäss inakzeptabel. das problem hier ist die as-if regel: volatile ordnet nur zugriffe auf volatiles, alles andere dagegen bleibt ungeordnet bzgl. operationen auf volatiles (typisch: double-checked locking).

    im zusammenhang mit asm blöcken soll es das umordnen des blockes bzgl. des umgebenden codes verhindern - das ist aber nicht 100% zuverlässig. will man sicher gehen, benötigt man einen eintrag "memory" in der clobber-liste. in diesem falle funktioniert der asm block als barriere (und den enstprechenden assembler code vorausgesetzt kann man damit dann memory berriers bauen).



  • Dieser Beitrag von camper ist IMHO einen FAQ Eintrag wert, speziell da es das Thema volatile dort scheinbar noch nicht gibt (jedenfalls laut Forensuche) ⚠



  • für thread synchronisation ist volatile dagegen weitestgehend nutzlos

    richtig. ist aber auch nicht das, was ich gesagt hab 😉

    ich meinte speziell wenn ein thread ein objekt beliebig ändern kann. Der Compiler kann dies oft nicht wissen, und kann anfangen an dem objekt rumzuoptimieren. Speziell in verbindung mit const kann das ohne volatile probleme geben.


  • Mod

    otze schrieb:

    für thread synchronisation ist volatile dagegen weitestgehend nutzlos

    richtig. ist aber auch nicht das, was ich gesagt hab 😉

    ich weiss. deshalb hab ich auch nicht widersprochen 😉 - nur unkommentiert lassen wollte ich es auch nicht. volatile und threads ist ein thema, bei dem häufig konfusion herrscht.



  • Weiß nicht, ob's schon gesagt wurde, hab's auf die Schnelle nicht gesehen:

    volatile sorgt auch dafür, daß die Variable immer im Speicher nachgelesen wird. Der Compiler darf nicht beschließen die in ein Register zu packen.

    while(!workDone);

    Mit volatile könnte ein anderer Thread workDone auf true setzen und die Schleife bricht dann ab. Ohne volatile könnte der Compiler beschließen die Variable hier ins Register zu legen. Da ändert sie sich dann allerdings nie.

    Man kann damit also schon sowas wie Synchronisation machen. Es ist allerdings recht knifflig das richtig hinzukriegen. Deutlich besser funktioniert es halt doch mit atomaren Operationen.



  • Jester schrieb:

    Weiß nicht, ob's schon gesagt wurde, hab's auf die Schnelle nicht gesehen:

    volatile sorgt auch dafür, daß die Variable immer im Speicher nachgelesen wird. Der Compiler darf nicht beschließen die in ein Register zu packen.

    while(!workDone);

    Mit volatile könnte ein anderer Thread workDone auf true setzen und die Schleife bricht dann ab. Ohne volatile könnte der Compiler beschließen die Variable hier ins Register zu legen. Da ändert sie sich dann allerdings nie.

    Man kann damit also schon sowas wie Synchronisation machen. Es ist allerdings recht knifflig das richtig hinzukriegen. Deutlich besser funktioniert es halt doch mit atomaren Operationen.

    missverständlich. Im Register wird die Variable natürlich geändert, aber wahrscheinlich nicht an ihrer Adresse im Hauptspeicher. Die Frage ist, ob bei einem Non-Pointer nicht direkt aus dem Register gelesen wird wenn jene darin liegt, sondern trotzdem aus dem Speicher. Wie ist das?



  • WhoTheFuck??? schrieb:

    missverständlich. Im Register wird die Variable natürlich geändert, aber wahrscheinlich nicht an ihrer Adresse im Hauptspeicher.

    Wo wird in der Zeile die Variable geändert? Garnicht. Sie ändert sich nicht. Daß ein anderer Thread die Speicherstelle der Variablen verändert bleibt unbemerkt.


Anmelden zum Antworten