450 likes | 585 Views
VPR - Repetition. Trådning Distribueret Programmering Sprogteori Grafer. Tråde. Tråd (lightweight process) Enkel sekventiel kontrolsekvens i et program Deler fælles data. Trådning. Fordele Overvågningssystemer med flere uafhængige opgaver Muliggør brugerinteraktion via BGF
E N D
VPR - Repetition • Trådning • Distribueret Programmering • Sprogteori • Grafer
Tråde • Tråd (lightweight process) • Enkel sekventiel kontrolsekvens i et program • Deler fælles data
Trådning • Fordele • Overvågningssystemer med flere uafhængige opgaver • Muliggør brugerinteraktion via BGF • Muliggør serverhåndtering af flere samtidige klienter • Udnytter flerprocessor-systemer optimalt
Tråde • Ulemper • Trådene afvikles uafhængigt af hverandre • Afviklingsrækkefølgen er vilkårlig • Samspillet mellem tråde er ofte meget kompleks • Problemer med safety og liveness
Instantiering af tråde • Tråde kan skabes på 2 måder: • Arve fra Thread-klassen • Implemetere Runnable-interfacet
Thread-klassen • Skabe en tråd vha. Thread • extends Thread-klassen • Overskriv run-metoden • Lav en instans af trådklassen • Kald metoden start() på denne instans
Thread-klassen class Tråd extends Thread { public void run() { kode } } ... new Tråd().start();
Runnable-interfacet • Implements Runnable-interfacet • implementér run-metoden • Lav en instans af trådklassen • Lav en ny Thread-instans med Runnable-objektet som argument • Kald metoden start() på denne instans
Runnable-interfacet class Tråd implements Runnable { public void run() { kode } } ... new Thread(new Tråd()).start();
Runnable-interfacet class Tråd implements Runnable { public void run() { kode } public void start() { new Thread(this).start(); } } ... new Tråd().start();
Trådsikre klasser • Problem: Hvis en tråd afbrydes, medens den arbejder på et objekt, er der risiko for, at objektet efterlades i eninkonsistent tilstand. Dette kan give problemer, når en anden tråd forsøger at få tilgang til objektet
Trådsikre klasser • Løsning: Løsningen er at forhindre mere end én tråd ad gangen i at få tilgang til de kritiske områder i koden • Vha. synkronisering opnår en tråd eneret på et objekt (lås) • Låsen frigives, når tråden forlader det kritiske område eller ved kald af metoden wait() på objektet. Kritiske områder på samme objekt deler samme lås!
Liveness problemer • Starvation (udhungring): En tråd, som er i tilstanden ready, får aldrig lejlighed til at køre, fordi der findes andre tråde med højere prioritet • Dormancy (dvale): En tråd, som er i tilstandenblocked on wait, vækkes aldrig med notify() • Deadlock (hårdknude): To eller flere tråde kæmper om flere fælles ressourcer, og hver tråd efterspørger på samme tid disse ressourcer • Premature Termination (for tidlig død): En tråd termineres for tidligt og hindrer derved andre tråde i at blive vækket. (Evig dvale)
volatile vs. synchronized • Anvend volatile på en attribut, hvis denne kan tilgås af flere tråde; med mindre at alle trådene tilgår attributten gennem synkroniserede metoder (kodeblokke) • Hvis flere tråde samtidigt kan tilgå en attribut, og mindst én af disse kan ændre i attributtens værdi, så er det generelt en god idé at anvende synchronized til at styre tilgangen • Hvis kun én tråd kan tilgå attributten, så er brugen afsynchronized overflødig og sløver programafviklingen
Brug af synchronized • Nødvendig, hvis man vil lave "trådsikre klasser" • Ej omkostningsfrit:Kræver CPU-kraft langsommere programafvikling • "Hellere for mange synkroniserede blokke end for få!"MEN - pas på deadlocks
Monitor • En monitor indkapsler fælles ressourcer som private attributter og sikrer trådene enetilgang vha. synchronized metoder til de kritiske områder • Formål: Overvågning af trådes adgang til fælles ressourcer • Objekt, hvor de fælles ressourcer er samlet (attributter) • Der er udelelig adgang til monitorens metoder (mutex) • Én monitor-metode pr. kritisk sektion
Missed notification • Problemnotify sendes før wait • Konsekvensnotify mistes og wait-tråden bliver ved med at vente • LøsningSørg for kun at gå i wait, hvis notify endnu ikke er sendt. Sæt evt. en boolsk variabel, når notify sendes, og gå kun i wait, hvis denne variabel er sat • KonklusionSørg for at samle én begivenhed i ét synkroniseret monitorkald
Early notification • Problemnotify sendes før betingelserne for wait er opfyldt • Konsekvenswait-tråden vækkes før tid • LøsningCheck (igen) betingelserne for wait, når wait-tråden vækkes • KonklusionAnvend altid while (i stedet for if) i forbindelse med check af wait-betingelser
Early notification • Bufferen er tom! • C1-tråden er i wait-tilstand • P-tråden generer et nyt element og kalder monitorens synkroniserede put-metode • C1-tråden underrettes via notify, og tråden går i ready-tilstand • P-tråden forlader monitorens put-metode og slipper objekt-låsen på monitoren • Bufferen indeholder nu ét element! • Trådskifte! • C2-tråden trækker et element fra bufferen ved at kalde monitorens get-metode • C2-tråden forlader monitorens get-metode og slipper objekt-låsen på monitoren • Der er ingen elementer i bufferen! • Trådskifte! • C1 fortsætter nu fra wait i monitorens get-metode i forsøget på at trække endnu et element fra bufferen … Dette er ikke muligt!
Guarded Suspension publicsynchronizedvoid put(String data) throws InterruptedException { while (buffer.isFull()) // while i stedet for if this.wait(); if (buffer.isEmpty()) this.notify(); buffer.add(data); } public synchronized String get() throws InterruptedException { while (buffer.isEmpty()) // whilei stedet for if this.wait(); if (buffer.isFull()) this.notify(); String data = (String)buffer.remove(); return data; }
Distribueret Programmering • Sockets • RMI • CORBA (ej pensum) • JDBC (ej pensum)
Sockets • Sockets er logiske endepunkter i en forbindelse mellem server og klient • På applikationsniveauet betragtes Sockets som ”pålidelige”, dvs. data som sendes fra den ene ende af forbindelsen modtages i den anden ende i samme rækkefølge, som de er sendt, og uden tab • Sockets optræder parvis – klienten har en Socket til serveren og omvendt • En Socket er tilknyttet både en • InputStream • OutputStream • Klientens OutputStream er forbundet til serverens InputStream og omvendt
Sockets - Serversiden • Skab en ServerSocket på portnr 2000 (fx) try { ServerSocket s = new ServerSocket(2000); } catch (IOException e) {} • Vent på forespørgsel fra klient while (true) { Socket socket = s.accept(); } • Skab InputStream og OutputStream ud fra Socket BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); • Send og modtag via InputStream og OutputStream in.read(); out.println(); • Luk strømme og Sockets
Sockets - Klientsiden • Skab en Socket til serveren vha. hostname og portnr try { Socket s = new Socket(”localhost”, 2000); } catch(IOException e) {} • Skab InputStream og OutputStream ud fra Socket BufferedReader in = new BufferedReader( new InputStreamReader(s.getInputStream())); PrintWriter out = new PrintWriter(s.getOutputStream(), true); • Send og modtag via InputStream og OutputStream in.read(); out.println(); • Luk strømme og Socket
Flere samtidige klienter • Server class Server { publicstaticvoid main(String[] args) { try { ServerSocket s = new ServerSocket(2000); while (true) { // Vent på anmodning fra klient ... Socket socket = s.accept(); // Instantiér klienttråd - og start den ... new ClientHandler(socket).start(); } } catch (IOException e) {} } }
Flere samtidige klienter ClientHandler class ClientHandler extends Thread { private Socket incoming; public ClientHandler(Socket incoming) { this.incoming = incoming; } publicvoid run() { try { // Instantiér ind- og ud-strøm while (true) { // Kommunikér } } catch (IOException e) {} } }
RMI • RMI (Remote Method Invocation)Kald af metoder på serverobjekt fra klient • FilosofiObjekter på serveren gøres tilgængelige på klienten • Abstraktionsniveau • Højere abstraktionsniveau end Sockets • Objektorienteret – Syntaksen svarer til almindelig Java • Fælles data og funktionalitet • Transparens – Der arbejdes med serverobjekterne, som om de lå på klienten • MiljøRMI findes kun til Java
RMI - Arkitektur • Kald af metoden server.metode() fra klienten udføres som et metodeklad på stub’en: stub.metode() • Stub’en arrangerer argumenterne i metodekaldet, (marshalling), og sender dem til skeleton’en på serveren tillige med information om kaldet • Skeleton’en afkoder argumenterne samt informationen om kaldet, (demarshalling), og kalder metoden på serveren: server.metode() • Serverobjektet eksekverer metodekaldet og sender eventuel en returværdi til skeleton’en • Skeleton’en arrangerer returværdien, (marshalling), og sender resultatet til stub’en • Stub’en afkoder, (demarshalling), returværdien og returnerer den til klienten
RMI – Begreber • MarshallingArrangering af information om metodekald, dvs. objekt-id, metodenavn, argumenter og returværdier • Lokale objekterObjekter, som kun kan tilgås lokalt, enten på serveren eller på klienten.Lokale objekter, der overføres som argumenter eller returværdier skal implementere markør-interfacet Serializable • Remote objekterObjekter, som er tilgængelige fra andre maskiner/processer.Remote objekter skal implementere markør-interfacet Remote • Remote referenceReference til et objekt, der fysisk er placeret på en anden maskine/proces. Referencen indeholder ip-adresse, portnr samt objekt-id på serverobjektet • Remote metodekaldKald af servermetode fra klient. Ved remote metodekald overføres lokale objekter by value og remote objekter by reference
RMI - Serversiden import java.rmi.*; publicinterface Konto extends Remote { ... // metodeerklæringer publicdoubleindsaet(double beloeb) throws RemoteException; } import java.rmi.*; import java.rmi.server.UnicastRemoteObject; publicclass KontoServer extends UnicastRemoteObject implements Konto { ... // attributter double saldo; public KontoServer() throws RemoteException { super(); saldo = 0.0; } ... // metodeimplementeringer publicdoubleindsaet(double beloeb) throws RemoteException { saldo += beloeb; return saldo; } }
Forløbet af et RMI-kald (1) • Definér et interface (kontrakt) til et remote objekt publicinterface Konto extends java.rmi.Remote { ... public double indsaet(double beloeb) throws RemoteException; } • Implementér ovenstående interface på serversiden publicclass KontoServer extends java.rmi.server.UnicastRemoteObjectimplements Konto { ... publicdoubleindsaet(double beloeb)throws RemoteException; }
Forløbet af et RMI-kald (2) • Skab en instans af NameServer-objektet på en given port (fx 1099) vha. LocateRegistry java.rmi.registry.LocateRegistry.createRegistry(1099); • Skab en instans af serveren og registrér serveren i RMI-registry Konto server = new KontoServer(); java.rmi.Naming.rebind("Konto", server); • Generér stub og skeleton class-filer vha. RMI-compileFilerne får navnene KontoServer_Stub.class og KontoServer_Skeleton.classStub-klassen implementerer også Konto-interfacet
Forløbet af et RMI-kald (3) • Lokalisér remote objektet – konto er nu en instans af stub-klassen, som implementerer Konto-interfacet Konto konto = (Konto)java.rmi.Naming.lookup("//localhost:1099/Konto") • Lav en klient, som anvender metoderne på konto-objektet: konto.indsaet(100);
RMI – MathInterface package math; import java.rmi.*; publicinterface MathInterface extends Remote { publicint add(int a, int b) throws RemoteException; publicint sub(int a, int b) throws RemoteException; publicint mul(int a, int b) throws RemoteException; publicint div(int a, int b) throws RemoteException, ArithmeticException; }
RMI - MathServer package math; import java.rmi.*; import java.rmi.server.*; public class MathServer extends UnicastRemoteObject implements MathInterface { public MathServer() throws RemoteException {} publicint add(int a, int b) throws RemoteException{return a + b;} publicint sub(int a, int b) throws RemoteException{return a - b;} publicint mul(int a, int b) throws RemoteException{return a * b;} publicint div(int a, int b) throws RemoteException, ArithmeticException {return a / b;} }
RMI - Server package math; import java.rmi.*; import java.rmi.registry.*; publicclass Server { publicstaticvoid main(String[] args) { try { LocateRegistry.createRegistry(1099); Naming.bind("Math", new MathServer()); System.out.println("Serveren er registreret"); } catch (RemoteException e) {System.exit(1);} } }
RMI - Klient package math; import java.rmi.*; publicclass MathClient { publicstaticvoid main(String[] args) { MathInterface math = null; try { math = (MathInterface)Naming.lookup("Math"); System.out.println("1 + 2 = " + math.add(1, 2)); System.out.println("3 + 4 = " + math.add(3, 4)); System.out.println("5 + 6 = " + math.add(5, 6)); System.out.println("7 + 8 = " + math.add(7, 8)); } catch (Exception e) {System.exit(1);} } }