INF1010 Tråder2 31.mars2016 SteinGjessing Ins$tu'forinforma$kk UniversitetetiOslo 1 Ins$tu'forinforma$kk Kommunikasjon mellom tråder: Felles data F K Felles data (blå felt, F) må vanligvis bare aksesseres (lese eller skrives i) av en tråd om gangen. Hvis ikke blir det kluss i dataene. Et felles objekt kalles en monitor. Metodene i en monitor har modifikatoren synchronized F K f.eks. K: konstante data (immutable) putInn Monitor er ikke noe ord i Java hentUt Buffer Produsenter Konsumenter 2 Ins$tu'forinforma$kk BasaleJava-verktøy: synchronized,wait(),no$fy()ogno$fyAll() (metodene er definert i class Object) <Buffer-data> produsenter while(){ <lagnoe>; p.putInn(...); } konsumenter synchronizedvoidputInn(intverdi) while(){ p.hentUt <brukde'e>; } while(full)wait(); //nåerbufferetikkefult <legginn> synchronizedinthentUt while(){ <lagnoe>; p.putInn(...); } If(empty)returnnull; else <tautetelement> //nåerbufferetikkefult no3fy(); returnelement; Enmonitor(etobjekt) while(){ p.hentUt <brukde'e>; } Passpååunngå: polling=ak$vven$ng (prøveomogomigjen 3 (utenåfågjortnoe))Ins$tu'forinforma$kk To køer i en basal Java monitor: <Buffer-data> Enkøavventendetråder påhelemonitoren køforåfålåsen($lgang$lmonitoren) køavventendetråder synchronizedvoidputInn(intverdi) while(full)wait(); //nåerbufferetikkefult <legginn> synchronizedinthentUt If(empty)returnnull; else <tautetelement> //nåerbufferetikkefult no3fy(); returnelement; Enmonitor(etobjekt) Enkøavventendetråderpå ”wait”-instruksjoner (wait-set). Startesavno$fy()og/eller no$fyAll() Leggesdaidenandrekøen (først?(Nei,ingengaran$)) Derforerdetnødvendigmed ”while…” 4 Ins$tu'forinforma$kk Javaharénkø forallewait()- instruksjonene påsammeobjekt! produsenter while(){ <lagnoe>; p.putInn(...); } <Buffer-data> ENkøforåfålåsen ENkøforventendetråder synchronizedvoidputInn(intverdi) konsumenter while(full)wait(); //nåerbufferetikkefult <legginn> //nåerbufferetikketomt no3fy(); synchronizedinthentUt while(){ <lagnoe>; p.putInn(...); } while(empty)wait(); //nåerbufferetikketomt <tautetelement> //nåerbufferetikkefult no3fy(); returnelement; Enmonitor(etobjekt) while(){ p.hentUt <brukde'e>; } while(){ p.hentUt <brukde'e>; } Passpå:Unngåvranglås 5 (deadlock) Ins$tu'forinforma$kk <Buffer-data> Flytt en: notify (); køforåfålåsen Flytt alle: notifyAll (); ventendetråder intledig=totRes; //invariant:0<=ledig<=totRes synchronizedvoidreserver(intantall) while(ledig<antall)wait(); //nåerdetnokledig ledig=ledig–antall; synchronizedvoidfrigi(intantall) ledig=ledig+antall; //nåermangeflereledig no3fyAll(); Enmonitor(etobjekt)foråreservereogfrigi etantalllikeresurser Hvis du ikke er HELT sikker på at enhver ventende tråd kan ordne skikkelig opp må du si: notifyAll(); Da blir ALLE ventende tråder flyttet opp til køen for å få låsen Men hva med rettferdighet (fairness) ?? 6 Ins$tu'forinforma$kk teknikk for å Eksempelpåparallellisering: (samme finne sum / gjennomsnitt) Finnminstetallitabell HovedprogrammetstarterN Tråd1finnerminstetalli tråderogventerpåatdealle erferdigeførdethenterminste verdiframonitorenMinstVerdi dennedelenavtabellen Tråd2finnerminstetalli dennedelenavtabellen synchronizedvoidgiMinsteVerdi(intverdi) synchronizedinthentMinst Objektavklassen MinstVerdi Trådenes minste verdigis$l monitoren Trådn(64?)finnerminstetalli dennedelenavtabellen BARE FANTASIEN SETTER GRENSER 7 Ins$tu'forinforma$kk Amdahlslov • Enberegningdeltoppiparallellgårforterejomeruavhengigdeleneer • Amdahlslov: – Total$dener • $deniparallell+ • $dendettaråkommunisere/synkronisere/gjørefellesoppgaver – Tidendettaråsynkronisereerikkeparallelliserbar(hjelperikkemedflere prosessorer) – Mendukanværesmartoglagesynkroniseringensåkortellermellomsåfå trådersommulig total tid Start opp Synkroniser Parallelle beregninger Lag resultat Parallelle beregninger 8 Ins$tu'forinforma$kk Amdahlslovog”finnminstetall” • Total$d: – Tidendettarålageogse'eigang64tråder * • (kandetgjøresiparallell?)(log64=6) 2 – Tidendettaråfinneetminstetallimindelavtabellen – Tilslu'imonitoren:Enogentrådmåtestesi'resultat • (Kandetgjøresiparallell?) total tid Start opp n tråder Parallelle beregninger Synkronisering Lag endelig resultat 6 * Start med én tråd, vha. doblinger 6 ganger har vi 64 tråder, dvs, 2 = 64, og log2 64 = 6 2, 4, 8, 16, 32, 64 9 Ins$tu'forinforma$kk Hovedprogrammetversjon1 public class MinstR { final int maxVerdiInt = Integer.MAX_VALUE; int [ ] tabell; MinstMonitorR monitor; public static void main(String[ ] args) { new MinstR(); } public MinstR ( ) { tabell = new int[640000]; for (int in = 0; in< 640000; in++) tabell[in] = (int)Math.round(Math.random()* maxVerdiInt); monitor = new MinstMonitorR(); for (int i = 0; i< 64; i++) // Lag og start 64 tråder new MinstTradR(tabell,i*10000,((i+1)*10000)-1,monitor).start(); monitor.vent(); System.out.println("Minste verdi var: " + monitor.hentMinste()); } } 10 Ins$tu'forinforma$kk class MinstMonitorR { private int minstTilNa = Integer.MAX_VALUE; private int antallFerdigeSubtrader = 0; synchronized public void vent() { while (antallFerdigeSubtrader != 64) { try {wait(); System.out.println(antallFerdigeSubtrader + " ferdige subtråder "); } catch (InterruptedException e) { System.out.println(" Uventet avbrudd "); System.exit(1); } // antall ferdige subtråder er nå 64 } } synchronized public void giMinsteVerdi (int minVerdi) { antallFerdigeSubtrader ++; if(minstTilNa > minVerdi) minstTilNa = minVerdi; if(antallFerdigeSubtrader == 64) notify(); // eller hver gang, (men stort sett unødvendig): notify(); } synchronized public int hentMinste () { return minstTilNa; } } 11 Ins$tu'forinforma$kk Trådersomfinnerminstetallidelavtabellen class MinstTradR extends Thread { int [ ] tab; int startInd, endInd; MinstMonitorR mon; MinstTradR(int [ ] tb, int st, int en, MinstMonitorR m) { tab = tb; startInd = st; endInd = en; mon = m; } public void run(){ int minVerdi = Integer.MAX_VALUE; for ( int ind = startInd; ind <= endInd; ind++) if(tab[ind] < minVerdi) minVerdi = tab[ind]; // denne tråden er ferdig med jobben: mon.giMinsteVerdi(minVerdi); } // slutt run } // slutt MinstTradR 12 Ins$tu'forinforma$kk Barriereriparallellprogrammering Barriere, dvs. vent på at alle er ferdig Denne tråden kan fortsetter når alle har nådd barrieren (join) Gren opp i parallelle beregninger (fork) Alle trådene sier fra når de er ferdige tid 13 Ins$tu'forinforma$kk Barriereriparallellprogrammering import java.util.concurrent.*; Barrieren CountDownLatch minBariere = new CountDownLatch(6) minBarriere.await(); minBarriere.countDown(); tid 14 Ins$tu'forinforma$kk Barrierenide'eeksemplet Start opp Alle trådene sier fra når de er ferdige (har nådd barrieren) Gren opp i parallelle beregninger (fork) Denne tråden kan fortsetter når alle har nådd barrieren (join). Da er det endelige resultatet klart. Barieren Alle trådene avsluttes med å kalle en metode i en og samme monitor tid Kallet monitor.vent(); i minstR-programmet er en hjemmelaget barriere 15 Ins$tu'forinforma$kk Hovedprogrammet,versjonmedbarriere import java.util.concurrent.*; public class MinstB { final int maxVerdiInt = Integer.MAX_VALUE; int [ ] tabell; final int antallTrader = 64; MinstMonitorB monitor = new MinstMonitorB();; CountDownLatch minBarriere = new CountDownLatch(antallTrader); public static void main(String[ ] args) { new MinstB(); } public MinstB ( ) { tabell = new int[640000]; for (int in = 0; in< 640000; in++) tabell[in] = (int)Math.round(Math.random()* maxVerdiInt); for (int i = 0; i< antallTrader; i++) // Lag og start antallTrader tråder new MinstTradB(tabell,i*10000,((i+1)*10000)-1,monitor,minBarriere).start(); //vent på at alle trådene er ferdig: try { minBarriere.await(); // vent på at alle ”Minst-trådene” har nådd barrieren System.out.println("Minste verdi var: " + monitor.hentMinste() ); } catch (InterruptedException ex){ } } } 16 Ins$tu'forinforma$kk Monitorforresultater class MinstMonitorB { private int minstTilNa = Integer.MAX_VALUE; synchronized public void giMinsteVerdi (int minVerdi) { if(minstTilNa > minVerdi) minstTilNa = minVerdi; } synchronized public int hentMinste () {return minstTilNa;} } 17 Ins$tu'forinforma$kk Trådersomfinnerminstetallidelavtabellen class MinstTradB extends Thread { int [ ] tab; int startInd, endInd; CountDownLatch barriere; MinstMonitorB mon; MinstTradB(int [ ] tb, int st, int en, MinstMonitorB mon, CountDownLatch barriere) { tab = tb; startInd = st; endInd = en; this.mon = mon; this.barriere = barriere; } public void run(){ int minVerdi = Integer.MAX_VALUE; for ( int ind = startInd; ind <= endInd; ind++) if(tab[ind] < minVerdi) minVerdi = tab[ind]; // gi minste resultat til monitoren: mon.giMinsteVerdi(minVerdi); // signaler at denne tråden er ferdig med jobben: barriere.countDown(); // sier fra at jeg har nådd barrieren } // slutt run } // slutt MinstTradB 18 Ins$tu'forinforma$kk Mennoengangererdetmuligåsynkroniseremindre (IKKEvik3giINF1010) Nyskisse3lmonitorforresultater class MinstMonitorS { private int [] deMinste = new int[antallTrader]; private int minstTilNa = Integer.MAX_VALUE; public void giMinsteVerdi(int tradNr, int minVerdi) { // Hver tråd har sitt eget element i tabellen deMinste[tradNr] = minVerdi; } synchronized public int hentMinste () { // Bare en tråd kaller // behøver ikke være synchronized for (int enVerdi: deMinste) { if(minstTilNa > enVerdi) minstTilNa = enVerdi; } return minstTilNa; } } Hva med Amdahls lov nå? 19 Ins$tu'forinforma$kk Mennoengangererdetmuligåsynkroniseremindre (IKKEvik3giINF1010) Amdahlslovmednyskisse3lmonitorforresultater • Total$d: – Tidendettarålageogse'eigang64tråder – Tidendettaråfinneetminstetallimindelavtabellen – Tilslu'imonitoren: • Iparallell(blå'påfiguren):Enogentrådleggerinnsi'resultat • Tilslu'finnerhovedprogrammetdenminsteverdien total tid Start opp n tråder Parallelle beregninger Lag endelig resultat Barriere * Sammenlign med lysark 9 Ins$tu'forinforma$kk Maskinarkitektur, f.eks.4prosessorer(repe$sjon) prosessor registre cache 1 cache 2 prosessor registre cache 1 Minne (RAM) prosessor registre cache 1 cache 2 prosessor registre cache 1 21 Ins$tu'forinforma$kk Javasminnemodell(memorymodel) • Enminnemodeldefineresvedåsepålovligerekkefølgerav leseogskriveoperasjonerpåvariable. • Innadientrådskjer$ngirekkefølgengi'avprogrammet, bortse'fraatuavhengigeoperasjonerkan”re-ordnes”(for op$malisering). • Mellomtråderskjer$ngikkeirekkefølgeunnta' – Vedbrukavvola$levariable – Alleoperasjonerføren”unlock”skjerirekkefølgeføralleoperasjoner e'erene'erfølgende”lock”pådensammemonitoren. 22 Ins$tu'forinforma$kk Vola$levariable • envariabelsomerdeklarertvola$lecachesikke (ogoppbevaresikkeiregistre(lengerennheltnødvending)). – Envola$lvariableskriveshelt$lbakeiprimærlageretførneste instruksjonuqøres. • Rekkefølgenavskriv/les-operasjonerpåvola$levariableog låsing/opplåsingavlåserdefinererensekvensieltkonsistent rekkefølgeavalleoperasjonersomerendelavseman$kken $lprogrammeringsspråketJava. 23 Ins$tu'forinforma$kk Synkroniseringogfellesvariable • Synchroniza$onensuresthatmemorywritesbyathread beforeorduringasynchronizedblockaremadevisibleina predictablemannertootherthreadswhichsynchronizeon thesamemonitor.Arerweexitasynchronizedblock,we releasethemonitor,whichhastheeffectofflushingthe cachetomainmemory,sothatwritesmadebythisthread canbevisibletootherthreads.Beforewecanentera synchronizedblock,weacquirethemonitor,whichhasthe effectofinvalida$ngthelocalprocessorcachesothat variableswillbereloadedfrommainmemory.Wewillthen beabletoseeallofthewritesmadevisiblebytheprevious release. From: JSR 133 (Java Memory Model) FAQ Jeremy Manson and Brian Goetz, February 2004 24 Ins$tu'forinforma$kk Synkroniseringogfellesvariable • Thismeansthatanymemoryopera$onswhichwerevisibleto athreadbeforeexi$ngasynchronizedblockarevisibletoany threadareritentersasynchronizedblockprotectedbythe samemonitor,sinceallthememoryopera$onshappen beforetherelease,andthereleasehappensbeforethe acquire. From: JSR 133 (Java Memory Model) FAQ Jeremy Manson and Brian Goetz, February 2004 25 Ins$tu'forinforma$kk OgfradefinisjonenavJava:Versjon8kap.17.7: 17.7Non-atomicTreatmentofdoubleandlong 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 implemented as 32-bit or 64-bit values. 26 Ins$tu'forinforma$kk MerfradefinisjonenavJava:Versjon8,kap17.3: Forexample,inthefollowing(broken)codefragment,assumethat this.doneisanon-vola$lebooleanfield: while(!this.done) Thread.sleep(1000); Thecompilerisfreetoreadthefieldthis.donejustonce,andreuse thecachedvalueineachexecu$onoftheloop.Thiswouldmeanthat theloopwouldneverterminate,evenifanotherthreadchangedthe valueofthis.done. 27 Ins$tu'forinforma$kk Fordelenmedkonstanter(immutableobjects) • Konstanterkandetaldriskrives$l • Minnemodellenforkonstanterblirderforveldigenkel. • Prøvåhamestmuligkonstanternårdataskaldelesmellom tråder. • Eksempel:Geografiskedata,observasjoner • Hvisduønskerågjøreenforandring: – Kastdetgamleobjektetoglagetny'. 28 Ins$tu'forinforma$kk Vi tar opp tråden (J) fra sidene lenger foran i forbindelse med at tråder skal vente i monitorer: Vanligviserdetflereforskjelligebe#ngelser (condi3ons)viventerpåienmonitor: venterpååkomme innførstegang <Buffer-data> synchronizedvoidsetInn(intverdi) If(antall==1000)vent-$l:Ikke-Full(); antall++; : no$fy:Ikke-Tom(); Men innebygget i java er det bare en kø. Hva gjør vi? synchronizedinttaUt() If(antall==0)vent-$l:Ikke-Tom(); antall--; : no$fy:Ikke-Full(); Enmonitor(etobjekt) 29 Ins$tu'forinforma$kk Biblioteketjava.concurrent.SlikdetbrukesiHorstmann(læreboka): Flerekøeravventendetråder Locklaas=newReentrantLock(); Condi3onikkeFull=laas.newCondi$on(); Condi3onikkeTom=laas.newCondi$on(); voidse'Inn(intverdi) laas.lock(); try{ while(full)ikkeFull.await(); //nåerdethelstsikkertikkefult : //deterlagtinnnoe,sådeter //heltsikkertikketomt: ikkeTom.signal(); }finally{ laas.unlock() } inttaUt() Enkøforselvelåsen ogenkøforhver condi$on-variabel (importjava.concurrent.locks.*) Metodene er ikke lenger ”synchronized” og vi må låse (og låse opp !) monitoren selv :-( 30 Ins$tu'forinforma$kk Java´sAPI (java.concurrent) InterfaceCondi3on • voidawait() Causesthecurrentthreadtowait un$litissignalled(orinterrupted) • voidsignal() Wakesuponewai$ngthread. • ClassReentrantLockerenlåsogenfabrikksomlagerobjekter somimplementerergrensesni'etCondi$on(pådennelåsen) 31 Ins$tu'forinforma$kk Locklaas=newReentrantLock(); Condi3onikkeFull=laas.newCondi$on(); Condi3onikkeTom=laas.newCondi$on(); voidse'Inn(intverdi)throwsInterrupedExcep$on laas.lock(); try{ while(full)ikkeFull.await();//OKmedif? //nåerdetheltsikkertikkefult : //deterlagtinnnoe,sådeterheltsikkertikketomt: ikkeTom.signal(); }finally{ laas.unlock(); } inttaUt()throwsInterrupedExcep$on laas.lock(); try{ while(tom)ikkeTom.await();//OKmedif? //nåerdetheltsikkertikketomt; : //deterdetta'utnoe,sådeterheltsikkertikkefult: ikkeFull.signal(); }finally{ laas.unlock(); } Nå har vi en kø per betingelse som skal oppfylles (og vi kan til og med få rettferdighet!) Bra! 32 Ins$tu'forinforma$kk Leggmerke$lbrukenavfinally voidputInn(intverdi)throwsInterrupedExcep$on{ laas.lock(); try{ : : }finally{ laas.unlock(); } } Dablirlaas.unlock()all3duqørt!! 33 Ins$tu'forinforma$kk Prosesservs.tråder P1 P2 Pn Operativsystemet (styrer alt og sørger for kommunikasjon mellom prosesser) Datamaskin 1 P1 P2 Pm Operativsystemet (styrer alt og sørger for kommunikasjon mellom prosesser) Datamaskin 2 34 Ins$tu'forinforma$kk Kommunikasjon mellom prosesser Samarbeidende prosesser sender meldinger til hverandre (brune piler, mest vanlig) eller leser og skriver i felles lager (blå piler). Prosess 2 MPI: Message Passing Interface Prosess 1 Prosess 3 Meldingsutveksling Prosess 1 Prosess 2 Felles data Prosess 3 I Java: Et objekt 35 Ins$tu'forinforma$kk Parallellitetmellomprosesser: Eks:CORBA,MPI(ikkepensumiINF1010) • CORBA(CommonObjectRequestBrokerArchitecture)er(var)en språkuavhengigmåteådefinerekommunikasjonmellomprosesservha. {ern-objekter EtIDL(InterfaceDefini$onLanguage)definerergrensesni'et$lobjektene(på sammemåtesomInterfaceiJava) • EnIDL-kompilatoroverse'er$ldi'valgtespråk(Java,C++,C#,Smalltalk,…) • De'egjøratprosesserskrevetiforskjelligeobjektorientertespråkogsom kjørerpåforskjellige(ellersamme)maskinkankommunisere. • Språksomikkeerobjektorienterte: P2 Sendeogmo'ameldinger (MPI–Message-PassingInterface) P3 P1 Send en melding 36 Motta en melding Ins$tu'forinforma$kk KommunikasjonmellomJava-prosesser: RMI:RemoteMethodInvoca$on (Norsk:Fjern-metode-kall) Dette ønsker vi å oppnå: Et Java program (på en maskin) Et annet Java program (på en annen maskin) InterfaceNavn fjernPeker = …….; ... fjernPeker.metodeNavn( ); ... metodeNavn objekt av en klasse som implementerer InterfaceNavn Alternativt navn: RPC: Remote Procedure Call 37 Ins$tu'forinforma$kk RMI: Implementasjon (bak kulissene) En maskin fjernPeker en proxy for fjern-objektet Ikke pensum i INF1010 En annen maskin et skjelett formidler kall og retur metodeNavn tjenerMetode ... fjernPeker.metodeNavn( ); ... en stub for fjern-metoden Odene proxy og stub brukes ikke alltid like konsistent fjern-objekt (kan også brukes av Javaprogrammet på denne maskinen) Parametere (og returverdi) pakkes ned og sendes mellom de to maskinen (marshaling) 38 Ins$tu'forinforma$kk RMI:Hvordankallemetoderi (Java-)objekterpåandremaskiner Ikke pensum i INF1010 klient tjener Register/ navnetjener 3. oppgi navn på objekt 4. og få tilbake peker 2. 5. bruk peker til fjernmetode-kall (Remote Method Invocation): 1. registrer (bind) med navn på objektet objekt fjernPeker.metodeNavn( ); Og det eneste som er kjent på begge maskinene er Interfacet til objektet og navnet 39 Ins$tu'forinforma$kk
© Copyright 2024