Toon posts:

[java] threadsafety..?

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

Verwijderd

Topicstarter
Ik vroeg me nou gewoon eigelijk eens af of het volgende stukje threadsafe is:
Java:
1
2
3
4
private volatile int counter = 0;
public void increment(){
++counter;
}

Op processor niveau is het immers met een enkele instructie. Hoe gaat de compiler/vm hiermee om?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Welke processor? Threadsafe in Java moet je zien als threadsafe volgens de specificatie, niet alleen als "threadsafe op de 1.4.1 Sun JVM voor x86".

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


Verwijderd

Topicstarter
volatile
MSalters schreef op zondag 29 mei 2005 @ 17:52:
Threadsafe in Java moet je zien als threadsafe volgens de specificatie, niet alleen als "threadsafe op de 1.4.1 Sun JVM voor x86".
Dat zeg ik toch ook niet :/

  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06-2025

Varienaja

Wie dit leest is gek.

In assembler zal een 'x++'-instructie iets worden als

load AX,[geheugenpaats]
inc AX ; Inderdaad in 1 kloktik
store AX,[geheugenplaats]

En dat is zeker niet threadsafe.

Siditamentis astuentis pactum.


Verwijderd

Topicstarter
Varienaja schreef op zondag 29 mei 2005 @ 17:57:
In assembler zal een '++x'-instructie iets worden als
[..]
Is dat tegenwoordig niet in 1 instructie te flikken (kan haast niet geloven van niet)

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

Je zegt ook niet wat je wel bedoelt hoor, dus wat minder brutaal met die smiley mag ook wel. :/ Geef dan wat meer info in je topicstart, want je geeft hier nou zo weinig mogelijk info en wacht dan tot wij je probleem voor je oplossen. Dat is niet de bedoeling in Programming & Webscripting. Lees ook P&W FAQ - De "quickstart" maar even door om erachter te komen wat we wel willen zien in een topicstart.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Juist. Het hangt er vanaf wat je wilt bereiken, maar je wilt waarschijnlijk dat de increments van de counter vanuit verschillende threads geen rare effecten heeft.

De increment is geen atomaire operatie: het is een samenstelling van een GETFIELD, ICONST_1, IADD en PUTFIELD. De laatste PUTFIELD kan er voor zorgen dat een aanpassing die ondertussen door een andere thread gedaan is verloren gaat.

Hier heeft volatile dus niet direct iets mee te maken. Volatile is alleen belangrijk als je het veld gebruikt op meerdere plaatsen en het veld ondertussen door een andere thread aangepast kan zijn.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06-2025

Varienaja

Wie dit leest is gek.

Verwijderd schreef op zondag 29 mei 2005 @ 18:01:
[...]

Is dat tegenwoordig niet in 1 instructie te flikken (kan haast niet geloven van niet)
Je quote me verkeerd. Ik heb die ++ expres rechts naast de x gezet.

Denk je echt dat geheugentoegang inclusief een operatie, en dan nog eens geheugentoegang binnen 1 kloktik zou moeten kunnen? Er zijn niet voor niks level1 en level2 caches in een processor hoor..

Wellicht dat in de meeste gevallen de variabele die je wilt ++en in de cache staat. Dan nog duurt het een kloktik voordat die waarde naar een register is verhuisd, nog een kloktik voor de ++ en nog een kloktik om de cache weer bij te werken. Tussen al deze kloktikken door kan geswitched worden naar een ander proces dat dezelfde variabele wil veranderen.

Siditamentis astuentis pactum.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
markvleth: Is dat tegenwoordig niet in 1 instructie te flikken (kan haast niet geloven van niet)
Decompileer de .class dan gewoon met javap -c:

code:
1
2
3
4
5
6
7
8
9
void foo();
  Code:
   0:   aload_0
   1:   dup
   2:   getfield        #12; //Field counter:I
   5:   iconst_1
   6:   iadd
   7:   putfield        #12; //Field counter:I
   10:  return

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02-05 01:32
Verwijderd schreef op zondag 29 mei 2005 @ 18:01:
Is dat tegenwoordig niet in 1 instructie te flikken (kan haast niet geloven van niet)
Dat is dus precies de foute insteek. ;) Op de IA-32 architectuur is er een INC instructie die ook werkt op een geheugenlocatie, dus daar hoef je de bewerking niet per se in een register te doen zoals Varienaja deed, maar dat is maar één specifiek voorbeeld en slechts een mogelijkheid. Het hele idee van een portable taal als Java is dat je geen aannames kan doen over zaken die niet expliciet gespecificeerd zijn in de standaard.

Als je op een andere architectuur werkt heb je dus geen garantie dat zo'n instructie bestaat. Verder is er geen enkele garantie dat zelfs als er zo'n instructie bestaat, de Java compiler die ook genereert (de Java compiler kan best de code van Varienaja generen, ook in een IA-32 architectuur).

Tenslotte gaat het zelfs bij de IA-32 architectuur mis als je een multiprocessor systeem hebt (of een CPU met hyperthreading), omdat de uitvoering van de instructie in micro operations niet thread safe is (op laag nivo heb je dan dezelfde code als Varienaja gaf). Je zou de instructie dan een lock prefix moeten geven, wat de compiler zeker niet zal doen, want dat verpest de performance volledig.

  • c0deaddict
  • Registratie: Mei 2004
  • Laatst online: 10-01 12:11

c0deaddict

Don't be lame, be KLEI


Verwijderd

Topicstarter
-NMe- schreef op zondag 29 mei 2005 @ 18:01:
Je zegt ook niet wat je wel bedoelt hoor, dus wat minder brutaal met die smiley mag ook wel. :/ Geef dan wat meer info in je topicstart, want je geeft hier nou zo weinig mogelijk info en wacht dan tot wij je probleem voor je oplossen.
Wat de neuk is er nou weer brutaal aan dat smiley :/
Welke info heb je nog meer nodig dan de lading dekkende term "Threadsafe"...

Maar goed het is dus niet threadsafe, jammerlijk. Dus dergelijke simpele dingen hebben dus helaas sunchronisatie nodig...

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
Bij mij kwam die smiley ook brutaal over.
Men probeert hier gewoon een discussie te houden, en als mensen reageren, dan hoef je er helemaal geen smiley plaatsen die -zoals NMe al zegt- brutaal is, dat zorgt er enkel voor dat die mensen al helemaal geen zin meer zullen hebben om zich nog in de discussie te mengen.
IRL ga je anderen waarmee je in discussie bent, of als je die mensen een vraag stelt, toch ook niet afblaffen of scheel bekijken ?

Maar goed, laten we het nu maar verder on topic houden.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Ik bedoelde hem gewoon verbaast ...

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
mbravenboer schreef op zondag 29 mei 2005 @ 18:04:
Juist. Het hangt er vanaf wat je wilt bereiken, maar je wilt waarschijnlijk dat de increments van de counter vanuit verschillende threads geen rare effecten heeft.

De increment is geen atomaire operatie: het is een samenstelling van een GETFIELD, ICONST_1, IADD en PUTFIELD. De laatste PUTFIELD kan er voor zorgen dat een aanpassing die ondertussen door een andere thread gedaan is verloren gaat.
Overigens, het feit dat het meerdere bytecodes zijn hoeft niet te betekenen dat het ook meerdere assembly instructies worden. Een VM hoeft alleen het formeel waarneembare effect te produceren.

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 =-

Verwijderd schreef op zondag 29 mei 2005 @ 20:13:
[...]
Maar goed het is dus niet threadsafe, jammerlijk. Dus dergelijke simpele dingen hebben dus helaas sunchronisatie nodig...
Ik heb er zelf weinig problemen mee. Voor de enkele keer dat ik threadsafe met primitives om wil gaan kan je gebruik maken van de nieuwe Atomic classes (AtomicInteger, AtomicBoolean etc). Maar synchroniseren doe ik meestal op hoger nivo en het zijn meestal een aantal resources die ik synchroniseer. Daarvoor vind ik het niet erg dat de resources niet atomic zijn. Ik gebruik bv ook nauwelijks HashTables,Vectors of de Collections.synchronized wrappers. En verder kan een beetje non-determinisme het leven mbt concurrency ook veel en veel eenvoudiger maken (en sneller).

[ Voor 17% gewijzigd door Alarmnummer op 29-05-2005 22:15 ]


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Alarmnummer: Voor de enkele keer dat ik threadsafe met primitives om wil gaan kan je gebruik maken van de nieuwe Atomic classes (AtomicInteger, AtomicBoolean etc).
Goed punt, ik was vergeten om te zeggen dat die klassen al standaard methoden aanbieden om een atomaire increment of decrement te doen (in ++i en i++ variant).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


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

Alarmnummer

-= Tja =-

MSalters schreef op zondag 29 mei 2005 @ 17:52:
Welke processor? Threadsafe in Java moet je zien als threadsafe volgens de specificatie, niet alleen als "threadsafe op de 1.4.1 Sun JVM voor x86".
Was het maar zo. Van cpu tot cpu, van os tot os zijn er wel degelijk grote verschillen tussen implementaties mbt threading. Kijk bv naar de verschillen in thread prioriteiten. Onder windows is minder variatie in threadprioriteiten beschikbaar, dan de api je doet denken. Als je denkt dat je 2 threads met verschillende prioriteiten hebt gemaakt, kan het gerust zijn dat er onder windows geen onderscheid tussen wordt gemaakt en windows ze ziet als 2 gelijkwaardige threads.

Java = zeker geen echte WORA... in de praktijk zullen de meeste mensen er geen last van hebben en niet het onderste uit de kant halen. Maar als je dat wel wilt doen, dan zul je toch rekening moeten houden met de specificaties van het os/cpu.

[ Voor 4% gewijzigd door Alarmnummer op 29-05-2005 22:23 ]


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Alarmnummer: Kijk bv naar de verschillen in thread prioriteiten ...
Gelukkig zijn de mogelijkheden tot deze verschillen wel onderdeel van de specificatie. Het gaat bij zulke vragen dus altijd om de specificatie, en niet om een specifiek platform. Zolang je aan de specificatie voldoet (in dit geval: volgens de specificatie atomair of niet), mag je er vanuit gaan dat dit ook op alle platformen geldt. Dat er toch nog platformspecifieke verschillen zijn is dus onderdeel van de specificatie.

Maar ja, dat maakt het punt wat je aansnijdt natuurlijk niet minder vervelend ;)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


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

Alarmnummer

-= Tja =-

mbravenboer schreef op zondag 29 mei 2005 @ 22:28:
[...]

Gelukkig zijn de mogelijkheden tot deze verschillen wel onderdeel van de specificatie.
Yep.. maar het staat niet in de Javadoc (dingen die de meeste developers alleen maar lezen). Ik geloof dat ik het ergens in "Concurrent Programming in Java" heb. Maarja.. dit is (vreemd genoeg) ook geen standaard kost voor de meeste java developers...

[edit]
Zeker voor developers die niet regelmatig met concurrency werken, kan dit 'vreemde' situaties opleveren. Ik wil Java trouwens hierdoor niet bestempelen als slecht... alleen dat je niet de indruk moet hebben dat je echt een WORA app aan het schrijven bent.

[ Voor 30% gewijzigd door Alarmnummer op 29-05-2005 22:56 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Alarmnummer schreef op zondag 29 mei 2005 @ 22:22:
[MSalters schreef op zondag 29 mei 2005 @ 17:52:
Welke processor? Threadsafe in Java moet je zien als threadsafe volgens de specificatie, niet alleen als "threadsafe op de 1.4.1 Sun JVM voor x86".]

Was het maar zo. Van cpu tot cpu, van os tot os zijn er wel degelijk grote verschillen tussen implementaties mbt threading. Kijk bv naar de verschillen in thread prioriteiten. Onder windows is minder variatie in threadprioriteiten beschikbaar, dan de api je doet denken. Als je denkt dat je 2 threads met verschillende prioriteiten hebt gemaakt, kan het gerust zijn dat er onder windows geen onderscheid tussen wordt gemaakt en windows ze ziet als 2 gelijkwaardige threads.

Java = zeker geen echte WORA... in de praktijk zullen de meeste mensen er geen last van hebben en niet het onderste uit de kant halen. Maar als je dat wel wilt doen, dan zul je toch rekening moeten houden met de specificaties van het os/cpu.
Is de specificatie zo slecht? Als het goed is, dan stelt de specificatie wat threadsafe is, en implementeert elk platform dat. Het enige verschil is dan dat sommige JVMs constructies hebben die in de praktijk threadsafe zijn , maar niet volgens de specificatie.

Priorities zijn op een niet-RTOS hooguit een hint, en dus is zo'n gedrag als je beschrijft niet fout. Ja, je kunt je iets aantrekken van os/cpu/vm, en non-portable code schrijven. In die zin kun je dus threadsafe code voor de 1.4.1 JVM @x86 schrijven. Ik stel dus dat dat geen threadsafe Java(TM) is.

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 30 mei 2005 @ 08:07:
[...]

Is de specificatie zo slecht? Als het goed is, dan stelt de specificatie wat threadsafe is, en implementeert elk platform dat.
Soms is het niet mogelijk. Windows heeft bv te weinig prioriteiten en dan kan een vm hoog en laag springen, maar het houd dan op.
Het enige verschil is dan dat sommige JVMs constructies hebben die in de praktijk threadsafe zijn , maar niet volgens de specificatie.
Nou klinkt het ook wel heel erg.. Het is niet dat je allerlei raceproblemen krijgt ;)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Alarmnummer schreef op maandag 30 mei 2005 @ 08:34:
Soms is het niet mogelijk. Windows heeft bv te weinig prioriteiten en dan kan een vm hoog en laag springen, maar het houd dan op.
Da's natuurlijk onzin. Een VM moet gewoon zelf doen wat het OS niet doet. Concreet: je moet een thread dispatcher gebriken, die voor elke Windows prioriteit weet welke Java threads op die prioriteit draaien. Vervolgens moet je als een Windows thread op een van die Windows prioriteiten becschikbaar komt zelf de hoogste Java prioriteit uitzoeken.

vb Windows heeft prio 0,10,20 en Java heeft 0...31. Dan moet je alle Java prio's 0-9 mappen naar Windows prio 0. Als er dan een Windows thread @ prio 0 unblockt, dan run je eerst de Java prio 9 threads, dan 8, etc.

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 =-

Nou nou nou..
Een VM moet gewoon zelf doen wat het OS niet doet. Concreet: je moet een thread dispatcher gebriken, die voor elke Windows prioriteit weet welke Java threads op die prioriteit draaien. Vervolgens moet je als een Windows thread op een van die Windows prioriteiten becschikbaar komt zelf de hoogste Java prioriteit uitzoeken.
Java heeft 10 prioriteiten en windows 7 geloof ik.
vb Windows heeft prio 0,10,20 en Java heeft 0...31. Dan moet je alle Java prio's 0-9 mappen naar Windows prio 0. Als er dan een Windows thread @ prio 0 unblockt, dan run je eerst de Java prio 9 threads, dan 8, etc.
Schrijf een brief naar Sun zou ik zeggen ;)

  • CubicQ
  • Registratie: September 1999
  • Laatst online: 22:50
Maar dan ga je weer richting Green threads, en dat is volgens mij nou net iets waar Sun vandaan probeert te komen met de nieuwere JDK's.

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Met volatile bereik je inderdaad geen threadsafety. De enige manier om dat te doen is met één van de synchronisatie mechanismes in Java. Volatile is een gevaarlijk keyword omdat de praktische waarde meestal beperkt is, en de impact op performance vrij hoog kan zijn.

Interessant detail aan dit voorbeeld is ook dat het volatile keyword pas in Java 5 gefixed is, en daarvoor op de meeste Sun VM's niet helemaal correct werkte.

Verwijderd

Wat mischien ook nog op te merken valt, is dat in java (in tegenstelling tot bijvoorbeeld C++) een enkele assignment wel atomair is (behalve als het om floats of doubles gaat).

Java:
1
int a = 257;


In C++ -kan- het voorkomen dat er midden in de assignment geswitched wordt. Op een 8 bitter zou je heel even een 1 erin hebben, en dan pas de volgende cycle de 257.

Volgens de java language specification is een dergelijke assignment dus altijd atomair.

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 05-05 14:48
Verwijderd schreef op woensdag 01 juni 2005 @ 11:02:
Wat mischien ook nog op te merken valt, is dat in java (in tegenstelling tot bijvoorbeeld C++) een enkele assignment wel atomair is (behalve als het om floats of doubles gaat).

Java:
1
int a = 257;


In C++ -kan- het voorkomen dat er midden in de assignment geswitched wordt. Op een 8 bitter zou je heel even een 1 erin hebben, en dan pas de volgende cycle de 257.

Volgens de java language specification is een dergelijke assignment dus altijd atomair.
Dit is inderdaad zo volgens de Java spec (naast floats en doubles zijn ook long assignments niet atomic trouwens).

Hierbij moet je wel het volgende in de gaten houden:

Myth 3 op http://www-106.ibm.com/de.../it-1001art24/?dwzone=ibm

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

Alarmnummer

-= Tja =-

Verwijderd schreef op woensdag 01 juni 2005 @ 11:02:
Volgens de java language specification is een dergelijke assignment dus altijd atomair.
Ik geloof het niet. Bij longs en doubles kan het misgaan en die moet je dus ook al afschermen (van floats weet ik het niet). Object references die worden wel altijd atomair gezet.

Verwijderd

Alarmnummer schreef op woensdag 01 juni 2005 @ 13:20:
[...]

Ik geloof het niet. Bij longs en doubles kan het misgaan en die moet je dus ook al afschermen
Ik bedoelde inderdaad longs en doubles ipv doubles en floats...

De standaard zegt er in sectie 17.7 het volgende over.

Samengevat: writes naar longs en doubles (64bit) zijn niet perse atomic, behalve als je ze volatile declared.
Some implementations may find it convenient to divide a single write action
on a 64-bit long or double value into two write actions on adjacent 32 bit values.
For efficiency's sake, this behavior is implementation specific; Java virtual
machines are free to perform writes to long and double values atomically or in two
parts.
For the purposes of the Java programming language memory model, a single
write to a non-volatile long or double value is treated as two separate writes: one
to each 32-bit half. This can result in a situation where a thread sees the first 32
bits of a 64 bit value from one write, and the second 32 bits from another write.
Writes and reads of volatile long and double values are always atomic. Writes to
and reads of references are always atomic, regardless of whether they are imple-
mented as 32 or 64 bit values.
VM implementors are encouraged to avoid splitting their 64-bit values where
possible. Programmers are encouraged to declare shared 64-bit values as volatile
or synchronize their programs correctly to avoid possible complications

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 05-05 14:48
Maar je hebt er niks extra's aan ten opzichte van b.v. C++, omdat een JVM dus een "private working memory" per thread kan gebruiken zoals in dat artikel staat.

Verwijderd

icm volatile heb je wel wat aan de atomaire acties. Tevens heb je de garantie dat je geen corrupte waarde krijgt. Een waarde kan alleen stale zijn, dat is jammer maar niet in elke situatie een ramp. Als je namelijk een race condition hebt, dan had de andere thread net zo goed later kunnen zijn en was de waarde wel correct.

Moet de waarde echt globaal uniek zijn, dan kun je dus volatile of synchronized toepassen. C++ kent ook volatile. Deze doet grotendeels hetzelfde als in java; je gebruikt de global memory versie en niet een thread local of een register versie. Echter, omdat in C++ de access niet atomair is, is deze veel minder bruikbaar.
Pagina: 1