[disc/java] concurrency control instinker

Pagina: 1 2 Laatste
Acties:
  • 362 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Creepy schreef op maandag 21 augustus 2006 @ 21:12:
eeh.. is dat je volledige object of is de value van MyInt nog ergens uit te lezen of heeft MyInt nog meer methods?
Dit is alle code. En er gaat ook niet stiekum bytecode gemodificeerd worden.
Want met alleen bovenstaande code zou ik ook geneigd zijn om te zeggen dat MyInt threadsafe is.
Helemaal begrijpelijk. Ik zet je ook bij het lijsjtje.
Zodra de value te wijzigen is dan is het niet meer threadsafe omdat je in een thread dezelfde MyInt bij elkaar op kan tellen en de uitkomst dan niet 2 x de waarde van MyInt hoeft te zijn omdat een andere thread tussendoor value veranderde.
value kan niet gewijzigd worden. Het is immutable.

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 19:26

RayNbow

Kirika <3

Alarmnummer schreef op maandag 21 augustus 2006 @ 21:15:
[...]
value kan niet gewijzigd worden. Het is immutable.
En met reflectie? :+

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 09:28
Aangezien je het vraagt, zal het wel niet threadsafe zijn, alhoewel het er toch thread-safe uitziet.
Ik zou eigenlijk niet inzien waarom het niet thread-safe zou zijn; de member krijgt een value dmv de constructor en kan nadien niet meer gewijzigd worden.

Met Creepy en MSalters dus: threadsafe.

Maareh, doet het er iets toe dat die code in Java is, of kan je hetzelfde aantonen in gelijk welke andere OO taal ?

[ Voor 16% gewijzigd door whoami op 21-08-2006 21:32 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Na maanden afwezigheid op dit forum, gok ik op niet thread safe :P (nouja, het is geen gok...)

[ Voor 17% gewijzigd door Zoijar op 21-08-2006 21:31 ]


Acties:
  • 0 Henk 'm!

  • bloody
  • Registratie: Juni 1999
  • Laatst online: 20:27

bloody

0.000 KB!!

smarty ;) Volgens mij bedoelt TS dat geen reflection gebruikt hoeft te worden.
Zoijar schreef op maandag 21 augustus 2006 @ 21:30:
...gok ik op niet thread safe :P (nouja, het is geen gok...)
Verklaar u nader :9

nope


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ook niet. Er gaat dus niets vies met dit object uitgehaald worden.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
whoami schreef op maandag 21 augustus 2006 @ 21:29:
Maareh, doet het er iets toe dat die code in Java is, of kan je hetzelfde aantonen in gelijk welke andere OO taal ?
Daar kan ik je eigelijk geen antwoord op geven. Ik kom straks wel op de terminologie en dan kun je ook kijken of .net daar bv last van heeft.

Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Dit moet wel thread safe zijn, aangezien er alleen via de constructor een waarde toegekend wordt aan de private variabele.

Iedere thread heeft dus per definitie een eigen instance.

Conclusie: thread safe

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Little Penguin schreef op maandag 21 augustus 2006 @ 21:37:
Dit moet wel thread safe zijn, aangezien er alleen via de constructor een waarde toegekend wordt aan de private variabele.

Iedere thread heeft dus per definitie een eigen instance.

Conclusie: thread safe
De instantie kan uiteraard wel gedeeld worden tussen meerdere threads. Daar gaat het hier ook om.

Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
De instantie kan uiteraard wel gedeeld worden tussen meerdere threads. Daar gaat het hier ook om.
Oeps, ja daar heb je gelijk in - even over het hoofd gezien.

Maar ook dan blijft het code die volgens mij thread safe is, het is namelijk niet mogelijk om de waarde in MyInt te lezen of te overschrijven. -> nog steeds dezelfde conclusie dus.

Ik durf nog een stapje verder te gaan:
Zelfs al is er een getter, dan blijft deze code thread safe.

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:17
Is het niet zo dat in java de member variabelen vanuit een subclass direct beschikbaar zijn? In dit geval kan je er natuurlijk wel getters en setters om heen klussen, maar ik weet niet of subclasses togestaan waren...

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Ik zou zelf ook gokken op thread-safe. Als ik deze code zou zien zou ik er normaal gesproken iig geen vraagtekens bij zetten ivm concurrency. Maar aangezien het hier om een instinker gaat zal het waarschijnlijk niet zo zijn ;) Als ik dan een oorzaak zou moeten vinden zit ikte denken aan boxing/unboxing wat voor verassingen zorgt (gokkerdegeok).

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Orphix schreef op maandag 21 augustus 2006 @ 21:56:
Ik zou zelf ook gokken op thread-safe. Als ik deze code zou zien zou ik er normaal gesproken iig geen vraagtekens bij zetten ivm concurrency. Maar aangezien het hier om een instinker gaat zal het waarschijnlijk niet zo zijn ;) Als ik dan een oorzaak zou moeten vinden zit ikte denken aan boxing/unboxing wat voor verassingen zorgt (gokkerdegeok).
Java kent toch geen boxing?
Of zeg ik nu wat doms...

On-topic: mij lijkt de code ook thread-safe. De enige manier om de state van het object te bepalen is via de constructor, na construction kan het object niet meer gewijzigd worden en is het dus immutable. Immutable objecten zijn bij mijn weten per definitie thread-safe en reentrant.

[ Voor 21% gewijzigd door MrBucket op 21-08-2006 22:00 ]


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
sig69 schreef op maandag 21 augustus 2006 @ 21:56:
Is het niet zo dat in java de member variabelen vanuit een subclass direct beschikbaar zijn? In dit geval kan je er natuurlijk wel getters en setters om heen klussen, maar ik weet niet of subclasses togestaan waren...
We gaan ook geen subclassen maken. Daar hoef je de boosdoener ook niet te zoeken.

Acties:
  • 0 Henk 'm!

  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

MrBucket schreef op maandag 21 augustus 2006 @ 21:58:
[...]

Java kent toch geen boxing?
Of zeg ik nu wat doms...
Nee, je leeft nog in pre java 5 ;)
Maar goed, dat gaat volgens mij alleen op voor bepaalde typen.

Zelf zou ik NU ook op thread-safe gokken, maar aangezien het hier om een instinker gaat, zal dat het w.s. niet zijn ;) Of het is een dubbele instinker waarbij we gewoon allemaal aan het overanalyseren zijn ;)

[ Voor 38% gewijzigd door prototype op 21-08-2006 22:01 ]


Acties:
  • 0 Henk 'm!

  • CubicQ
  • Registratie: September 1999
  • Laatst online: 20:39
Gezien de vraagstelling en de titel zal het antwoord wel niet thread safe zijn, maar ik zie het niet...

Heeft het misschien iets te maken met reordening en JSR 133? (dus dat in bepaalde situaties eerst de value geschreven wordt voordat de this aangepast wordt bij het aanroepen van de constructor)

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Orphix schreef op maandag 21 augustus 2006 @ 21:56:
Ik zou zelf ook gokken op thread-safe. Als ik deze code zou zien zou ik er normaal gesproken iig geen vraagtekens bij zetten ivm concurrency. Maar aangezien het hier om een instinker gaat zal het waarschijnlijk niet zo zijn ;) Als ik dan een oorzaak zou moeten vinden zit ikte denken aan boxing/unboxing wat voor verassingen zorgt (gokkerdegeok).
Ik heb je naam er bij gezet en je hoeft daar de oorzaak ook niet te zoeken.

Met deze code hoeft niet speciaals gedaan te worden.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
CubicQ schreef op maandag 21 augustus 2006 @ 22:00:
Gezien de vraagstelling en de titel zal het antwoord wel niet thread safe zijn, maar ik zie het niet...

Heeft het misschien iets te maken met reordening en JSR 133? (dus dat in bepaalde situaties eerst de value geschreven wordt voordat de this aangepast wordt bij het aanroepen van de constructor)
Bingo :)

Acties:
  • 0 Henk 'm!

  • CubicQ
  • Registratie: September 1999
  • Laatst online: 20:39
Nou niet gaan denken dat ik het 'normaal gesproken' zou zien hoor :) Maar een beetje Googlen op 'concurrency java constructor' levert alleen dit op :)

Is dit probleem eigenlijk op te lossen door this. weg te laten, of wordt er dan impliciet weer this. voorgezet?

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ikke niet snappe nie... 8)7

Kan je misschien wat meer uitleg geven over wat er dan precies verkeerd gaat?

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Wil jij een poging wagen cubicq?

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
CubicQ schreef op maandag 21 augustus 2006 @ 22:02:
[...]

Nou niet gaan denken dat ik het 'normaal gesproken' zou zien hoor :) Maar een beetje Googlen op 'concurrency java constructor' levert alleen dit op :)

Is dit probleem eigenlijk op te lossen door this. weg te laten, of wordt er dan impliciet weer this. voorgezet?
Het probleem zit hem niet in de this.

De volgende code zou namelijk net zo hard op zijn gat gaan.
code:
1
2
3
4
5
6
7
public class MyInt{
    private int _value;
    
    public MyInt(int value){
        _value = value;
    }
}


Zal ik de uitleg geven?

Acties:
  • 0 Henk 'm!

  • CubicQ
  • Registratie: September 1999
  • Laatst online: 20:39
Is goed. Ik zal deze post wel editen, ik denk dat het wel een tijdje duurt voordat ik enigzins helder heb opgeschreven wat er zou kunnen gebeuren denk ik.

De pagina waar ik het idee vandaan heb is trouwens http://www.cs.umd.edu/~pu...oryModel/jsr-133-faq.html

Edit:
Een JVM voert allerlei optimalisaties uit om ervoor te zorgen dat de code sneller wordt uitgevoerd. Een van die optimalisaties is code reordening: het naar voren halen of het naar achteren plaatsen van instructies.

In (sommige? alle? huidige?) implementaties van de JVM was/is het zo (en laat de Java standaard toe) dat het wegschrijven van de int te vroeg / te laat gebeurt (Alarmnummer, weet jij de details hiervan?)

Eigenlijk is dit dus geen bug in de Java code, maar gewoon een bug in de Java spec.
Zal ik de uitleg geven?
Graag

[ Voor 52% gewijzigd door CubicQ op 21-08-2006 22:16 . Reden: Uitleg toegevoegd ]


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

I could tell you... but... well, you know.. the usual, killing and stuff ;)

Het is wel iets dat iedereen zou moeten weten eigenlijk. Helemaal omdat velen deze code gebruiken in een andere vorm.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
CubicQ schreef op maandag 21 augustus 2006 @ 22:06:
Is goed. Ik zal deze post wel editen, ik denk dat het wel een tijdje duurt voordat ik enigzins helder heb opgeschreven wat er zou kunnen gebeuren denk ik.

De pagina waar ik het idee vandaan heb is trouwens http://www.cs.umd.edu/~pu...oryModel/jsr-133-faq.html
De goeie plek :)

Ok. Het is een vm toegestaan om instructies (bytecode) te gaan reordenen omdat processors hier vaak performance winst mee kunnen halen. Stel dit is de orginele bytecode:

code:
1
2
3
4
5
6
7
8
//maakt een niet geinitialiseerde versie van 
//MyInt aan. value staat nu op 0 omdat de default 
//value van een int 0 is.
mem = maak-instantie(MyInt)                                             
//roep nu de constructor aan met 21
constructor-call(mem, 21)      
//wijs het geheugen toe aan een globaal veld
globaalveld = mem


Stel dat 1 thread dit aanroept, en een andere thread leest globaal veld uit, dan zou het null kunnen zien (dus de 2e thread die leest komt voor de uitvoering van de laatste instructie door thread1 aan beurt) of hij leest een MyInt met value 21 uit (nadat de laatste instructie door thread1 is uitgevoerd)

Het is toegestaan voor een vm dus om instructies te gaan rewriten en een mogelijke reordening zou zijn:

code:
1
2
3
mem = maak-instantie(MyInt)
globaalveld = mem
constructor-call(mem,21)


Stel dat een 2e thread net voor de uitvoering van de laatste instructie door de 1e thread dat globaal veld uitleest, dan zou het een instantie van MyInt kunnen zien waarvan de constructor nog niet is aangeroepen, het zou dus een MyInt(0) kunnen zien ipv een MyInt(21)

2e oorzaak:
Je zult misschien denken: ok, dat is maar een fractie van de tijd waarop het fout zou kunnen gaan. Alhoewel dit imho geen goed concurrency control is, is het probleem nog groter dan je zou denken.

Dit heeft te maken met het memory model van java. Als je een normaal veld hebt (dus niet volatile, final of gebruikt in een gesynchroniseerde context) dan is de vm niet verplicht om de waarde die erin geschreven gaat worden ook direct naar main memory te sturen. Processors hebben tegenwoordig meerde lagen van cache aan boord en het is veel goedkoper om daar uit te lezen en naar toe te schrijven).

Stel dat we meerdere cpu's hebben (bv multicores) en dat iedere cpu zijn eigen cache heeft.

Stel nu dat thread 1 net het aangemaakt object (waarvan de constructor nog aangeroepen moet worden) naar main memory heeft geschreven. Stel nu dat thread2 direct daarna the value hiervan uitleest (die waarde is 0). Deze waarde zou hij in zijn cache mogen plaatsen (dit zou een cache op een andere cpu kunnen zijn). Stel dat daarna de constructor door thread 1 wordt aangeroepen zodat die waarde:21 in main memory komt te staan, dan is er geen reden voor thread 2 om nu ineens een nieuwe waarde voor value uit te gaan lezen want hij heeft zijn 0 waarde nog mooi in de cache staan. Hij ziet die waarde dus niet en de kans bestaat ook dat hij hem nooit zal zien.

Een andere variant op het laatste probleem:
ook de writes hoeven niet direct geflusht te worden naar main memory. Dus die write van 21 binnen de constructor hoeft ook niet naar main memory geflust te worden. Dus ook al zou thread2 altijd netjes uit main memory lezen ipv cache, dan zou hij die nieuwe waarde nooit hoeven te zien.

Zoals je kunt zien is het allemaal vrij tricky en moet je goed weten wat je moet doen als je bezig bent met concurrency control. Het probleem zou trouwens eenvoudig gefixt kunnen worden door het final te maken. Door het veld final te maken zijn niet allerlei reordening meer mogelijk maar hier ben ik nog niet volledig in thuis (ben op dit moment bezig om de materie te bestuderen).
stel dat

Stel dat thread 2 het niet uitgeconstrueerde object heeft uitgelezen en ook het value veld.

[ Voor 5% gewijzigd door Alarmnummer op 21-08-2006 22:34 ]


Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Ik snap het ook niet, ik heb 2 stukjes t.o.v. JSR gelezen - die op IBM.com -> http://www-128.ibm.com/de...tml?ca=dgr-lnxw16FixJMMP1

Het enige dat ik dan kan verzinnen is het feit dat als er twee keer geprobeerd wordt deze class te instantieren de variabele die in 'this' staat niet de juiste hoeft te zijn (en dan maakt het vgls mij ook niet uit of je 'm niet weg haalt of niet - bij het weghalen wordt natuurlijk wel ff de private member hernoemt zodat this ook echt niet nodig is)

Maar dat betekent dat er in Java een knoert van een ontwerpfout zit - na het lezen van de JSR133 heb ik begrepen dat dit dus ook zo is.

Als ik in het dagelijks werk (ook programmeer ook regelmatig in Java :)) hier problemen mee zou krijgen dan zou ik er dus echt 100% overheen blijven lezen - hetgeen volgens mij ook niet verwonderlijk is omdat het ook enigszins een bug in het JMM blijkt te zijn...

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Little Penguin schreef op maandag 21 augustus 2006 @ 22:31:
Maar dat betekent dat er in Java een knoert van een ontwerpfout zit - na het lezen van de JSR133 heb ik begrepen dat dit dus ook zo is.
Ook in C++. Maar daar ligt de fout bij de programmeur, want C++ doet geen enkele claim mbt threads. Maar dus wel in veel C++ applicaties...

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

* Creepy snapt het nog steeds niet.

Over oorzaak 1: reordening mag alleen zo plaatsvinden dat het binnen 1 thread moet lijken alsof er geen reordening plaats vindt. Als dit niet het geval is dan lijkt me dat een enorme bug in Java en geen normaal concurreny probleem meer.

Over oorzaak 2: CPU2 kan de value niet uitlezen want die is niet uit te lezen. En ik kan me a.t.m. ook niet voorstellen hoe thread 1 een MyInt kan aanmaken die voordat de constructor is afgelopen aan thread2 wordt meegegeven zodat thread 2 een eventueel niet geheel geinitialiseerde instantie heeft.

Edit: als value nu static zou zijn of this wordt in de constructor naar buiten gebracht dan volg ik het wel (zie bijv. http://www-128.ibm.com/de.../library/j-jtp0618.html#2)

[ Voor 14% gewijzigd door Creepy op 21-08-2006 22:41 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Little Penguin schreef op maandag 21 augustus 2006 @ 22:31:
Ik snap het ook niet, ik heb 2 stukjes t.o.v. JSR gelezen - die op IBM.com -> http://www-128.ibm.com/de...tml?ca=dgr-lnxw16FixJMMP1

Het enige dat ik dan kan verzinnen is het feit dat als er twee keer geprobeerd wordt deze class te instantieren de variabele die in 'this' staat niet de juiste hoeft te zijn (en dan maakt het vgls mij ook niet uit of je 'm niet weg haalt of niet - bij het weghalen wordt natuurlijk wel ff de private member hernoemt zodat this ook echt niet nodig is)

Maar dat betekent dat er in Java een knoert van een ontwerpfout zit - na het lezen van de JSR133 heb ik begrepen dat dit dus ook zo is.

Als ik in het dagelijks werk (ook programmeer ook regelmatig in Java :)) hier problemen mee zou krijgen dan zou ik er dus echt 100% overheen blijven lezen - hetgeen volgens mij ook niet verwonderlijk is omdat het ook enigszins een bug in het JMM blijkt te zijn...
Het is niet zozeer een bug. Als jij volledig serializable gedrag wilt hebben tussen alle threads, zal je een extreem trage vm krijgen. De snelheid winst zit hem in het feit dat een cpu er mee mag goochelen. Binnen een enkele thread zie je er niets van alleen tussen verschillende threads moet je hier rekening mee houden. Je moet het zo zien:

als velden in een multithreaded context worden gebruikt dan moeten ze:
-final zijn
-volatile zijn
-gebruikt worden in een gesynchroniseerde context

De rest is fout.

En daarbij kom ik dus ook aan bij mijn volgende punt. Wat je ziet bij veel componenten is dat er vaak gebruikt wordt gemaakt van setters ipv constructors en dat de velden niet voldoen aan een van de bovenstaande eigenschappen. Dus al die objecten zijn dus niet threadsafe :) Objecten die wel een constructor hebben en die niet voldoen aan bovenstaande eigenschappen zijn dus ook niet threadsafe, maar ik maak velden zelf altijd final zodat ik mijn class invarianten kan garanderen en dat je dus ook niet met dit soort ellende in aanraking kom. Daarom geef ik ook nog steeds de voorkeur van constructors boven setters.

Acties:
  • 0 Henk 'm!

Verwijderd

Ik ga bij mijn reply even ervan uit dat JSR133 geimplementeerd is, voor het gemak draait het dus onder een 1.5 JVM. Dit is allemaal voor zover ik weet, als ik grote fouten maak, verbeter me dan, dan leer ik er ook nog van.
Alarmnummer schreef op maandag 21 augustus 2006 @ 22:27:
[...]

Stel dat een 2e thread net voor de uitvoering van de laatste instructie door de 1e thread dat globaal veld uitleest, dan zou het een instantie van MyInt kunnen zien waarvan de constructor nog niet is aangeroepen, het zou dus een MyInt(0) kunnen zien ipv een MyInt(21)
Nope, want onder de java memory model specificaties is een object altijd gegarandeerd volledig geinitialiseerd als de constructor returnt, en mogen er geen references zijn zolang dat niet zo is (tenzij je ze zelf lekt).
Dit heeft te maken met het memory model van java. Als je een normaal veld hebt (dus niet volatile, final of gebruikt in een gesynchroniseerde context) dan is de vm niet verplicht om de waarde die erin geschreven gaat worden ook direct naar main memory te sturen. Processors hebben tegenwoordig meerde lagen van cache aan boord en het is veel goedkoper om daar uit te lezen en naar toe te schrijven).
De waarde hoeft inderdaad niet direct in het veld te staan, maar bij het voorbeeld is dat geen probleem, er is geen functie die afhankelijk is van het veld, het object is niet Serializable, de waarde is niet eens opvraagbaar (tenzij je heel moeilijk gaat doen, maar dat was al uitgesloten in de vraagstelling)

Het enige punt is dat methodes van Object afhankelijk kunnen zijn van de waarde. Een verdachte is hashCode, die normaalgesproken het interne adres omzet in een integer waarde. Dit is echter niet gegarandeerd, dus heel misschien zou een JVM speciale implementatie van hashCode afhankelijk kunnen zijn van het value veld dat nog niet visible voor is die thread (ik weet niet zeker of het 'general contract' van hashCode wordt overtreden als de default implementatie van waarde verandert als een member dat doet, dus of het uberhaupt toegestaan om die waarde invloed te laten hebben)

[edit] wat voorbehoud bij hashCode toegevoegd

[ Voor 6% gewijzigd door Verwijderd op 21-08-2006 22:48 ]


Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Creepy schreef op maandag 21 augustus 2006 @ 22:38:
* Creepy snapt het nog steeds niet.

Edit: als value nu static zou zijn of this wordt in de constructor naar buiten gebracht dan volg ik het wel (zie bijv. http://www-128.ibm.com/de.../library/j-jtp0618.html#2)
Zo als ik het begreep uit het artikel bij IBM (het .edu linkje verwijst naar hetzelfde artikel zag ik) en de uitleg in deze thread is het dus zo dat the 'this' variable in de constructor mogelijk door een andere thread gelezen kan worden en ook gebruikt kan worden dmv de reordering. In zekere zijn wordt deze dan ook buiten de class om gebruikt.

Het blijft een lastige materie, zeker omdat de bytecode compiler achteraf nog bepaalde wijzigingen door gaat voeren.

Wat ik me wel af vraag is in hoeverre de MS-CLR/.net omgeving hier last van heeft - want als je de code accademisch bekijkt (dus zonder de JVM implementatie ernaast) ga je er vanuit dat deze code thread-safe is (ik ging er in elk geval wel vanuit)

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Creepy schreef op maandag 21 augustus 2006 @ 22:38:
* Creepy snapt het nog steeds niet.

Over oorzaak 1: reordening mag alleen zo plaatsvinden dat het binnen 1 thread moet lijken alsof er geen reordening plaats vindt. Als dit niet het geval is dan lijkt me dat een enorme bug in Java en geen normaal concurreny probleem meer.
Thread 1 ziet toch niet dat die instructies omgewisseld zijn.

a = MyInt(23)
int b = a.getValue();// (ff een getter erbij verzonnen).

Dan zal b nog steeds 23 zijn. Alle instructies mogen gereordened worden zo lang de reordening maar niet zichtbaar is binnen een enkele thread. Dat een andere thread er hinder van ondervind is voor de vm geen probleem.

check het volgende eens:

code:
1
2
3
4
5
6
7
8
9
10
11
int a = 0;
int b = 0;

void print(){
    System.out.println("a = "+a"+" b="+b);
}

void inc(){
   a=1
   b=1;
}


STel dat thread1 print aanroept, en thread2 inc. Wat zou alle mogelijke output zijn die je zou zien?

a=0 b=0
a=1 b=0
a=1 b=1

Of zou je nog meer kunnen zien? Reorden die a=1 en b=1 maar eens (dat zal voor thread2 worst zijn).

Je zou dan ook nog een
a=0 b=1
kunnen zien :)

[code]
Over oorzaak 2: CPU2 kan de value niet uitlezen want die is niet uit te lezen.
[/quote]
Why not? default aangemaakt object staat netjes in main memory. constructor moet alleen nog aangeroepen worden. En op dit niet geinitialiseerde object (met value = 0, want dat is de default voor een int) zou gerust de getValue aangeroepen worden.


Oeps.. ik zie het.. Ik had er ff een getter bij moeten maken.


code:
1
 En ik kan me a.t.m. ook niet voorstellen hoe thread 1 een MyInt kan aanmaken die voordat de constructor is afgelopen aan thread2 wordt meegegeven zodat thread 2 een eventueel niet geheel geinitialiseerde instantie heeft.


Dat kan :)

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

@Little Penguin: Aangezien this niet buiten de constructor wordt gelekt kan dat niet en is er geen probleem tenzij het een bug betreft in Java zelf. Ik zie dan ook niet in hoe de MyInt class niet threadsafe is aangezien de thread die een MyInt aanmaakt deze pas door kan geven nadat deze is aangemaakt (als de constructor klaar is dus).

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Alarmnummer schreef op maandag 21 augustus 2006 @ 22:41:
[...]
Het is niet zozeer een bug. Als jij volledig serializable gedrag wilt hebben tussen alle threads, zal je een extreem trage vm krijgen. De snelheid winst zit hem in het feit dat een cpu er mee mag goochelen. Binnen een enkele thread zie je er niets van alleen tussen verschillende threads moet je hier rekening mee houden. Je moet het zo zien:

als velden in een multithreaded context worden gebruikt dan moeten ze:
-final zijn
-volatile zijn
Maar kan ik dan kiezen tussen final of volatile? Als ik JSR-133 goed begrijp dan zou vanaf Java 1.5 volatile volstaan en moet je voor Java 1.5 final/volatile combineren - of zie ik dat verkeerd?
...maar ik maak velden zelf altijd final zodat ik mijn class invarianten kan garanderen en dat je dus ook niet met dit soort ellende in aanraking kom. Daarom geef ik ook nog steeds de voorkeur van constructors boven setters.
Begrijp ik het goed dat final variabelen ook nog te wijzigen zijn in de constructor? Want ik begrijp ze eigenlijk altijd als een static variabele dus:
Java:
1
public static int NAAM = 1;

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

Alarmnummer schreef op maandag 21 augustus 2006 @ 22:50:
[...]

Thread 1 ziet toch niet dat die instructies omgewisseld zijn.

a = MyInt(23)
int b = a.getValue();// (ff een getter erbij verzonnen).
Nu verzin je er toch een getter bij ;)
Dan zal b nog steeds 23 zijn. Alle instructies mogen gereordened worden zo lang de reordening maar niet zichtbaar is binnen een enkele thread. Dat een andere thread er hinder van ondervind is voor de vm geen probleem.

check het volgende eens:

code:
1
2
3
4
5
6
7
8
9
10
11
int a = 0;
int b = 0;

void print(){
    System.out.println("a = "+a"+" b="+b);
}

void inc(){
   a=1
   b=1;
}


STel dat thread1 print aanroept, en thread2 inc. Wat zou alle mogelijke output zijn die je zou zien?

a=0 b=0
a=1 b=0
a=1 b=1

Of zou je nog meer kunnen zien? Reorden die a=1 en b=1 maar eens (dat zal voor thread2 worst zijn).

Je zou dan ook nog een
a=0 b=1
kunnen zien :)
Helemaal mee eens. Alleen zie ik de link niet met MyInt?
[/quote]
Why not? default aangemaakt object staat netjes in main memory. constructor moet alleen nog aangeroepen worden. En op dit niet geinitialiseerde object (met value = 0, want dat is de default voor een int) zou gerust de getValue aangeroepen worden.

Oeps.. ik zie het.. Ik had er ff een getter bij moeten maken.
Wil je nu zeggen dat je MyInt niet threadsafe is tenzij je een getter erbij hebt?
Edit: ja dus :)
Dat kan :)
:)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

.. leuk die dubbelpostrechten :/ ...

[ Voor 96% gewijzigd door Creepy op 21-08-2006 22:56 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

Verwijderd

Alarmnummer schreef op maandag 21 augustus 2006 @ 22:50:
[...]

Thread 1 ziet toch niet dat die instructies omgewisseld zijn.
JSR133 heeft hiervoor initialization safety, het object is, als je niet in de constructor een reference lekt, gegarandeerd geinitialiseerd in elke reference, elk final veld heeft de waardes die gezet zijn in de constructor. Het veld value is niet final, maar is in het eerste voorbeeld nergens toegankelijk, dus is het geen probleem. Als er een getter bij gemaakt zou worden, is het probleem opgelost door het veld final of volatile te maken.

Acties:
  • 0 Henk 'm!

Verwijderd

Owja, zet mij maar in het rijtje threadsafe :P

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Verwijderd schreef op maandag 21 augustus 2006 @ 22:43:
Ik ga bij mijn reply even ervan uit dat JSR133 geimplementeerd is, voor het gemak draait het dus onder een 1.5 JVM. Dit is allemaal voor zover ik weet, als ik grote fouten maak, verbeter me dan, dan leer ik er ook nog van.
goeie instelling
Nope, want onder de java memory model specificaties is een object altijd gegarandeerd volledig geinitialiseerd als de constructor returnt, en mogen er geen references zijn zolang dat niet zo is (tenzij je ze zelf lekt).
Ik moet hiervoor de literatuur ff naslaan. Sinds jsr133 is er wel het een en ander veranderd, maar ik geloof dat een reordening van instructies hier ook nog steeds is toegestaan.

Ik ga deze vraag morgen ff op de concurrency mailing lijst plaatsen.
De waarde hoeft inderdaad niet direct in het veld te staan, maar bij het voorbeeld is dat geen probleem, er is geen functie die afhankelijk is van het veld
My bad..er had nog ff een getter bij gemoeten.
Het enige punt is dat methodes van Object afhankelijk kunnen zijn van de waarde. Een verdachte is hashCode, die normaalgesproken het interne adres omzet in een integer waarde. Dit is echter niet gegarandeerd, dus heel misschien zou een JVM speciale implementatie van hashCode afhankelijk kunnen zijn van het value veld dat nog niet visible voor is die thread (ik weet niet zeker of het 'general contract' van hashCode wordt overtreden als de default implementatie van waarde verandert als een member dat doet, dus of het uberhaupt toegestaan om die waarde invloed te laten hebben)

[edit] wat voorbehoud bij hashCode toegevoegd
Hier ga ik morgen nog even over nadenken. Ik ben gaar en ga zo mijn bed opzoeken.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Creepy schreef op maandag 21 augustus 2006 @ 22:56:
[...]

Nu verzin je er toch een getter bij ;)
My bad.. een getter had er wel ff bij gemoeten, maar doet verder geen afbraak aan het verhaal.
Helemaal mee eens. Alleen zie ik de link niet met MyInt?
Hier zie je dat instructie reordening is toegelaten zo lang het binnen een thread maar niet zichtbaar is. a=1,b=1 of b=1,a=1 zal voor thread2 worst zijn.. alleen kunnen andere threads hiervan wel nadelen ondervinden.

En dat is dus precies hetzelfde als met die MyInt en zijn 3 instructies die door 1 thread worden uitgevoerd. Binnen een enkele thread kan je de laatste 2 instructies zonder problemen omdraaien. Alleen heeft dit wel gevolgen voor andere threads.
Wil je nu zeggen dat je MyInt wel threadsafe is tenzij je een getter erbij hebt?
Nope. die getter was ff nodig zodat thread2 die waarde uit kan lezen. Die had er even bijgemoeten maar een getter zal hem het voorbeeld niet threadsafe maken.

Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
@Creepy: Over het lekker van de 'this' variable:
Zo als ik het net begreep (voornamelijk uit de uitleg in deze thread :) op GoT is het dus mogelijk dat 2 threads tegelijk de initialisatie doen en dat gedurende de constuctor fase dezelfde variabele gebruikt wordt om de tijdelijk referentie in op te slaan.

N.B. Als het dan inderdaad mogelijk is om via reordering deze variabele dubbel te gebruiken vind ik dat een grote ontwerpfout in Java - maar uit de documentatie op IBM.com over JSR-133 (waar ik dus al eerder naar verwees) begreep ik al dat er her en der zaken niet helemaal goed uitgewerkt zijn voor wat betrefd de toegang tot het geheugen...

Acties:
  • 0 Henk 'm!

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

met de kenis dat een veld die in een multithreaded omgeving gebruikt gaat worden altijd
-volatile
-final
-binnen een synchronized context staat
moet zijn, denk eens wat de gevolgen hiervan zijn van bekende frameworks. Welke frameworks, servers zijn vatbaar voor deze problemen? :) Mijn favoriete framework is Spring en ik wil zelf binnen Spring kijken of het ook vatbaar is, maar ik moet daarvoor eerst nog meer begrijpen over oa synchronisatie met main memory.

JSR133 kun je trouwens hier downloaden. Maar JSR133 is pas vanaf java 5 geintroduceerd in de vm, en ik heb op dit moment nog niet een goed beeld wat de verschillen tussen de oude en de nieuwe versie zijn. Wellicht dat ik in de toekomst nog meer hierover ga vermelden (voor de liefhebbers).

[ Voor 48% gewijzigd door Alarmnummer op 21-08-2006 23:15 ]


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Alarmnummer schreef op maandag 21 augustus 2006 @ 22:27:
Dit heeft te maken met het memory model van java. Als je een normaal veld hebt (dus niet volatile, final of gebruikt in een gesynchroniseerde context) dan is de vm niet verplicht om de waarde die erin geschreven gaat worden ook direct naar main memory te sturen. Processors hebben tegenwoordig meerde lagen van cache aan boord en het is veel goedkoper om daar uit te lezen en naar toe te schrijven).
Eh, die cache is automatisch en niet software-controlled, dus de VM kan dat helemaal niet kiezen.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
OlafvdSpek schreef op maandag 21 augustus 2006 @ 23:15:
[...]

Eh, die cache is automatisch en niet software-controlled, dus de VM kan dat helemaal niet kiezen.
Dat is niet correct.

Voor meer informatie zie Memory Barrier

[ Voor 3% gewijzigd door Alarmnummer op 21-08-2006 23:17 ]


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Alarmnummer schreef op maandag 21 augustus 2006 @ 23:16:
[...]

Dat is niet correct.

Voor meer informatie zie Memory Barrier
Heb je toevallig een voorbeeld van een CPU architectuur die stores out-of-order retired naar cache/memory? x86 doet het niet voor zover ik weet.

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

Little Penguin schreef op maandag 21 augustus 2006 @ 23:07:
@Creepy: Over het lekker van de 'this' variable:
Zo als ik het net begreep (voornamelijk uit de uitleg in deze thread :) op GoT is het dus mogelijk dat 2 threads tegelijk de initialisatie doen en dat gedurende de constuctor fase dezelfde variabele gebruikt wordt om de tijdelijk referentie in op te slaan.
Dat kan dus alleen als vanuit 1 thread de this buiten de constructor wordt gelekt. Ik zie dus niet in hoe zonder dat een tweede thread bij de constructor kan komen.

Ook met een getter zie ik a.t.m. nog niet in hoe de instantie gecreeert door thread 1 aan thread 2 doorgegeven kan worden voordat de constructor is afgelopen (met weer als voorwaarde dat this niet in de constructor naar buiten wordt gelekt).

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
OlafvdSpek schreef op maandag 21 augustus 2006 @ 23:20:
[...]

Heb je toevallig een voorbeeld van een CPU architectuur die stores out-of-order retired naar cache/memory? x86 doet het niet voor zover ik weet.
Nope (op hardware nivo weet ik er niet veel vanaf). Maar Java draait op erg veel platformen, dus wellicht dat een van de platformen dat op dit moment al doet. Het feit is dat de Java Memory Model dit dus toe laat, dus dit soort fouten zou je kunnen verwachten.

Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Alarmnummer schreef op maandag 21 augustus 2006 @ 23:29:
Nope (op hardware nivo weet ik er niet veel vanaf). Maar Java draait op erg veel platformen, dus wellicht dat een van de platformen dat op dit moment al doet. Het feit is dat de Java Memory Model dit dus toe laat, dus dit soort fouten zou je kunnen verwachten.
Dat klopt, maar het lijkt me veel logischer dat de compiler/VM die reordering doet.

Acties:
  • 0 Henk 'm!

  • bloody
  • Registratie: Juni 1999
  • Laatst online: 20:27

bloody

0.000 KB!!

Volgens mij is dit een relevant stukje uit de genoemde JSR:
Final fields must be used correctly to provide a guarantee of immutability. An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object’s final fields.

The usage model for final fields is a simple one. Set the final fields for an object in that object’s constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object’s constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object’s final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

nope


Acties:
  • 0 Henk 'm!

  • martennis
  • Registratie: Juli 2005
  • Laatst online: 12-10 13:48
in principe is geen enkel object compleet thread safe. even een scenario:

1) MyInt constructor wordt aangeroepen
2) geen ruimte meer in het geheugen voor het opslaan van de int waarde (kan gebeuren)
3) exception wordt 'genegeerd' door programmeur door wel een try/catch blok te gebruiken, maar daarna nogmaals naar het object te verwijzen met de getter method
4) thread object vraagt om data dat er niet is (via getter-methode)
5) geen idee wat er dan gebeurt.... beetje onvoorspelbaar

zet mij maar in rijtje -> niet veilig

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

Als een object niet aangemaakt kan worden en je refereert er toch nog naar dan gaat het mis ja. Maar dat knalt singlethreaded net zo hard als dat het multithreaded zou gebeuren ;)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • martennis
  • Registratie: Juli 2005
  • Laatst online: 12-10 13:48
klopt =)
maar 1 thread is ook een thread ;)

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

eeh, ja. Maar met 1 thread heb je in dit geval 0,0 te maken met concurrency control......

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Waarom is dit een instinker? Het is toch duidelijk niet treadsafe?

Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Oh nee, oops, het is een constructor.

Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
makreel schreef op dinsdag 22 augustus 2006 @ 20:49:
Waarom is dit een instinker? Het is toch duidelijk niet treadsafe?
Waarom is dit zo duidelijk dan? (als we uitgaan van Java 1.5)

Edit: laat maar, je zag 't net op tijd :)

[ Voor 8% gewijzigd door Little Penguin op 22-08-2006 21:36 ]


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Ik vroeg me al af waarom hij geen setDinges heette..

Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Oh, hm, sorry, het is ingewikkeld

ik lees net http://www.theserverside....hread.tss?thread_id=24199

:S

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Inderdaad threadsafe dus. Toegegeven, ju kunt een threadprobleem hebben in de aanroepende code. Elke gedeelde variabele moet voor elke schrijf of lees actie beschermd worden met thread synchronisatiemechanismes. Een constructor is een schrijfactie en moet dus ook beschermd worden. Vóór de unlock blokkeren andere threads die het nieuwe object willen lezen. Na de unlock is er een write barrier op de unlockende thread, en een read barrier op de thread die gaat lezen. Regels gevolgd, geen enkel probleem. Zonder locks en hun impliciete memory barriers heb je wel een probleem.

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


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Eh nou:

"not all multiprocessor systems exhibit cache coherency; if one processor has an updated value of a variable in its cache, but one which has not yet been flushed to main memory, other processors may not see that update. In the absence of cache coherency, two different processors may see two different values for the same location in memory. This may sound scary, but it is by design -- it is a means of obtaining higher performance and scalability -- but it places a burden on developers and compilers to create code that accommodates these issues."

:$

'k moet toegeven nog nooit hierover te hebben nagedacht.
De ts wordt bedankt. 7(8)7

Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Op deze fiets geldt dit issue dan ook net zo goed voor alle andere multithreaded programeertalen buiten Java? Dan nog, dat is inderdaad wel iets om over na te denken bij het coden, de business objecten zijn praktisch allemaal DTO objecten :/ Interessant punt anyway.

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Zonder de overige 2 pagina's van het topic doorgelezen te hebben. Ik zou zeggen dat het NIET threadsafe is.
De eenvoudige reden is dat als men met 2 threads gebruik maakt van deze klasse het gewoonweg ontzettend fout kan gaan. Omdat er geen vorm van locking wordt toegepast is het mogelijk om tegelijkertijd te schrijven en te lezen in dezelfde int waarde (nouja niet tegelijkertijd maar you get the point). Waardoor dus in de ene thread tussen 2 instructies in stiekem de waarde door een andere thread gewijzigd wordt. Waardoor je dus bij instructie 2 ineens een heel andere waarde hebt dan dat je verwacht. Je zult dus een bepaalde vorm van resource locking toe moeten passen.

Ongeacht welke vorm van threading je toepast. Of dit nu met met meerdere threads op 1 of op 2 cpu's is. Al weet ik de specifieken van java niet precies dus ik kan er wel een beetje naast zitten. Maar ik grove lijnen denk ik dat in ieder geval wel goed zit.

En nu de rest van t topic lezen:P

Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Deathraven zit in het stadium waar ik net ook zat. :')

Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

D-Raven schreef op dinsdag 22 augustus 2006 @ 22:35:
De eenvoudige reden is dat als men met 2 threads gebruik maakt van deze klasse het gewoonweg ontzettend fout kan gaan. Omdat er geen vorm van locking wordt toegepast is het mogelijk om tegelijkertijd te schrijven en te lezen in dezelfde int waarde (nouja niet tegelijkertijd maar you get the point). Waardoor dus in de ene thread tussen 2 instructies in stiekem de waarde door een andere thread gewijzigd wordt. Waardoor je dus bij instructie 2 ineens een heel andere waarde hebt dan dat je verwacht. Je zult dus een bepaalde vorm van resource locking toe moeten passen.

Ongeacht welke vorm van threading je toepast. Of dit nu met met meerdere threads op 1 of op 2 cpu's is. Al weet ik de specifieken van java niet precies dus ik kan er wel een beetje naast zitten. Maar ik grove lijnen denk ik dat in ieder geval wel goed zit.
Dat is hier toch niet het geval? Het lijkt alsof je denkt dat de Javacode alleen maar uit static variabelen bestaat.

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

Deathraven: de class heeft alleen een constructor.
Edit: ok. Nu niet meer. Er is nu ook een getter bijgekomen :)
Maar dan geldt wat mij betreft nog steeds: Value kan dus na de constructor niet worden gezet. MyInt is dus threadsafe.

Je verhaal klopt uiteraard wel voor elke willekeurige class met een set en get voor een willekeurig field :) (maar dat lijkt me dan ook redelijk common knowledge als je met meerdere threads aan de slag gaat)

@BalusC en markeel: cache coherency is ook iets wat door bijv. de kernel kan worden afgedwongen (al dan niet met behulp van hardware). Interresant stukje leesvoer over reorderning en cache coherency bij SMP systemen: http://www.rdrop.com/user.../ordering.2006.03.13a.pdf

[ Voor 33% gewijzigd door Creepy op 22-08-2006 23:09 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Je kan me nog meer vertellen, zet mij in het rijtje "niet threadsafe". (zolang de startpost niet wijzigt ;) )

Misschien denk ik er morgen anders over.

edit:
cache coherency is ook iets wat door bijv. de kernel kan worden afgedwongen
Het kan, maar is het gegarandeerd?
Nee.
Djeez.

[ Voor 32% gewijzigd door makreel op 22-08-2006 22:56 ]


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
OlafvdSpek schreef op maandag 21 augustus 2006 @ 23:32:
[...]

Dat klopt, maar het lijkt me veel logischer dat de compiler/VM die reordering doet.
Ik neem aan dat je bedoelt dat de vm/compiler zelf in staat zou moeten zijn om te bepalen of reordening legaal is ipv dat dit mensenwerk moet zijn?

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
martennis schreef op dinsdag 22 augustus 2006 @ 20:11:
in principe is geen enkel object compleet thread safe. even een scenario:

1) MyInt constructor wordt aangeroepen
2) geen ruimte meer in het geheugen voor het opslaan van de int waarde (kan gebeuren)
3) exception wordt 'genegeerd' door programmeur door wel een try/catch blok te gebruiken, maar daarna nogmaals naar het object te verwijzen met de getter method
Als het object niet wordt aangemaakt, kan je er ook niet naar refereren.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
MSalters schreef op dinsdag 22 augustus 2006 @ 21:56:
Inderdaad threadsafe dus. Toegegeven, ju kunt een threadprobleem hebben in de aanroepende code.
Ok, naamgevings verschil.
Elke gedeelde variabele moet voor elke schrijf of lees actie beschermd worden met thread synchronisatiemechanismes.
Ik zal het je nog gekker vertellen: dat is dus niet altijd nodig :P Er is ondergronds gedrag (onderdeel van jsr133) waardoor volatile/non volatile reads/writes niet mogen worden gereordened + voordat een volatile read/write wordt aangeroepen gaan ze eerst syncen met main mem.

Volgens mij zou dit dus ook goed gaan:

code:
1
2
3
4
5
6
7
8
class Bla{
   private int a;
   private volatile int b;

   public Bla(int a, int b){
      this.a = a; this.b = b;
   }
}


Maar dat is imho wel vrij buggy en onbegrijpelijk. Ik heb net een vraag naar de concurrency mailign list gestuurd hierover.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
BalusC schreef op dinsdag 22 augustus 2006 @ 22:25:
Op deze fiets geldt dit issue dan ook net zo goed voor alle andere multithreaded programeertalen buiten Java? Dan nog, dat is inderdaad wel iets om over na te denken bij het coden, de business objecten zijn praktisch allemaal DTO objecten :/ Interessant punt anyway.
Yep.. alhoewel het nu schijnbaar allemaal wel goed gaat (hoe vaak zie jij een topic voorbij komen met 'mijn velden zijn niet gezet terwijl ik ze net heb gezet!) denk ik wel dat je rekening met dit soort dingen zou moeten houden: je houd je niet aan de specs en dat kan problemen veroorzaken. Helemaal omdat er steeds meer vm's komen.

[edit]
Leuk om te zien dat zo veel mensen nog op dit topic druk bezig zijn.

[ Voor 7% gewijzigd door Alarmnummer op 22-08-2006 23:21 ]


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
OlafvdSpek schreef op maandag 21 augustus 2006 @ 23:20:
[...]

Heb je toevallig een voorbeeld van een CPU architectuur die stores out-of-order retired naar cache/memory? x86 doet het niet voor zover ik weet.
Het gaat om de spec niet om de realiteit van vandaag.
Die kan veranderen, potvolperemoes! }:|

Acties:
  • 0 Henk 'm!

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Alarmnummer schreef op maandag 21 augustus 2006 @ 20:31:
[edit]
Ik heb nog even een setter toegevoegd aan het voorbeeld. Ik ben dit vergeten en aan het einde van de discussie zag ik deze fout pas.
Ik neem aan dat je getter bedoelt, dan is je naamgeving gelijk aan de code - overigens wanneer je alleen een setter toe zou voegen dan is de discussie niet relevant want dan kun je toch niks meer met de variabele doen en heb je ook geen concurrency probleem.

Even enigszins off-topic:
Nu ik dit doorlees begrijp ik ook waarom ik in het verleden zoveel problemen had met een multi-threaded Delphi applicatie (zonder GUI) - uiteindelijk heb ik de problemen die ik had opgelost door diverse zaken via de Windows message queue te laten lopen. - maar goed dat heeft verder niets met de JVM en het JMM te maken.

[ Voor 3% gewijzigd door Little Penguin op 22-08-2006 23:43 ]


Acties:
  • 0 Henk 'm!

  • makreel
  • Registratie: December 2004
  • Niet online
Hey, Olaf van der Spek kan zijn posts later verwijderen...
Cool. :X

Acties:
  • 0 Henk 'm!

  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Alarmnummer schreef op dinsdag 22 augustus 2006 @ 23:08:
[...]

Yep.. alhoewel het nu schijnbaar allemaal wel goed gaat (hoe vaak zie jij een topic voorbij komen met 'mijn velden zijn niet gezet terwijl ik ze net heb gezet!) denk ik wel dat je rekening met dit soort dingen zou moeten houden: je houd je niet aan de specs en dat kan problemen veroorzaken. Helemaal omdat er steeds meer vm's komen.
Compilers die beter optimaliseren, multi-core processoren, processoren met grotere caches... en programmeurs die multithreaded moeten programmeren terwijl ze er eigenlijk te weinig kennis voor hebben, maar dat toch moeten doen omdat de opdrachtgever een sneller programma wil.

Nu zijn we door de komst van VM's in de toekomst eindelijk van buffer-overlfow bugs af, krijgen we moeilijk opspoorbare concurrency bugs ervoor in de plaats... ach, het moet ook niet te makkelijk worden he :)

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Infinitive schreef op woensdag 23 augustus 2006 @ 00:08:
[...]

Compilers die beter optimaliseren, multi-core processoren, processoren met grotere caches... en programmeurs die multithreaded moeten programmeren terwijl ze er eigenlijk te weinig kennis voor hebben, maar dat toch moeten doen omdat de opdrachtgever een sneller programma wil.

Nu zijn we door de komst van VM's in de toekomst eindelijk van buffer-overlfow bugs af, krijgen we moeilijk opspoorbare concurrency bugs ervoor in de plaats... ach, het moet ook niet te makkelijk worden he :)
Op het moment dat het voorspelbaar is (ook al is het complex) en ik mijn brood ermee kan verdienen (mijn doel is het om concurrency expert te worden binnen het bedrijf waar ik voor werk) vind ik alles best :) En verder is het een onderwerp die de moeite waard is (zie het voorbeeld) in een paar regels kan je het al helemaal fout hebben.

[ Voor 7% gewijzigd door Alarmnummer op 23-08-2006 07:20 ]


Acties:
  • 0 Henk 'm!

  • bloody
  • Registratie: Juni 1999
  • Laatst online: 20:27

bloody

0.000 KB!!

In hoeverre speelt dit probleem nog in java 1.5?
Volgens ibm zijn veel holes in de JMM al gedicht in 1.4 en zou de JSR meegenomen zijn voor 1.5

nope


Acties:
  • 0 Henk 'm!

Verwijderd

Zeer interessant. Ik zou ook threadsafe hebben gezegd. Gelukkig definieer ik attributen van non-mutable classes tegenwoordig altijd als final, al was het maar om eigen stommiteiten tegen te gaan.

Dit betekend dus ook dat alle primitieve wrapper classes in principe niet threadsafe zijn!? Maar zoals volgens mij Alarmnummer al ongeveer zei: Het is niet zo dat elke dag topics voorbij komen waarbij dit de oorzaak is van een probleem.

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Creepy schreef op dinsdag 22 augustus 2006 @ 22:43:
Deathraven: de class heeft alleen een constructor.
Edit: ok. Nu niet meer. Er is nu ook een getter bijgekomen :)
Maar dan geldt wat mij betreft nog steeds: Value kan dus na de constructor niet worden gezet. MyInt is dus threadsafe.
Je hebt gelijk. Er zijn geen getters en setters, dus dan gaat mijn verhaal niet op.

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
makreel schreef op dinsdag 22 augustus 2006 @ 22:40:
Deathraven zit in het stadium waar ik net ook zat. :')
Inderdaad makreel :P ;)

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:38

Creepy

Tactical Espionage Splatterer

makreel schreef op dinsdag 22 augustus 2006 @ 23:44:
Hey, Olaf van der Spek kan zijn posts later verwijderen...
Cool. :X
offtopic:
Geen idee wat je bedoelt maar niemand kan zomaar posts verwijderen. Daarnaast heeft het 0,0 met het topic te maken dus laat dit gebeuren liever achterwege..


@Alarmnummer: waarom denk je nu dat het een probleem is? Vanwege de reordening? Of vanwege het SMP en cache concurrency verhaal? Het eerste lijkt me namelijk helemaal geen probleem tenzij je this lekt vanuit de constructor. Het tweede zal op o.a. Windows en Linux in de praktijk niet voor mogen komen. Als dit wel gebeurd dan lijkt het me een kernel bug.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Alarmnummer schreef op woensdag 23 augustus 2006 @ 07:09:
[...]

Op het moment dat het voorspelbaar is (ook al is het complex) en ik mijn brood ermee kan verdienen (mijn doel is het om concurrency expert te worden binnen het bedrijf waar ik voor werk) vind ik alles best :) En verder is het een onderwerp die de moeite waard is (zie het voorbeeld) in een paar regels kan je het al helemaal fout hebben.
Eventjes wat dingen aandragen ;)
-Ik vindt het super dat je dit soort dingen aankaart hier op GoT. Zeer verfrissend topic. _/-\o_

-Concurrency is inderdaad complexe materie. Helaas wordt er in de HIO (Hogere Informatica Opleiding) veel te weinig aandacht aan besteed.

Ik zal eens gaan zoeken vanmiddag of dit probleem ook speelt bij c#, ik ben benieuwd.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
bloody schreef op woensdag 23 augustus 2006 @ 08:10:
In hoeverre speelt dit probleem nog in java 1.5?
Volgens ibm zijn veel holes in de JMM al gedicht in 1.4 en zou de JSR meegenomen zijn voor 1.5
Deze issues spelen ook in de nieuwe versie. Wat voornamelijk is veranderd is dat final velden nu wel final zijn (in oudere versies van jmm zijn deze zelfs niet final.. onder java 5 is MyInt met een final value wel threadsafe, maar in principe ondere oudere vm's niet!)

en volatile gedrag is veranderd
-er vind nu synchronisatie met main memory plaats van de non volatile stores voor het volatile veld
-non volatile en volatile stores mogen niet gereordenend worden

Acties:
  • 0 Henk 'm!

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 15-10 22:58
Ik mis nog even 1 ding in het geheel.

Zolang de int netjes ge initialiseerd wordt in de constructor en er geen this reference exposed wordt in de constructor datn is toch alles prima?

Of moet ik denken aan een object wat geinitialiseerd is, maar waarvan de weggeschreven int nog niet vanuit de cache naar main memory geschreven is zodat een CPU op een andere cache hier problemen van krijgt. (Core Duo's hebben een enkele cache richting main memory bijvoorbeeld)

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
The - DDD schreef op woensdag 23 augustus 2006 @ 10:31:
Ik mis nog even 1 ding in het geheel.

Zolang de int netjes ge initialiseerd wordt in de constructor en er geen this reference exposed wordt in de constructor datn is toch alles prima?
Nope :) Dat is dus het vervelende. Het kan gebeuren dat een gedeeltelijk geinitialiseerd object wordt gepubliceerd zodat andere threads er toegang naar hebben. Zij zien dan een partially constructed object met alle gevolgen van dien. Nadat het de constructor helemaal is uitgedraaid, zijn de waarden die die thread zag ineens veranderd. En een ander nadeel is dat die waarden die gezet worden niet gepubliceerd hoeven te worden. Dus andere threads zouden eventueel nooit die nieuwe waarde zien.
Of moet ik denken aan een object wat geinitialiseerd is, maar waarvan de weggeschreven int nog niet vanuit de cache naar main memory geschreven is zodat een CPU op een andere cache hier problemen van krijgt. (Core Duo's hebben een enkele cache richting main memory bijvoorbeeld)
Dat is idd een gedeelte van het probleem. Het andere gedeelte is dus de 'onverwachte' reordening van instructies.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Creepy schreef op woensdag 23 augustus 2006 @ 09:16:
@Alarmnummer: waarom denk je nu dat het een probleem is? Vanwege de reordening? Of vanwege het SMP en cache concurrency verhaal?
Ik denk dat het een probleem is vanwege visibility problemen. Het zou kunnen dat andere threads partially created objecten zien. Dus dependencies zijn wellicht niet goed of class invarianten de houden niet meer. En verder zullen wijzigingen op beans bv ook niet zichtbaar worden.

Stel dat je een ThreadPool hebt met een bepaalde size. Als je dynamisch de size aan gaat passen, en de size gaat niet gepubliceerd worden, dan kan het zijn dat deze waarde nooit zichtbaar gaat worden en de size van de pool ook niet gaat veranderen.
Het eerste lijkt me namelijk helemaal geen probleem tenzij je this lekt vanuit de constructor.
Het heeft niets te maken met die this lekken uit de constructor. De vm mag instructies gaan reordenen zo lang deze reordening niet binnen de thread zelf zichtbaar is. Als andere threads naar dezelfde data kijken, kan deze reordening wel zichtbaar zijn. En dat is iets dat mag en eigelijk ook noodzakelijk is ivm performance. Alleen moet je in sommige gevallen dit gaan verhinderen en hierbij komen de volgende constructies: synchronized blokken, volatile en final je bij helpen.
Het tweede zal op o.a. Windows en Linux in de praktijk niet voor mogen komen. Als dit wel gebeurd dan lijkt het me een kernel bug.
Het is geen kernel bug. Het is toegestaan gedrag.. Als je meerdere cpu's hebt met meerdere afzonderlijke caches, dan loop je de kans dat er verschillen gaan bestaan tussen caches. Binnen een thread zie je dit niet, alleen tussen threads (threads die bv draaien op verschillende cpu's) kan je dus tegen problemen aanlopen.

[ Voor 14% gewijzigd door Alarmnummer op 23-08-2006 10:56 ]


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Verwijderd schreef op woensdag 23 augustus 2006 @ 08:59:
Dit betekend dus ook dat alle primitieve wrapper classes in principe niet threadsafe zijn!?
Afhankelijk van het memory model en het feit of je het veld bv final hebt gemaakt.

Onder oude memory model zou zelfs met een final veld je geen garanties kunnen krijgen mbt immutability.

Onder nieuwe memory model krijg je wel garanties mbt immutability.

Check verder de documentatie die in de opening post is geplaatst.

[ Voor 6% gewijzigd door Alarmnummer op 23-08-2006 11:00 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Alarmnummer schreef op woensdag 23 augustus 2006 @ 11:00:
Afhankelijk van het memory model en het feit of je het veld bv final hebt gemaakt.
Ik doelde op classes zoals "java.lang.Integer". Daarin is immers het attribute 'value' niet als volatile of final gedeclareerd.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Verwijderd schreef op woensdag 23 augustus 2006 @ 11:13:
[...]

Ik doelde op classes zoals "java.lang.Integer". Daarin is immers het attribute 'value' niet als volatile of final gedeclareerd.
Uhhhh... dat zou vrij naar zijn. Dat ga ik even controleren en navragen op de concurrency mailinglist.

[edit]
In 1.5 is het wel final. In 1.3 is het niet final. 1.4 source heb ik niet bij de hand, wie zou dat ff kunnen controleren?

Onder de oudere JMM heeft final mbt reordening sowieso geen toegevoegde waarde.

[ Voor 33% gewijzigd door Alarmnummer op 23-08-2006 12:02 ]


Acties:
  • 0 Henk 'm!

  • CubicQ
  • Registratie: September 1999
  • Laatst online: 20:39
1.4 is ie ook niet final.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Alarmnummer schreef op dinsdag 22 augustus 2006 @ 23:06:
Ik zal het je nog gekker vertellen: dat is dus niet altijd nodig :P Er is ondergronds gedrag (onderdeel van jsr133) waardoor volatile/non volatile reads/writes niet mogen worden gereordened + voordat een volatile read/write wordt aangeroepen gaan ze eerst syncen met main mem.
Volatile betekent toch simpelweg dat alle reads en writes ervan impliciete memory barriers hebben?

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
Volatile is niet alleen een memory barrier maar heeft ook de "happens before" relatie om reordering problematiek te voorkomen. De "happens before" is echter alleen van kracht als een andere thread ook synchroniseert op dezelfde volatile waarde. Het [b]voorbeeld[/b] wat alarmnummer eerder noemde is dan ook niet helemaal volledig:

code:
1
2
3
4
5
6
7
8
class Bla{
   private int a;
   private volatile int b;

   public Bla(int a, int b){
      this.a = a; this.b = b;
   }
}

Of dit thread-safe is hangt er (theoretisch) van af of "b" altijd wordt gebruikt bij het uitlezen van "a". Het voorbeeld wat hier genoemd is wat uitgebreider en laat een correct gebruik zien. Ik vind het overigens ook onduidelijke side-effects, vooral als je het de ene keer wél en de andere keer niet goed zou doen.

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 18:54

Gerco

Professional Newbie

@misfire. Ik neem aan dat je dit voorbeeld bedoelt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}


Als ik het goed begrijp uit dit voorbeeld van JSR-133, worden alle fields die je 'tegelijk' schrijft met een volatile field ook een beetje volatile. In de link van misfire lees ik dit:
Thus, if the reader sees the value true for v, it is also guaranteed to see the write to 42 that happened before it. This would not have been true under the old memory model. If v were not volatile, then the compiler could reorder the writes in writer, and reader's read of x might see 0.
Wat er in het oude memory model gebeurt, lijkt me niet meer dan normaal. Als je had gewild dat x ook door andere threads altijd correct gelezen zou worden, had je x ook wel volatile gemaakt of ben ik nu gek?

Je hebt nu natuurlijk het probleem dat, als je meerdere waardes wilt schrijven in volatile fields, je niet zeker kan zijn dat ze allemaal geschreven zijn wanneer een andere thread wil lezen. Je zou dan een lock moeten gebruiken om die field writes te beschermen. Dat gebeurt onder het nieuwe model "stiekem" en ik weet niet of dat zo handig is.

[ Voor 13% gewijzigd door Gerco op 24-08-2006 11:50 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Ja dat is inderdaad het voorbeeld dat ik bedoel. De sleutel in het voorbeeld is dat v ook in de reader methode wordt gebruikt. Hierdoor heb je de "happens-before" relatie waardoor x gegarandeerd 42 is.

Ik heb begrepen dat de reden waarom dit zo werkt te maken heeft met dat je meestal als programmeur dit gedrag ook wilt als je met volatile aan de gang gaat, omdat dit impliceert dat de status van die variabele bepalend is voor meerdere threads, en dus ook wat ervoor gebeurt. Dat is ten minste wat Brian Goetz opmerkte toen hij dit op de Javapolis uitlegde afgelopen jaar. Maar volgens mij is iedereen het er wel over eens dat het wel een beetje stiekem is allemaal.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op donderdag 24 augustus 2006 @ 11:40:
Volatile is niet alleen een memory barrier maar heeft ook de "happens before" relatie om reordering problematiek te voorkomen. De "happens before" is echter alleen van kracht als een andere thread ook synchroniseert op dezelfde volatile waarde. Het [b]voorbeeld[/b] wat alarmnummer eerder noemde is dan ook niet helemaal volledig:

code:
1
2
3
4
5
6
7
8
class Bla{
   private int a;
   private volatile int b;

   public Bla(int a, int b){
      this.a = a; this.b = b;
   }
}

Of dit thread-safe is hangt er (theoretisch) van af of "b" altijd wordt gebruikt bij het uitlezen van "a". Het voorbeeld wat hier genoemd is wat uitgebreider en laat een correct gebruik zien. Ik vind het overigens ook onduidelijke side-effects, vooral als je het de ene keer wél en de andere keer niet goed zou doen.
In het voorbeeld heb ik duidelijk proberen te maken dat met een volatile write erin, het alsnog threadsafe zou worden

1) het is niet toegestaan om de write van a om te wisselen met b
2) het is niet toegestaan om de write van memory (van Bla naar een globaal veld bv) om te wisselen met de write van b
3) de waarde van a is zichtbaar door de publicatie functionaliteit van de volatile write van b

Hierdoor voorkom je dus dat een object partially constructed beschikbaar is in andere threads. En is de waarde van a zichtbaar binnen andere threads.

Zover ik begrepen heb hangt dit niet nog een keer weer af van de threading context waarin dit weer gebruikt gaat worden.

quote uit de desbetreffende faq "Under the new memory model, accesses to volatile variables cannot be reordered with each other or nonvolatile variable accesses"

[edit]
Om in happens before termen te blijven:
iedere access van volatile of non volatile variable a, die in de code voor volatile b staat, die heeft een happens before relatie.

iedere access van volatile b, die in de code voor volatile of non volatile c staat, die heeft een happens before relatie.

maw: de happens before relatie is er dus zeker :)

[ Voor 12% gewijzigd door Alarmnummer op 25-08-2006 02:59 ]


Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Gerco schreef op donderdag 24 augustus 2006 @ 11:47:
@misfire. Ik neem aan dat je dit voorbeeld bedoelt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}


Als ik het goed begrijp uit dit voorbeeld van JSR-133, worden alle fields die je 'tegelijk' schrijft met een volatile field ook een beetje volatile. In de link van misfire lees ik dit:

[...]


Wat er in het oude memory model gebeurt, lijkt me niet meer dan normaal. Als je had gewild dat x ook door andere threads altijd correct gelezen zou worden, had je x ook wel volatile gemaakt of ben ik nu gek?
*houd zich stil* ;)

Maar om antwoord te geven op je vraag: ik zat hier dus ook mee. Voor primitives zou dit wellicht lukken, maar je wilt ook graag object structuren uit gaan wisselen tussen threads die dus wellicht niet safely published zijn. Om te voorkomen dat je daar ook alle velden nog een keer volatile zou moeten maken (hoe diep moet je gaan??), is voor deze oplossing gekozen.

Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 18:54

Gerco

Professional Newbie

Alarmnummer schreef op vrijdag 25 augustus 2006 @ 02:56:
Maar om antwoord te geven op je vraag: ik zat hier dus ook mee. Voor primitives zou dit wellicht lukken, maar je wilt ook graag object structuren uit gaan wisselen tussen threads die dus wellicht niet safely published zijn. Om te voorkomen dat je daar ook alle velden nog een keer volatile zou moeten maken (hoe diep moet je gaan??), is voor deze oplossing gekozen.
Ik snap dat het op deze manier makkelijker is, maar ik vind gewoon die 'happens before' een beetje stiekem. Als ik het goed begrijp gebeurt er eigenlijk dit:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Example {
  volatile int a;
  int b;
  int c;

  void method() {
    synchronized(somelock) { // Deze word door de compiler verzonnen ???
      b = 10;
      a = 11;
    }
  }

  void method2() {
    b = 10;
    c = 11;
  }
}


Twee stukken code die er in source vorm hetzelfde uitzien, waarbij de compiler er een lock bijverzint als 1 van die velden volatile blijkt te zijn? Al schijnt het geen echte lock te zijn, maar enkel een "lock release". Een verplichte cache flush dus.

[ Voor 4% gewijzigd door Gerco op 25-08-2006 08:52 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Alarmnummer schreef op vrijdag 25 augustus 2006 @ 02:42:
[...]

In het voorbeeld heb ik duidelijk proberen te maken dat met een volatile write erin, het alsnog threadsafe zou worden

1) het is niet toegestaan om de write van a om te wisselen met b
2) het is niet toegestaan om de write van memory (van Bla naar een globaal veld bv) om te wisselen met de write van b
3) de waarde van a is zichtbaar door de publicatie functionaliteit van de volatile write van b

Hierdoor voorkom je dus dat een object partially constructed beschikbaar is in andere threads. En is de waarde van a zichtbaar binnen andere threads.

Zover ik begrepen heb hangt dit niet nog een keer weer af van de threading context waarin dit weer gebruikt gaat worden.

quote uit de desbetreffende faq "Under the new memory model, accesses to volatile variables cannot be reordered with each other or nonvolatile variable accesses"

[edit]
Om in happens before termen te blijven:
iedere access van volatile of non volatile variable a, die in de code voor volatile b staat, die heeft een happens before relatie.

iedere access van volatile b, die in de code voor volatile of non volatile c staat, die heeft een happens before relatie.

maw: de happens before relatie is er dus zeker :)
Volgens gaat voor het constructor voorbeeld punt 3 in theorie niet op, omdat "publicatie" alleen werkt als er zowel bij de read als de write een memory barrier is, en als je in een methode alleen iets met "a" zou doen in een andere thread dan raak je die niet. In de praktijk zul je (meestal?) wel gelijk hebben. Als het nieuwe object in een andere thread voor de eerste keer gebruikt zal worden dan moeten de waardes wel uit memory gelezen worden en heb je geen kans op stale data, dus het feit dat een tweede thread niet altijd een memory barrier over zou hoeven voor variabele "a" maakt dan niet meer uit.

De "happens-before" relatie is verder wel afhankelijk van of alle threads gebruik make van volatile members van hetzelfde object. Als één van de threads dat niet doet, dan is het niet thread-safe. Dus het voorbeeld nog een keer als foute variant (en beide blokken zijn methodes zodat er niet meer valsgespeeld kan worden met memory barriers ;)):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class VolatileExample {
  int x = 0;
  boolean y = false;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    y = true;
    v = true;
  }

  public int reader() {
    if (y) { // v niet gebruikt, dus niet thread-safe    
      return x; // ook niet thread-safe, kan 0 of 42 zijn
    }
    return 0;
  }
}

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op vrijdag 25 augustus 2006 @ 15:00:
[...]
Volgens gaat voor het constructor voorbeeld punt 3 in theorie niet op, omdat "publicatie" alleen werkt als er zowel bij de read als de write een memory barrier is, en als je in een methode alleen iets met "a" zou doen in een andere thread dan raak je die niet. In de praktijk zul je (meestal?) wel gelijk hebben. Als het nieuwe object in een andere thread voor de eerste keer gebruikt zal worden dan moeten de waardes wel uit memory gelezen worden en heb je geen kans op stale data, dus het feit dat een tweede thread niet altijd een memory barrier over zou hoeven voor variabele "a" maakt dan niet meer uit.
Dat klopt. Maar as far as the constructor is concerned, hij heeft zijn taak gedaan.
De "happens-before" relatie is verder wel afhankelijk van of alle threads gebruik make van volatile members van hetzelfde object. Als één van de threads dat niet doet, dan is het niet thread-safe. Dus het voorbeeld nog een keer als foute variant (en beide blokken zijn methodes zodat er niet meer valsgespeeld kan worden met memory barriers ;)):
Tja.. en ik zeg dat die happens before relatie hier word afgedwongen door het feit dat we een volatile veld hebben en je instructies die eronder staan niet naar boven mag schoppen, en die er boven staan niet naar onderen mag schoppen. Dus ongeacht de threading context zal de happens before rules van volatile leiden tot een threadsafe class (afgezien van die 'a'-variable dus ook netjes uitgelezen moet worden en niet alleen netjes weggeschreven). Daarom zal het voorbeeld (afgezien van die a) dus altijd threadsafe zijn.

Voorbeeld uitgebreid
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
lass Bla{
   private int a;
   private volatile int b;

   public Bla(int a, int b){
      this.a = a;
      this.b = b;
   }

   public void foo(){
       int btemp = b;
       int atemp = a;
       System.out.println(btemp+" "+atemp)
   }
}


[edit]
Zelfs zonder de read van b zal a correct worden uitgelezen. Omdat a safely is published in de constructor en nog geen enkel thread een ref had naar een partially created object. Dus iedere andere thread zal de published versie zien van a, dus threadsafe.

[ Voor 25% gewijzigd door Alarmnummer op 25-08-2006 16:12 ]


Acties:
  • 0 Henk 'm!

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Klopt helemaal, het ging mij alleen om de redenering. Volgens de specs werkt volatile alleen goed als alle threads het ook gebruiken (je moet reordering voorkomen én allemaal een memory barrier over voordat een "happens-before" relatie kan worden gegarandeerd).

In de praktijk lijk je met jouw voorbeeld in de constructor voor een safe situatie te zorgen zónder dat meerdere threads per sé volatile gebruiken... Tenzij er nog haken en ogen zijn aan dit voorbeeld waar wij allebei nog niet aan hebben gedacht? Het is in ieder geval niet een gebruik van volatile op de manier zoals het ontworpen is, dus ik ben er niet helemaal gerust op dat ook hier (net als bijv DCL) toch stiekem nog ergens een addertje zit... Ik ben benieuwd of men in de mailing list jouw voorbeeld kan bewijzen als een geldige oplossing! :)

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
misfire schreef op vrijdag 25 augustus 2006 @ 16:51:
Klopt helemaal, het ging mij alleen om de redenering. Volgens de specs werkt volatile alleen goed als alle threads het ook gebruiken (je moet reordering voorkomen én allemaal een memory barrier over voordat een "happens-before" relatie kan worden gegarandeerd).

In de praktijk lijk je met jouw voorbeeld in de constructor voor een safe situatie te zorgen zónder dat meerdere threads per sé volatile gebruiken... Tenzij er nog haken en ogen zijn aan dit voorbeeld waar wij allebei nog niet aan hebben gedacht? Het is in ieder geval niet een gebruik van volatile op de manier zoals het ontworpen is, dus ik ben er niet helemaal gerust op dat ook hier (net als bijv DCL) toch stiekem nog ergens een addertje zit... Ik ben benieuwd of men in de mailing list jouw voorbeeld kan bewijzen als een geldige oplossing! :)
Voor de rest van de mensen... dit is puur een theoretisch issue.. Niemand moet zulke code schrijven om iets threadsafe te maken. Het is puur een middel om onze gedachten duidelijk te krijgen.
Pagina: 1 2 Laatste