Toon posts:

[Java] volatile keyword

Pagina: 1
Acties:
  • 169 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
hoi Tweakers

Tijdens mijn studie over concurrency kom ik volatile tegen, nu dit is me niet duidelijk als ik op zoek ga hier en op de site van java versta ik hier het volgende uit:

volatile wordt gebruikt om er zeker van te zijn dat je variabele niet aangepast is door een andere thread en gaat daarom altijd de waarde van de variabele zeker nog eens uit je instantie van je klasse halen

Maar hier heb ik toch mijn bedenkingen bij want de variabelen van elke instantie van je klasse worden sowieso toch gescheiden, uitgezonderd de statics. -> zodoende is volatile toch overbodig ????

volgende letterlijk overgenomen van een website
Volatile variables Indicates a variable may be changed by more than one thread.
Each thread has it's own copy of a working variable. Volatile ensures the variable is compared to the master copy each time it is accessed

is precies wat ik dacht
nu ja heel verwarrend

  • Onno
  • Registratie: Juni 1999
  • Niet online
Verwijderd schreef op maandag 01 augustus 2005 @ 01:59:
Maar hier heb ik toch mijn bedenkingen bij want de variabelen van elke instantie van je klasse worden sowieso toch gescheiden, uitgezonderd de statics. -> zodoende is volatile toch overbodig ????
Ik zie niet helemaal hoe het ene het andere impliceert.. als je een object van een bepaalde klasse hebt kan die toch door meerdere threads tegelijk aangepast worden? Dat worden niet ineens verschillende instanties ofzo.. :)

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Onno schreef op maandag 01 augustus 2005 @ 02:07:
[...]

Ik zie niet helemaal hoe het ene het andere impliceert.. als je een object van een bepaalde klasse hebt kan die toch door meerdere threads tegelijk aangepast worden? Dat worden niet ineens verschillende instanties ofzo.. :)
^^eensch

zal het morgen voor je opzoeken (ga nu zo eens een keer pitten he)

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Variabelen kunnen worden gekopieerd voor performance optimalisaties. Zo kan bijvoorbeeld een variabele worden gekopieerd naar een register van een cpu, daar verschillende keren gelezen en geschreven worden voordat ie weer terug wordt gekopieerd naar het geheugen. Volatile vereist dat alle reads/writes meteen met het geheugen worden gesynced. Voor primitieve waardes groter dan 32 bits is het extra belangrijk, omdat hiervoor geen atomic writes/reads worden afgedwongen, tenzij de variabele volatile is.

Synchronized code regelt dit al automatisch voor je door in het begin en einde van het block een geheugen sync af te dwingen. Het is vooral interessant als je code niet synchroniseert. Merk op dat volatile een behoorlijke performance impact kan hebben, gebruik het alleen als je het echt nodig hebt.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Sluit zich aan bij het verhaal van Misfire. Volatile zorgt ervoor dat je geen waarde uit de cache van de cpu leest. Verder moet ik toegeven dat ik het nog niet vaak heb gebruik en ik ben absoluut niet vies van een stevig potje concurrency control *doet het dus ook zeer regelmatig*

[ Voor 8% gewijzigd door Alarmnummer op 01-08-2005 08:43 ]


Verwijderd

Topicstarter
dus het is niet zo dat meerdere threads de volatile keywords kunnen aanpassen , het wil enkele zeggen dat de variabele zeker uit het geheugen wordt geladen ?

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 08:42:
dus het is niet zo dat meerdere threads de volatile keywords kunnen aanpassen , het wil enkele zeggen dat de variabele zeker uit het geheugen wordt geladen ?
Die meerdere threads zijn wel belangrijk omdat het probleem zich anders niet zou voordoet ;) En het volatile keyword kunnen ze ook niet aanpassen ;)

Op het moment dat jij en ik allebei met een bepaalde variable (bv een counter) aan de slag willen, dan zou je denken dat we ook allebei gebruik maken van exact dezelfde variable. Maar de compiler die voert soms wat optimalisaties uit en daardoor worden er copies gemaakt van die variable. Stel dat ik een copy krijg van die variable en die stond nog op 0. Ik ga er een tijdje mee aan de slag.. en jij past die variable aan naar 1. Ik zie dit niet omdat ik een copy heb. Met volatile zorg je ervoor dat er dus nooit copies zijn en ik moet dus altijd kijken naar het orgineel (en dat kost dus extra tijd)

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 08:14

Janoz

Moderator Devschuur®

!litemod

Meerdere threads kunnen juist de volatile aanpassen. Volatile geeft juist aan dat je zeker weet dat een thread de versie in het geheugen aanpast ipv de versie die tijdelijk in de cache staat.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Introduceert volatile ook memory barriers? Want "master copy" klinkt aardig, totdat je bedenkt dat die master copy in je geheugen zit, en niet in je cache. Die cache is namelijk wel shared tussen threads, maar niet tussen CPU's. Als volatile alleen een register flush forceert heb je nog steeds locks nodig.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

MSalters schreef op maandag 01 augustus 2005 @ 09:31:
Introduceert volatile ook memory barriers? Want "master copy" klinkt aardig, totdat je bedenkt dat die master copy in je geheugen zit, en niet in je cache. Die cache is namelijk wel shared tussen threads, maar niet tussen CPU's. Als volatile alleen een register flush forceert heb je nog steeds locks nodig.
Die volatile zorgt ervoor dat dus altijd uit het geheugen gelezen wordt en nooit uit de cache. Volatile is trouwens altijd al een 'vaag' punt in java geweest (veel threadproblematiek trouwens als je diep erin duikt). Ik werk zelf trouwens meestal met atomicxxx classes (atomicinteger etc) waarbij ik dit geneuzel niet heb.

Verwijderd

Topicstarter
zou het mogelijk zijn om efkes een klein vbje te geven waar je volatile moet gebruiken omdat het anders zou foutlopen
want heb hier op internet voorbeeldjes gevonden
waar ze een controle boolean in de run methode gebruiken en soms is die volatile en soms niet verwarrend hoor

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 09:55:
zou het mogelijk zijn om efkes een klein vbje te geven waar je volatile moet gebruiken omdat het anders zou foutlopen
want heb hier op internet voorbeeldjes gevonden
waar ze een controle boolean in de run methode gebruiken en soms is die volatile en soms niet verwarrend hoor
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo{
     int stop = false;

     void printOnzin(){
            while(!_stop){
                   System.out.println("bla");
            }
     }

     void stop(){
           _stop = true;
     }
}

Thread 1 roept printOnzin aan en je ziet dan bla bla bla op het scherm verschijnen. Thread 2 die roept aan: stop. Maar je blijft maar bla bla bla op je scherm zien. Dit komt omdat thread1 zijn copy van stop dus niet wordt geupdate en dus thread 1 de hele tijd met de oude waarde blijft werken en dus nooit gaat stoppen. Als _stop volatile maakt, dan heb je dit probleem niet en zal thread1 stoppen zo gauw thread 2 de stop methode aanroept.

Verwijderd

Topicstarter
ok thx maar na een tijd gaat die stop toch ook geupdate worden niet ? en dan zou die thread ook moeten stoppen normaal gezien of ben ik fout

Verwijderd

Topicstarter
Alarmnummer schreef op maandag 01 augustus 2005 @ 10:18:
[...]


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo{
     int stop = false;

     void printOnzin(){
            while(!_stop){
                   System.out.println("bla");
            }
     }

     void stop(){
           _stop = true;
     }
}

Thread 1 roept printOnzin aan en je ziet dan bla bla bla op het scherm verschijnen. Thread 2 die roept aan: stop. Maar je blijft maar bla bla bla op je scherm zien. Dit komt omdat thread1 zijn copy van stop dus niet wordt geupdate en dus thread 1 de hele tijd met de oude waarde blijft werken en dus nooit gaat stoppen. Als _stop volatile maakt, dan heb je dit probleem niet en zal thread1 stoppen zo gauw thread 2 de stop methode aanroept.
das raar zou eerder iets voor static zijn dan omdat die de variabelen shared over al de objecten

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

Alarmnummer schreef op maandag 01 augustus 2005 @ 10:18:
[...]


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo{
     int stop = false;

     void printOnzin(){
            while(!_stop){
                   System.out.println("bla");
            }
     }

     void stop(){
           _stop = true;
     }
}

Thread 1 roept printOnzin aan en je ziet dan bla bla bla op het scherm verschijnen. Thread 2 die roept aan: stop. Maar je blijft maar bla bla bla op je scherm zien. Dit komt omdat thread1 zijn copy van stop dus niet wordt geupdate en dus thread 1 de hele tijd met de oude waarde blijft werken en dus nooit gaat stoppen. Als _stop volatile maakt, dan heb je dit probleem niet en zal thread1 stoppen zo gauw thread 2 de stop methode aanroept.
Dit is volgens mij een slecht voorbeeld, al moet ik erbij zeggen dat ik niet precies weet hoe het in java in elkaar zit, maar in feite kan de compiler niet weten wat voor sideeffects de call naar println()
heeft, en dus mag hij de variabele nooit optimizen rond die call. Anders zou het ook niet goed werken met een enkele thread als println de variabele zou wijzigen

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Hoe kan code buiten Foo bij Foo::stop? Niet, dus kan de compiler (!stop) optimaliseren tot (true).

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Alarmnummer schreef op maandag 01 augustus 2005 @ 09:42:
[...]
Die volatile zorgt ervoor dat dus altijd uit het geheugen gelezen wordt en nooit uit de cache. Volatile is trouwens altijd al een 'vaag' punt in java geweest (veel threadproblematiek trouwens als je diep erin duikt). Ik werk zelf trouwens meestal met atomicxxx classes (atomicinteger etc) waarbij ik dit geneuzel niet heb.
Weet je het heel zeker? Atomic operaties hebben volgens mij geen memory barriers. Dat wil zeggen dat ze wel werken op een single-core CPU/multi-threaded programma, maar niet in split-cache systemen (multi-core/multi-CPU). De enige garantie van atomic operaties is dat de main memory update atomair gebeurt, dus dat een andere CPU de hele update ziet als hij de update ziet

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op maandag 01 augustus 2005 @ 10:49:
Hoe kan code buiten Foo bij Foo::stop? Niet, dus kan de compiler (!stop) optimaliseren tot (true).
Dit toevoegen aan de namespace waar Foo in staat:
Java:
1
2
3
4
5
6
7
public class Bar
{
    public static setFooStop (Foo foo, boolean stop)
    {
        foo._stop = stop;
    }
}


;)

Dus nee, de compiler kan dat hier niet optimaliseren. De VM wel natuurlijk aangezien hij alle benodige info heeft, maar ik betwijfel of dat ook zo gespecificeerd is. Ook een niet optimaliserende VM moet tenslotte aan de specs kunnen voldoen.

[ Voor 26% gewijzigd door .oisyn op 01-08-2005 11:09 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 10:27:
ok thx maar na een tijd gaat die stop toch ook geupdate worden niet ?
Dat weet ik niet :) En wie zegt wat die tijd is. een seconde? een minuut? nooit?
en dan zou die thread ook moeten stoppen normaal gezien of ben ik fout
Zo gauw die thread 1 ziet dat die stop waarde true is, dan zal hij stoppen. De vraag is wanneer dit gaat gebeuren.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 10:30:
[...]
das raar zou eerder iets voor static zijn dan omdat die de variabelen shared over al de objecten
Stel dat je een of ander motor-object hebt. Dan wil je een stop conditie per motor hebben en is static dus niet goed. Static is dus geen optie.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

.oisyn schreef op maandag 01 augustus 2005 @ 10:41:
[...]


Dit is volgens mij een slecht voorbeeld, al moet ik erbij zeggen dat ik niet precies weet hoe het in java in elkaar zit, maar in feite kan de compiler niet weten wat voor sideeffects de call naar println()
heeft, en dus mag hij de variabele nooit optimizen rond die call.
Wat er gebeurt is het volgende: voor die thread wordt die variable in een bepaald register neergezet (das de optimalisatie) Iedere wijziging in die thread, voor dat veld, zal voor die thread ook direct zichtbaar zijn omdat die waarde in het register wordt aangepast. Dus voor 1 thread werkt het heel goed.

[ Voor 3% gewijzigd door Alarmnummer op 01-08-2005 11:49 ]


Verwijderd

Topicstarter
ahja maar ik vind het raar als je bvb een motor gaat stoppen in een ander wagen object dus wagen2.setMotor(false) en dan gaat wagen1 ook stoppen begrijp je dat vind ik toch maar iets bizars
ik zou zeggen als ik wagen1.setMotor(false) zet dat dan wagen2.getMotor() nog altijd op true staat dus dat de motor van wagen2 nog werkt

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

MSalters schreef op maandag 01 augustus 2005 @ 10:52:
[...]

Weet je het heel zeker? Atomic operaties hebben volgens mij geen memory barriers. Dat wil zeggen dat ze wel werken op een single-core CPU/multi-threaded programma, maar niet in split-cache systemen (multi-core/multi-CPU). De enige garantie van atomic operaties is dat de main memory update atomair gebeurt, dus dat een andere CPU de hele update ziet als hij de update ziet
Atomicxxx zijn gewoon objecten wrappers om primitieve waarden met een volledige monitor om die primitieve waarde heen. Het gevolg hiervan is dat het dus niet voor kan komen dat er een copy wordt gemaakt van een register waarvan de waarde kan wijzigen (het veld waar die atomicxxx waarde in staat kan wel geopmitaliseerd worden naar een lokaal register, maar dat veld veranderd nooit van waarde).

zie: Atomic Integer

[ Voor 29% gewijzigd door Alarmnummer op 01-08-2005 12:07 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 11:49:
ahja maar ik vind het raar als je bvb een motor gaat stoppen in een ander wagen object dus wagen2.setMotor(false) en dan gaat wagen1 ook stoppen begrijp je dat vind ik toch maar iets bizars
ik zou zeggen als ik wagen1.setMotor(false) zet dat dan wagen2.getMotor() nog altijd op true staat dus dat de motor van wagen2 nog werkt
Dat klopt. En als jij werkt met een static conditie dan stoppen ineens alle motoren en dat is dus niet wat je wilt. Jij wilt per motor een condtie en dan zul je niet met een static variable moeten werken.

Verwijderd

Topicstarter
ok dat snap ik maar met die volatile wil ik verstaan dat door die variabele als volatile te zetten ook een andere thread bvb thread2 de volatile waarde van thread1 kan aanpassen is dit juist of loopt toch alles gescheiden en doet die vollatile alleen maar een call naar het geheugen om zeker te zijn dat alles altijd up to date is ???

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 11:57:
ok dat snap ik maar met die volatile wil ik verstaan dat door die variabele als volatile te zetten ook een andere thread bvb thread2 de volatile waarde van thread1 kan aanpassen is dit juist of loopt toch alles gescheiden en doet die vollatile alleen maar een call naar het geheugen om zeker te zijn dat alles altijd up to date is ???
Met volatile zorg je er dus voor dat er nooit copies gemaakt van velden worden (geen register optimalisaties) en daardoor krijg je de garanties dat iedereen met dezelfde instantie van dat veld werkt. (een wijziging binnen 1 thread zal daarom ook direct zichtbaar zijn in die andere threads die met hetzelfde veld werken).

[ Voor 4% gewijzigd door Alarmnummer op 01-08-2005 12:12 ]


Verwijderd

Topicstarter
dus kun je dan toch het motor object van een andere wagen aanspreken bizar

  • grhmpf
  • Registratie: December 2000
  • Laatst online: 29-05-2022

grhmpf

Android <3

Nee, je bent in de war met "static" (al de hele tijd :P).

Als je een class A hebt met een field x en die is niet volatile dan heb je geen garantie dat threads die die A.x lezen allemaal dezelfde waarde van x "zien" (dwz het kan goed gaan, maar dan heb je geluk :)). Maak je A.x volatile dan zorg je er dus voor dat elke thread de laatste waarde (de echte waarde) van A.x ziet.

Als elke thread een "A" heeft dan maakt dat dus niets uit, want er is dan maar 1 Thread die een instantie van A bewerkt.

Volgens mij is het wel duidelijk uitgelegd maar zie je het nog niet, dus lees het allemaal nog eens een keertje door zou ik zeggen :)

[ Voor 16% gewijzigd door grhmpf op 01-08-2005 12:05 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 12:01:
dus kun je dan toch het motor object van een andere wagen aanspreken bizar
Nope.. je begrijpt het niet.

Je moet niet werken met een static veld. Dan zou je dat veld tussen verschillende motoren delen en dat zou erg stom zijn. bij een motor het veld aanpassen, dan gaan alle motoren uit. Dit moet je dus niet. Static = bad in dit geval.

Verwijderd

Topicstarter
dus als een field volatile is wil dit zeggen dat het direct door threads kan gemanipuleerd worden en die veranderingen gaan direct zichtbaar zijn in het field door dat het volatile is

ben ik nu juist ?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

Alarmnummer schreef op maandag 01 augustus 2005 @ 11:49:
[...]

Wat er gebeurt is het volgende: voor die thread wordt die variable in een bepaald register neergezet (das de optimalisatie) Iedere wijziging in die thread, voor dat veld, zal voor die thread ook direct zichtbaar zijn omdat die waarde in het register wordt aangepast. Dus voor 1 thread werkt het heel goed.
Ik weet van volatile en register optimalisaties hoor ;) die heb je in C++ ook. Waar het me om gaat is dat de compiler hier niet mag optimizen (ongeacht het gebruik van volatile op _stop), omdat hij simpelweg niet weet of de call naar println side-effects heeft die diezelfde variabele _stop wijzigt. Want stel je hebt deze code:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Foo
{
     int _stop = false;

     void printOnzin(){
            while(!_stop){
                   Bar.doeIets();
            }
     }

     void stop(){
           _stop = true;
     }
}

public class Bar
{
    static Foo foo;

    public static void doeIets() { foo.stop(); }


    public static void main(String[] args)
    {
        foo = new Foo();
        foo.printOnzin();        
    }
}


De class Foo is hier exact hetzelfde, behalve dat hij een call doet naar Bar.doeIets() ipv System.out.println(), maar dat maakt voor de compiler niets uit. Hij mag de variabele dus niet optimizen naar een register om de call naar die functie, omdat die functie mogelijk side-effects heeft waardoor die variabele aangepast kan worden. Als hij die variabele optimized dan is je programma dus niet meer correct, zelfs met 1 thread.

En als de compiler hier de optimize mag doen, dan betekent dat simpelweg dat je vrijwel overal en altijd volatile moet specificeren voor een correct werkend programma ;)

[ Voor 7% gewijzigd door .oisyn op 01-08-2005 12:22 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op maandag 01 augustus 2005 @ 12:12:
dus als een field volatile is wil dit zeggen dat het direct door threads kan gemanipuleerd worden en die veranderingen gaan direct zichtbaar zijn in het field door dat het volatile is

ben ik nu juist ?
Yep..

Nog een keer duidelijk.

Stel dat ik een class heb met een veld a. Dit veld staat ergens in het geheugen. Stel ik ben nu 1 thread, dan wil je cpu nog wel eens een optimalisatie doen. He thread, jij wilt vaak werken met a, weet je wat, ik maak even een copy aan van die a, a*. Deze a* plaats ik even in een register en dan hoef ik niet de hele tijd naar het geheugen toe om a op te halen en kunnen we veel tijd besparen.

Nu komt thread2 eraan en nu zegt de cpu, van heej.. jij wilt ook met a werken, weet je wat ik maak even een copy aan, a**. Als jij nu a nodig bent dan ga ik even valsspelen en haal ik de waarde van a** op (die in het register staat) ipv de waarde van a.

Zoals je ziet werkt thread1 met a* en thread2 met a**. Stel dat thread1 de waarde van a aanpast, dan wordt niet de waarde van a aangepast, maar die van a*. Hetzelfde geld voor thread2.

Als je maar met 1 thread werkt dan is het niet zo`n probleem omdat uiteindelijk de waarde van die a* en a** wel weer terug worden gezet naar a. Maar bij meerdere threads kan het leiden tot vreemde situaties. Die volatile zorgt er dus voor dat er dus nooit van die ** variabelen (registers) worden aangemaakt en dat iedereen altijd moet werken met a. Nadeel -> je moet vaker het geheugen raadplegen -> dat is kostbaar (tov een register) -> dus langzamer.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

volatile is overigens geen op zichzelf bruikbare concurrency methode. Het is iets dat je nodig hebt bij concurrency control. Er is nog steeds geen garantie over de volgorde dat een en ander gebeurt. Het enige dat het zegt is dat een variabele door iets anders dan een programma statement kan worden veranderd. Tussen twee statements dat je variabele niet wordt aangepast in je code, zal de compiler dus niet aannemen dat deze nog dezelfde waarde bevat.

Als een 64bit int in twee keer moet worden weggeschreven, dan kan dit met het volatile keyword nog steeds fout gaan. Er is geen garantie dat de hele waarde wordt weggeschreven voordat er een andere thread draait. De enige garantie die je krijgt is dat je waarde altijd uit het geheugen wordt gelezen als deze nodig is, en dus niet lokaal gecached wordt. Binnen een 'lock' zijn je waardes niet volatile, en er buiten wel.

  • grhmpf
  • Registratie: December 2000
  • Laatst online: 29-05-2022

grhmpf

Android <3

Stelletje techneuten :) Hij vraagt waar het voor is en dan geef je een voorbeeld met hoe het werkt (tot op registernivo aan toe) :P

en:
volatile is overigens geen op zichzelf bruikbare concurrency methode.
...
Ik gebruik zelf liever synchronized om die reden, omdat je daarmee explicieter kan aangeven dat in een methode iets speciaals gebeurt. Nadeel is dat je er dan wel consequent goed moet doen :)

[ Voor 54% gewijzigd door grhmpf op 01-08-2005 12:36 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

grhmpf schreef op maandag 01 augustus 2005 @ 12:33:
Ik gebruik zelf liever synchronized om die reden, omdat je daarmee explicieter kan aangeven dat in een methode iets speciaals gebeurt. Nadeel is dat je er dan wel consequent goed moet doen :)
Dat wil niet zeggen dat je geen volatile nodig hebt. Compiler optimalisaties kunnen nog steeds roet in het eten gooien. zoals dat voorbeeld boven met die loop op een bool; je compiler kan die hele test op de bool eruit gooien, omdat het een constante test is in de ogen van je compiler. Synchronized moethoden zullen hier niets aan vernaderen.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Alarmnummer schreef op maandag 01 augustus 2005 @ 11:50:
[...]


Atomicxxx zijn gewoon objecten wrappers om primitieve waarden met een volledige monitor om die primitieve waarde heen. Het gevolg hiervan is dat het dus niet voor kan komen dat er een copy wordt gemaakt van een register waarvan de waarde kan wijzigen (het veld waar die atomicxxx waarde in staat kan wel geopmitaliseerd worden naar een lokaal register, maar dat veld veranderd nooit van waarde).

zie: Atomic Integer
Ik zie nergens iets over een cache flush (of monitors). Ben je bekend met JSR 133?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • grhmpf
  • Registratie: December 2000
  • Laatst online: 29-05-2022

grhmpf

Android <3

Het is toch geen constante als het een (niet final) field is? Het lijkt me niet dat dat weggeoptimaliseerd wordt, maar ik heb geen tegenbewijzen :) Als het in locale scope zou staan dan zou ik je direct geloven.

In het bovenstaande voorbeeld zou ik stop() synchronizen.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

MSalters schreef op maandag 01 augustus 2005 @ 12:45:
[...]

Ik zie nergens iets over een cache flush (of monitors).
Ieder java object kan als monitor werken. Het komt er dus op neer dat daar mbv synchronisatie wordt afgedwongen dat er dus geen gekke problemen op kunnen treden. Volatile is hier ook niet nodig omdat na het eindigen van een methode de eventuele copieen van registers weer worden weggeschreven naar het geheugen. En dit vind dus altijd plaats onder 1 atomaire aanroep. Het is dus niet mogelijk dat er op 1 tijdstip een register + het geheugen kan worden aangepast door meerdere threads

Flushen ed kunnen we ook niet zelf, dat is een vm aangelegenheid.
Ben je bekend met JSR 133?
Nope.. tenminst ik ben niet bekend met zaken die nu niet in java zitten. Verder hou ik me ook niet bezig op dit nivo. Ik gebruik zelf geen volatile velden (pak wel een atomicxxx object als ik dat nodig ben).

[ Voor 8% gewijzigd door Alarmnummer op 01-08-2005 12:57 ]


  • grhmpf
  • Registratie: December 2000
  • Laatst online: 29-05-2022

grhmpf

Android <3

offtopic:
[quote]Alarmnummer schreef op maandag 01 augustus 2005 @ 12:53:
Nope.. tenminst ik ben niet bekend met zaken die nu niet in java zitten. Verder hou ik me ook niet bezig op dit nivo. Ik gebruik zelf geen volatile velden (pak wel een atomicxxx object als ik dat nodig ben).[/quote]

Erhm, hoe zat dat dan met generics :) Ik kan me herinneren dat je daar een fervent gebruiker van was toen het nog in EA zat :P Op dat moment zat het ook niet in officieel in Java!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

grhmpf schreef op maandag 01 augustus 2005 @ 13:04:
offtopic:
Erhm, hoe zat dat dan met generics :) Ik kan me herinneren dat je daar een fervent gebruiker van was toen het nog in EA zat :P Op dat moment zat het ook niet in officieel in Java!
Mijn interesse voor concurrency control ligt niet zozeer op lowlevel nivo, maar meer op hoger nivo. En verder weet ik dat er heel wat gerommel is, en is geweest op dit gebied dus ik had zowieso al zoiets van: het zal wel.

[ Voor 13% gewijzigd door Alarmnummer op 01-08-2005 13:08 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

Alarmnummer: had je deze reactie nou nog gelezen? [rml].oisyn in "[ Java] volatile keyword"[/rml]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

.oisyn schreef op maandag 01 augustus 2005 @ 12:18:
Ik weet van volatile en register optimalisaties hoor ;) die heb je in C++ ook. Waar het me om gaat is dat de compiler hier niet mag optimizen (ongeacht het gebruik van volatile op _stop), omdat hij simpelweg niet weet of de call naar println side-effects heeft die diezelfde variabele _stop wijzigt. Want stel je hebt deze code:

De class Foo is hier exact hetzelfde, behalve dat hij een call doet naar Bar.doeIets() ipv System.out.println(), maar dat maakt voor de compiler niets uit. Hij mag de variabele dus niet optimizen naar een register om de call naar die functie, omdat die functie mogelijk side-effects heeft waardoor die variabele aangepast kan worden. Als hij die variabele optimized dan is je programma dus niet meer correct, zelfs met 1 thread.

En als de compiler hier de optimize mag doen, dan betekent dat simpelweg dat je vrijwel overal en altijd volatile moet specificeren voor een correct werkend programma ;)
Ik zou wel iets kunnen bedenken maar daar hebben we niets aan :) Ik zou het dus niet weten hoe hij ermee omgaat. In principe kan een methode call (zeker op een ander object) allerlei dingen als gevolg hebben. Misschien dat hij bij een methode call op een ander object eerst alles gaat flushen en bij de return van die methode call weer registers gaat vullen. Ik zou het echt niet weten wat de jit-compiler hier van bakt en of er dus uberhaubt wel geoptimaliseerd gaat worden. Mijn printlin was misschien wat onhandig gekozen.

[ Voor 4% gewijzigd door Alarmnummer op 01-08-2005 13:21 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Alarmnummer schreef op maandag 01 augustus 2005 @ 12:53:
[...]

Ieder java object kan als monitor werken. Het komt er dus op neer dat daar mbv synchronisatie wordt afgedwongen dat er dus geen gekke problemen op kunnen treden. Volatile is hier ook niet nodig omdat na het eindigen van een methode de eventuele copieen van registers weer worden weggeschreven naar het geheugen. En dit vind dus altijd plaats onder 1 atomaire aanroep. Het is dus niet mogelijk dat er op 1 tijdstip een register + het geheugen kan worden aangepast door meerdere threads
Ok, ik zie waar de verwarring vandaan komt. Je gaat er van uit dat iets threadsafe is als je geen conflicting writes hebt, en geen partial writes. (dwz een logische unit van data wordt in 1 keer geschreven door 1 thread). Dat is niet genoeg voor volledig threadsafe code. Niet alleen moeten writes atomair zijn, maar ook zichtbaar voor andere CPUs.

Dat is niet vanzelfsprekend op machines met zwakke geheugensynchroniteit. Daar is een write wel atomair maar niet noodzakelijk zichtbaar. Dat wil zeggen, voor elke CPU is een write of niet begonnen of helemaal voltooid, maar per CPU kan dat verschillen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

MSalters schreef op maandag 01 augustus 2005 @ 13:23:
[...]

Ok, ik zie waar de verwarring vandaan komt. Je gaat er van uit dat iets threadsafe is als je geen conflicting writes hebt, en geen partial writes. (dwz een logische unit van data wordt in 1 keer geschreven door 1 thread). Dat is niet genoeg voor volledig threadsafe code. Niet alleen moeten writes atomair zijn, maar ook zichtbaar voor andere CPUs.
Ik ga ervan uit, dat als je een lock op een object krijgt, dit object in een volledig goeie toestand staat. Ongeacht of er meerdere cpu`s op dit object willen werken. Dus als je een lock op een atomicxxx object krijgt, dan is die correct en is zijn toestand ook binnen alle cpu`s zichtbaar. Een atomic int is ook een normaal object die toevalligerwijs een primitieve integer als veld heeft. Verder is het niets bijzonders.

[ Voor 8% gewijzigd door Alarmnummer op 01-08-2005 13:41 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Een volledig goede toestand, maar niet noodzakelijkerwijs de volledig goede toestand. In race condities is namelijk (wiskundig) ongedefinieerd wat de goede toestand is. Als de gebruiker alle mogelijke toestanden goed vindt, dan kan zo'n atomic operatie nuttig zijn. Er zijn algoritmes waarbij dat acceptabel is, maar dat is niet het geval voor alle algoritmes. In die laatste gevallen moet je toch een mutex gebruiken, want die levert zeker een memory barrier met bijbehorende synchronisatie op.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
.oisyn schreef op maandag 01 augustus 2005 @ 12:18:
[...] stel je hebt deze code:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Foo
{
     int _stop = false;

     void printOnzin(){
            while(!_stop){
                   Bar.doeIets();
            }
     }

     void stop(){
           _stop = true;
     }
}

public class Bar
{
    static Foo foo;

    public static void doeIets() { foo.stop(); }


    public static void main(String[] args)
    {
        foo = new Foo();
        foo.printOnzin();        
    }
}


De class Foo is hier exact hetzelfde, behalve dat hij een call doet naar Bar.doeIets() ipv System.out.println(), maar dat maakt voor de compiler niets uit.
Snap ik het niet, of is de Foo in main (en dus de Foo::_stop) een andere dan de Foo in Bar?
De Foo::stop in main kan bewijsbaar alleen door main en de Foo instance uit main worden gewijzigd en niet door Bar. Een optimizer kan dus vasstellen dat die _specifieke stop dus altijd gelijk moet zijn aan false.

[ Voor 13% gewijzigd door MSalters op 01-08-2005 17:27 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

MSalters schreef op maandag 01 augustus 2005 @ 17:21:
Een volledig goede toestand, maar niet noodzakelijkerwijs de volledig goede toestand. In race condities is namelijk (wiskundig) ongedefinieerd wat de goede toestand is. Als de gebruiker alle mogelijke toestanden goed vindt, dan kan zo'n atomic operatie nuttig zijn. Er zijn algoritmes waarbij dat acceptabel is, maar dat is niet het geval voor alle algoritmes. In die laatste gevallen moet je toch een mutex gebruiken, want die levert zeker een memory barrier met bijbehorende synchronisatie op.
Bij een atomic int krijg je de garantie dat er geen race condities zich kunnen voortdoen en dat ze perfect gebruikt kunnen worden in multithreaded (ook meerdere cpu`s) omgevingen.

[ Voor 14% gewijzigd door Alarmnummer op 01-08-2005 17:39 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik denk het, of ik snap jou niet
of is de Foo in main (en dus de Foo::_stop) een andere dan de Foo in Bar?
:?
Bovenstaande code is correct as-is, gooi het in een Java file en het compilet volgens mij :)
Bar.main (static entry point) maakt een Foo aan en stored z'n instance. Vervolgens wordt foo.printOnzin() aangeroepen, die Bar.doeIets() aanroept totdat _stop op true staat. Bar.doeIets() zet die _stop op true, dus de loop stopt na een enkele iteratie. Mijn punt was dat de optimizer hier de while(_stop) niet mag optimizen naar een while(true) omdat hij simpelweg niet weet wat voor side-effects de call naar Bar.doeIets() heeft.

En ja, natuurlijk is het te bewijzen dat dat wel het geval is, omdat je de implementatie van Bar.doeIets() kent. De VM in feite ook, maar ik vraag me af of die zo ver gaat (dit is een redelijk simpel voorbeeld met 2 classes in dezelfde file, maar wat als je 1 van die classes nou dynamisch laadt at runtime?)
De Foo::stop in main kan bewijsbaar alleen door main en de Foo instance uit main worden gewijzigd en niet door Bar.
Kijk je wel goed :?. De foo instance wordt toch heel duidelijk opgeslagen als static field in de Bar class? Daar kan de Bar.doeIets() functie toch gewoon bij? Ergo, de _stop variabele kan wel degelijk door Bar worden aangepast, of niet?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Atomic ints kunnen die garantie niet geven. Als twee CPUs tegelijkertijd een operatie willen uitvoeren op dezelfde atomic int, dan is er een race conditie. De enige garantie die je hebt is dat de race wordt opgelost op een manier dat alle memory access die nodig is voor de atomaire operaties van de twee CPUs niet interleaved wordt.

Nogmaals, wat "perfect" is hangt van je algoritme af. Voor sommige algoritmen is dit perfect, andere hebben een memory barrier (en dus in Java een mutex) nodig. Zou je elke operatie op een atomic int een memory barrier geven, dan is de code nodeloos langzaam. Een programmeur kan dat niet zelf fixen door die memory barrier te verwijderen. Een programmeur kan wel een memory barrier toevoegen door een mutex te gebruiken.

Ik geef toe, het lijkt wel C. "Make it fast, trust the programmer to make it safe. The other way around is impossible".

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Zoijar, je hebt blijkbaar mijn eerste reactie op dit topic niet gelezen, of gewoon gedacht dat het niet klopte. Wat je zelf beschrijft klopt namelijk niet. Ik wil dit toch even corrigeren omdat dit duidelijk een topic is waar mensen willen leren over het volatile keyword en threading in Java in het algemeen. Het zou zonde zijn als ze dan de verkeerde dingen zouden leren. :)

Voor degenen die nog even rustig willen nalezen over volatile en synchronized: hier is een heel aardige uitleg te vinden.
Zoijar schreef op maandag 01 augustus 2005 @ 12:33:
Als een 64bit int in twee keer moet worden weggeschreven, dan kan dit met het volatile keyword nog steeds fout gaan. Er is geen garantie dat de hele waarde wordt weggeschreven voordat er een andere thread draait. De enige garantie die je krijgt is dat je waarde altijd uit het geheugen wordt gelezen als deze nodig is, en dus niet lokaal gecached wordt. Binnen een 'lock' zijn je waardes niet volatile, en er buiten wel.
Dat is niet waar, volatile garandeert namelijk ook op 64bit waardes atomic writes/reads. Dit is één van de specifieke redenen om volatile te gebruiken.
Zoijar schreef op maandag 01 augustus 2005 @ 12:41:Dat wil niet zeggen dat je geen volatile nodig hebt. Compiler optimalisaties kunnen nog steeds roet in het eten gooien. zoals dat voorbeeld boven met die loop op een bool; je compiler kan die hele test op de bool eruit gooien, omdat het een constante test is in de ogen van je compiler. Synchronized moethoden zullen hier niets aan vernaderen.
Synchronized garandeert een memory flush voor en na het locken. Alle variabelen zijn dus automatisch een verse kopie, en aangezien de synchronized code andere synchronized code blokken met dezelfde mutex blokkeert zullen er ook geen writes door andere threads worden uitgevoerd. Synchronized biedt dus wel degelijk een (meestal veel beter) alternatief voor volatile.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

misfire schreef op maandag 01 augustus 2005 @ 19:26:
Zoijar, je hebt blijkbaar mijn eerste reactie op dit topic niet gelezen, of gewoon gedacht dat het niet klopte. Wat je zelf beschrijft klopt namelijk niet. Ik wil dit toch even corrigeren omdat dit duidelijk een topic is waar mensen willen leren over het volatile keyword en threading in Java in het algemeen. Het zou zonde zijn als ze dan de verkeerde dingen zouden leren. :)
Ik ging uit van de C++ versie van volatile. Blijkbaar is in java volatile dusdanig veranderd dat dit soort problemen zich niet meer voordoen; ie. volatile is effectief een lock geworden. Veel meer dan een (snelle) compiler restrictie: iets dat ook daadwerkelijk code genereert in de vorm van memory barriers. In C++ is volatile niet echt bruikbaar, aangezien je compiler zich netjes aan de regels kan houden (met veel moeite), maar de processor caches niet. Dit artikel hier is ook wel interessant: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Maar... ik kan me dus blijkbaar beter niet met Java bezighouden, of in ieder geval geen parallellen trekken (pun intended) :) Excuus.

(vnl. dit stukje uit het artikel:)
So when dealing with some memory locations (e.g. memory mapped ports or
memory referenced by ISRs), some optimizations must be suspended. volatile
exists for specifying special treatment for such locations, specifically: (1) the
content of a volatile variable is “unstable” (can change by means unknown
to the compiler), (2) all writes to volatile data are “observable” so they must
be executed religiously, and (3) all operations on volatile data are executed
in the sequence in which they appear in the source code. The first two rules
ensure proper reading and writing. The last one allows implementation of I/O
protocols that mix input and output. This is informally what C and C++’s
volatile guarantees.
Java took volatile a step further by guaranteeing the properties above
across multiple threads. This was a very important step, but it wasn’t enough
to make volatile usable for thread synchronization: the relative ordering of
volatile and non-volatile operations remained unspecified. This ommission
forces many variables to be volatile to ensure proper ordering.
Java 1.5’s volatile [10] has the more restrictive, but simpler, acquire/release
semantics: any read of a volatile is guaranteed to occur prior to any memory
reference (volatile or not) in the statements that follow, and any write to a
volatile is guaranteed to occur after all memory references in the statements
preceding it. .NET defines volatile to incorporate multithreaded semantics as
well, which are very similar to the currently proposed Java semantics. We know
of no similar work being done on C’s or C++’s volatile.

[ Voor 41% gewijzigd door Zoijar op 01-08-2005 20:51 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Nee dus. Was vergeten dat main() in een class zit in Java :o

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Zoijar schreef op maandag 01 augustus 2005 @ 20:45:
[...]

Ik ging uit van de C++ versie van volatile. Blijkbaar is in java volatile dusdanig veranderd dat dit soort problemen zich niet meer voordoen; ie. volatile is effectief een lock geworden. Veel meer dan een (snelle) compiler restrictie: iets dat ook daadwerkelijk code genereert in de vorm van memory barriers. In C++ is volatile niet echt bruikbaar, aangezien je compiler zich netjes aan de regels kan houden (met veel moeite), maar de processor caches niet. Dit artikel hier is ook wel interessant: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Maar... ik kan me dus blijkbaar beter niet met Java bezighouden, of in ieder geval geen parallellen trekken (pun intended) :) Excuus.
Ik haalde JSR 133 aan omdat die in Java 5 ( 2.5, J2EE 5.0, laatik-maar-een-regex-gebruiken-J.*5.* of hoe die vandaag ook heet ;) ) een nieuw memory model introduceert. Voor zover ik weet is dat het derde in de Java standaarden. Omdat dat inmiddels toch wel beschamend begon te worden is er dit keer hard over nagedacht, en formele analyse tegenan gegooid. De naam Doug Lea is geen toeval in dit verband, dat is een erkend expert.

In C++ wordt er meer gekozen voor standaardisatie van bewezen technologie, en is er daarom nog geen standaard threading model. POSIX wordt wel eens gebruikt, maar dat is primair een superset van C, beperkt compatible met C++ en uit de JSR133 analyse bleek dat ok het POSIX threading model problemen heeft. Nu er een goed model is voor Java, en een Boost Threading Library is er een serieuze poging om het memory model van JSR 133 te "porten" naar C++. Dat voorstel (google: N1680, N1815) heeft redelijk support maar het blijft serieus ingewikkeld.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 28-04 14:41

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik ga de topic trouwens maar eens afsplitsen :)

.edit: en done: [rml][ Java] VM optimalisaties en performance[/rml]

[ Voor 46% gewijzigd door .oisyn op 04-08-2005 17:36 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1