IN 147 Program og maskinvare. Vranglås De spisende filosofer Lettvektsprosesser Moderne synkroniseringsmetoder Meldinger Monitorer Linda

Like dokumenter
IN 147 Program og maskinvare

Kort notat om parallellstyring IN147

IN 147 Program og maskinvare. Dagens tema:

Oppsummering av IN147 siste del Operativsystemer Parallellisering Veien videre

Dagens tema: Synkronisering

Dagens tema: Synkronisering

Dagens program. Operativsystemer Prosesser og systemkall i UNIX Hente prosessens nummer Starte prosesser Vente på prosesser Utføre programmer

Løsningsforslag til eksamen i IN 147 og IN 147A

Programmeringsspråket C

Dagens tema C, adresser og pekere

Ark 3 av 26. printf("i adresse %08x ligger b med verdien %d.\n", &b, b); printf("i adresse %08x ligger a med verdien %d.

Sortering med tråder - Quicksort

Del 4 Noen spesielle C-elementer

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

Oversikt over IN147(A):

Stein Gjessing. Institutt for informatikk. Universitetet i Oslo. Institutt for informatikk

Programmeringsspråket C

Avdeling for ingeniørutdanning Institutt for teknologi

Del 1 En oversikt over C-programmering

Programmeringsspråket C

Dagens tema. Hva er kompilering? Anta at vi lager dette lille programmet doble.rusc (kalt kildekoden): Hva er kompilering?

UNIVERSITETET I OSLO

I et Java-program må programmøren lage og starte hver tråd som programmet bruker. Er dette korrekt? Velg ett alternativ

Synkronisering II. Kapittel 7. Betingelse oppfylt (0) liste. tråd-deskriptor. venteliste. tråd-deskriptor. tråd-deskriptor.

Dagens tema. C-programmering. Nøkkelen til å forstå C-programmering ligger i å forstå hvordan minnet brukes.

Dagens tema: Parallellstyring

La oss begynne med en repetisjon av hva som skjer når du kjører Javaprogrammet

IN 147 Program og maskinvare

IN 147 Program og maskinvare

Oppsummering. Kort gjennomgang av klasser etc ved å løse halvparten av eksamen Klasser. Datastrukturer. Interface Subklasser Klasseparametre

Dagens tema INF1070. Vektorer (array er) Tekster (string er) Adresser og pekere. Dynamisk allokering

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

INF1010 Tråder J. Marit Nybakken Motivasjon. Å lage en tråd

Dagens tema. Nyttige programmer Programmet make. Flyt-tall Representasjon av flyt-tall. Standarden IEEE 754. Systemkall i Unix

Tråder Repetisjon. 9. og 13. mai Tråder

Eksamen INF1010 V2009 Del B prøveeksamen V2010 Vekt 60 %

INF 1010, vår 2005 Løsningsforslag uke 11

Kompilering Statiske Syntaksanalyse Feilsjekking Eksempel Oppsummering

Programmeringsspråket C Del 3

Kapittel 1 En oversikt over C-språket

Dagens tema: Datastrukturer

OPPGAVE 1 OBLIGATORISKE OPPGAVER (OBLIG 1) (1) Uten å selv implementere og kjøre koden under, hva skriver koden ut til konsollen?

Del 3: Evaluere uttrykk

Programmeringsspråket C Del 3

Vektorer. Dagens tema. Deklarasjon. Bruk

IN 147 Program og maskinvare

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

INF2100. Oppgaver 23. og 24. september 2010

Tråder Repetisjon. 9. og 13. mai Tråder

GUI («Graphical User Interface») del 2

Dagens tema. Nyttige programmer Programmet make. Hvis én fil endres, hvilke filer må da kompileres på nytt?

EKSAMEN. Operativsystemer. 1. Læreboken "A Practical Guide to Red Hat Linux" av Mark Sobell 2. Maks. tre A-4 ark med selvskrevne notater.

GetMutex(lock) { while(testandset(lock)) {} } En context switch kan ikke ødelegge siden testen og endringen av lock skjer i samme instruksjon.

Fra Python til Java, del 2

Mer om C programmering og cuncurrency

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

Programmeringsspråket C Del 3

Programmeringsspråket C Del 3

Løsningsforslag til eksamen i IN 147(A)

Synkronisering I. Kapittel 6. Tråd A. ferdig. t.varsle() u.vente() Tråd B. ferdig. tid

IN 147 Program og maskinvare

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

IN 211 Programmeringsspråk. Java. på 20 enkle ark. spesielt for de som kan. Simula. (og gjerne litt C) Ark 1 av 20

Programmering i C++ Løsningsforslag Eksamen høsten 2005

UNIVERSITETET I OSLO

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

Side 1 av 11, prosesser, tråder, synkronisering, V. Holmstedt, HiO 2006

Plan: Parameter-overføring Alias Typer (Ghezzi&Jazayeri kap.3 frem til 3.3.1) IN 211 Programmeringsspråk

INF2100. Oppgaver uke 40 og

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

2 Om statiske variable/konstanter og statiske metoder.

IN1010 våren Repetisjon av tråder. 15. mai 2018

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

Fra Python til Java. En introduksjon til programmeringsspråkenes verden. Dag Langmyhr

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

GJØVIK INGENIØRHØGSKOLE

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Repetisjon: Statiske språk uten rekursive metoder (C1 og C2) Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

INF Notater. Veronika Heimsbakk 10. juni 2012

Forelesning inf Java 5

Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

Forelesning inf Java 5

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

IN 147 Program og maskinvare

Gjennomgang av eksamen H99

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

UNIVERSITETET I OSLO

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

INF2100. Oppgaver 9. oktober 2012 C 100 X 10

UNIVERSITETET I OSLO

Dagens tema. Mer om C Enkle datatyper Sammensatte datatyper: Vektorer og matriser Tekster Mengder Strukturer Unioner Ringbuffere

Dagens tema: 12 gode råd for en kompilatorskriver

INF2100. Oppgaver 6. og 11. oktober 2011 C 100 X 10

Dagens tema. Hva er kompilering? Anta at vi lager dette lille programmet (kalt kildekoden): Hva er kompilering?

Dagens tema. Adresser som parametre Dynamisk allokering Signaturer Definisjon av nye typenavn Typekonvertering Pekere og vektorer

Dagens forelesning. Java 13. Rollefordeling (variant 1) Rollefordeling (variant 2) Design av større programmer : fordeling av roller.

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

Transkript:

Dagens tema: Vranglås De spisende filosofer Lettvektsprosesser Moderne synkroniseringsmetoder Meldinger Monitorer Linda Hvorfor nyttig? Parallellstyring brukes mye innen operativsystemer, systemprogrammer, kommunikasjon og nettverksprogrammer, databaser og programmer parallellisert av hensyn til hastigheten. Ark 1 av 27 Forelesning 3.5.2000

Vranglås Av og til kan det skje at flere prosesser venter på hverandre, for eksempel A skriver fil F A og trenger å lese F B. B skriver fil F B og trenger å lese F A. Hvis det å skrive på en fil låser den, har vi en vranglåssituasjon. Løsning Den eneste måten å løse opp en slik situasjon på er å drepe en av prosessene. Forhåpentligvis kan den startes på nytt igjen. Forelesning 3.5.2000 Ark 2 av 27

Hvordan løse vranglås? Dette har det vært forsket mye på. Noen muligheter er: Programmere slik at de ikke oppstår! Skrive programmene slik at de kan startes på nytt om noe går galt. Lære å leve med dem («strutsemetoden»). Forelesning 3.5.2000 Ark 3 av 27

Endelig: et forslag som fungerer Denne løsningen ble funnet av Edsger Dijkstra: #define N 5 #define LEFT(x) ((x)==0? N-1 : (x)-1) #define RIGHT(x) ((x)==n-1? 0 : (x)+1) enum Status {Tenker, Sulten, Spiser; enum Status stat[n]; semaphore mutex = 1; semaphore s[n]; void philosopher(i) /* Filosof nr. i */ int i; { while (TRUE) { think(); take_forks(i); eat(); put_forks(i); void take_forks(i) /* Få tak i 2 gafler. */ int i; { down(&mutex); /* Kritisk region... */ stat[i] = Sulten; /* Fortell om sulten. */ test(i); /* Prøv å få 2 gafler. */ up(&mutex); /*...kritisk region. */ down(&s[i]); /* Blokkér uten gafler. */ Forelesning 3.5.2000 Ark 4 av 27

void put_forks(i) /* Legg gaflene tilbake. */ int i; { down(&mutex); /* Kritisk region... */ stat[i] = Tenker; /* Fortell hva jeg gjør. */ test(left(i)); /* Sjekk om en nabo */ test(right(i)); /* vil spise nå. */ up(&mutex); /*...kritisk region. */ void test(i) /* Kan filosof nr i spise? */ int i; { if (stat[i] == Sulten && stat[left(i)]!= Spiser && stat[right(i)]!= Spiser) { stat[i] = Spiser; /* Nå kan nr. i spise. */ up(&s[i]); Forelesning 3.5.2000 Ark 5 av 27

Hvorledes fungerer dette opplegget? philosopher er filosof-prosessene. Hver filosof veksler mellom å tenke, bli sulten og ta opp to gafler (take forks vil blokkere inntil de aktuelle to gaflene er ledige), spise, og legge fra seg gaflene. take forks endrer filosofens status til Sulten. Så sjekkes (i funksjonen test) om filosofen kan spise; i så fall avsluttes rutinen; hvis ikke blokkeres på down(&s[i]). put forks vil legge fra seg gaflene og endre filosofens status til Tenker. Så sjekkes de to naboene; hvis de ønsket å spise og kan gjøre det nå, får de lov til det (up(&s[i])). test sjekker om en spesiell filosof (angitt som parameter) kan spise. I så fall endres status til Spiser, og det foretas en up(&s[i]). Avhengig av kallet kan dette ha to effekter: Hvis test ble kalt fra take forks, vil det siste down-kallet der gå glatt. Hvis test ble kalt fra put forks, vil den aktuelle filosofen være blokkert på det siste down-kallet i take forks, og vil nå få lov å spise. Forelesning 3.5.2000 Ark 6 av 27

Lettvektsprosesser Det er vanlig å tegne en prosess slik: Stakk Data Kode En lettvektsprosess (ofte kalt «tråd») deler data- og kodelager med opphavet: Stakk Stakk Data Kode Dataoverføring er da ikke lenger noe problem, men synkronisering er stadig nødvendig. Forelesning 3.5.2000 Ark 7 av 27

Lettvektsprosesser i Java I Java kan man opprette lettvektsprosesser ved å deklarere subklasser av Thread som inneholder en metode run: class PingPong extends Thread { String id; int ventetid; PingPong(String idx, int ventx) { id = idx; ventetid = ventx; public void run() { try { while (true) { System.out.print(id + " "); sleep(ventetid); catch (Exception e) { return; public static void main(string args[]) { new PingPong("ping", 33).start(); new PingPong("PONG", 84).start(); Metoden start() brukes til å starte tråden, og stop() til å stoppe den. maskin navn> java PingPong ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping PONG ping ping Forelesning 3.5.2000 Ark 8 av 27

Parallellstyring på høyt nivå Teknikkene beskrevet hittil har vært mellomnivåteknikker; de fungerer fint hvis programmeren behersker dem tilstrekkelig godt og ikke gjør feil. Feil bruk av semaforer semaphore mutex = 1; semaphore empty = N; /* Teller tomme */ semaphore full = 0; /* Teller fulle */ void producer() { int item; while (TRUE) { produce_item(&item); down(&mutex); down(&empty); /* Byttet! */ enter_item(item); up(&mutex); up(&full); void consumer() { int item; while (TRUE) { down(&full); down(&mutex); remove_item(&item); up(&mutex); up(&empty); consume_item(item); Forelesning 3.5.2000 Ark 9 av 27

Her kan følgende skje: 1. Vi antar at produsenten har vært raskere enn konsumenten slik at bufferen nå er full. 2. Produsenten lager enda ett element. Så utfører den down(&mutex) og går inn i kritisk region, og deretter down(&empty). Nå blokkeres den fordi bufferen er full. 3. Så skjer et prosessbytte. 4. Konsumenten gjør en down(&full) og deretter en down(&mutex) for å gå inn i kritisk region. Da blokkeres den, fordi produsenten allerede er i kritisk region. Vi har altså fått en situasjon med vranglås fordi to kall på down ble byttet om. Vi ønsker oss mer høynivå mekanismer hvor det er lettere å unngå slikt. Forelesning 3.5.2000 Ark 10 av 27

Meldinger Mange parallelle systemer er basert på en mekanisme som kalles meldinger. Det finnes mange varianter; én ser slik ut: Oversikt over meldinger Det finnes kun to operatorer for meldinger: send(q, kode, data ) sender meldingen data til meldingskøen q. Senderen blokkeren hvis køen er full, ellers ikke. receive(q, kode, & data ) henter en melding med angitt kode fra køen q. Henteren blokkeres inntil det finnes meldinger i køen. Forelesning 3.5.2000 Ark 11 av 27

Bruk av UNIX-meldinger #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> typedef struct { long id; char data[200]; mess_struct; void barn(int n, int q) { mess_struct m; int r_stat; printf("dette er barn nr %d\n", n); r_stat = msgrcv(q, &m, sizeof(m), n, 0); printf("barn %d: status=%d, id=%d, data=\"%s\"\n", n, r_stat, m.id, m.data); Meldingene er av typen mess struct; legg merke til at koden ligger i første ord. Barne henter en melding med riktig kode (n) fra køen q (med msgrcv) og skriver ut data de får. maskin navn> q Dette er barn nr 1 Dette er barn nr 2 Barn 2: status=204, id=2, data="dette er post 2." Barn 1: status=204, id=1, data="dette er post 1." Forelesning 3.5.2000 Ark 12 av 27

int main(void) { mess_struct m1, m2; int q, status; q = msgget(ipc_private, 0700); /* Opprett køen */ if (q < 0) { perror("q"); exit(1); if (safefork() == 0) { barn(1,q); exit(0); if (safefork() == 0) { barn(2,q); exit(0); m1.id = 1; strcpy(m1.data, "Dette er post 1."); m2.id = 2; strcpy(m2.data, "Dette er post 2."); if (msgsnd(q,&m2,sizeof(m2),0)<0) { perror("q"); exit(12); if (msgsnd(q,&m1,sizeof(m1),0)<0) { perror("q"); exit(11); wait(&status); wait(&status); /* Vent på barna */ msgctl(q, IPC_RMID, NULL); /* Fjern køen */ Hovedprogrammet gjør følgende: 1. oppretter en meldingeskø q, 2. oppretter to barneprosesser, 3. bygger opp to meldinger m1 og m2, 4. sender de to meldingene til køen q, 5. venter til barna dør og 6. fjerner køen q. Forelesning 3.5.2000 Ark 13 av 27

Vurdering + Meldinger er enkle å bruke og forstå. + De er enkle å implementere. Resultatet er at meldinger brukes svært mye. Forelesning 3.5.2000 Ark 14 av 27

Monitorer Den aller første høynivåløsningen ble oppfunnetavc.a.r.hoareogper Brinch-Hansen i 1974. Den består av en klasse-lignende struktur kalt en monitor: class Eksempel { int i; // Lokal variabel. void synchronized p(...) {. wait();. notify();. // Operator: Eksempel e; e :- new Eksempel(); e.p(...); Forelesning 3.5.2000 Ark 15 av 27

Følgende gjelder for monitorer: Kun én prosess av gangen får utføre en operator i en monitor. Ytterligere forsøk på kall vil bli blokkert inntil monitoren er ledig. (I Java angis dette med synchronized.) Alle de lokale variablene er usynlige utenfor monitoren. (Dette kreves ikke i Java, men jeg anbefaler det.) En monitor kan blokkere seg selv ved å benytte wait() vil blokkere prosessen. Monitoren vil da bli åpnet for andre prosesser. notify() vil starte en eller annen prosess som tidligere ble blokkert ved å utføre wait(). Forelesning 3.5.2000 Ark 16 av 27

PK-problemet med Javas monitorer Produsenten class Producer extends Thread { Monitor m; intx,i,s,n; Producer(int start, int inkr, int sleep, Monitor mx) { x = start; i = inkr; s = sleep; m = mx; n = 0; public void run() { while (n < 20) { m.enter(x); x += i; ++n; try { sleep(s); catch (Exception e) { return; Produsenten er en lettvektsprosess som genererer 20 tall x, x + i,x + 2i,...,x+19i som sendes til monitoren med m.enter(x). Etter hvert tall sover prosessen litt. Forelesning 3.5.2000 Ark 17 av 27

Konsumenten class Consumer extends Thread { Monitor m; Consumer(Monitor mx) { m = mx; setdaemon(true); public void run() { int n_on_line = 0; while (true) { int x = m.remove(); System.out.print(x + " "); if (++n_on_line%10 == 0) System.out.println(""); Konsumenten er en lettvektsprosess som henter tall fra monitoren med m.remove() og skriver dem ut, 10 på hver linje. Konsumenten er konfigurert som demon slik at den automatisk drepes når alle brukerprosessene er ferdige. Forelesning 3.5.2000 Ark 18 av 27

Monitoren (med hovedprogrammet) class Monitor { // En ringbuffer: private int buf[], inn_p = 0, ut_p = 0, n = 0; Monitor() { buf = new int[10]; public synchronized void enter(int x) { try { while (n == 10) wait(); catch (Exception e) { System.exit(1); buf[inn_p++] = x; ++n; if (inn_p >= 10) inn_p = 0; notify(); public synchronized int remove() { int res; try { while (n == 0) wait(); catch (Exception e) { System.exit(2); res = buf[ut_p++]; --n; if (ut_p >= 10) ut_p = 0; notify(); return res; public static void main(string args[]) { Monitor m = new Monitor(); new Producer(1,2,25,m).start(); new Producer(101,1,40,m).start(); new Consumer(m).start(); Forelesning 3.5.2000 Ark 19 av 27

Hoveprogrammet Hovedprogrammet main oppretter en monitor. Så oppretter den to produsenter og én konsument som startes. Monitoren Monitoren har en privat ringbuffer til bufring av 10 tall. Den har to operatorer: enter venter først til det er plass i ringbufferen. Så setter den inn et element og kaller notify (i tilfelle en konsument venter). remove venter først til det er noen elementer i ringbufferen. Så henter den ett element derfra som skal returneres. Først kaller den imidlertid notify (i tilfelle noen produsenter venter). Siden ringbufferen er private og operatorene er synchronized, er parallellstyringen sikker. Kjøring Slik blir en kjøring: maskin navn> java Monitor 1 101 3 102 5 103 7 9 104 11 105 13 15 106 17 107 19 21 108 23 109 25 27 110 29 111 31 33 112 35 113 37 39 114 115 116 117 118 119 120 Forelesning 3.5.2000 Ark 20 av 27

Vurdering + Monitorer er meget sikre. Kompilatoren vil ta seg av det meste av parallellitetskontrollen. + De er enkle å bruke. Det er lettere å unngå vranglås. + Det er trivielt å overføre data mellom prosessene (ved å benytte parametre til monitor-operatorene). + De gir anledning til strukturert programmering, siden monitorer er en form for abstrakte typer. Monitorer krever et eget språk; det er ikke nok å skrive noen rutiner. Svært få språk har monitorer. Konklusjon Monitorer er ypperlige, hvis de finnes. Forelesning 3.5.2000 Ark 21 av 27

Linda Linda er et av de aller nyeste konseptene for prosesskommunikasjon. Det er basert på tanken om at det finnes et eget lager for tupler hvor prosessene kan lagre og lese tupler. Et tuppel er en datastruktur med vilkårlig mange elementer; i Linda er hvert element er enten en verdi (av en eller annen type) eller en «potensiell verdi». Eksempler er (2, 4) ("Test", 4, 3) ("Melding",?x) (Her er?x er potensiell verdi.) Forelesning 3.5.2000 Ark 22 av 27

Følgende atomiske operasjoner finnes i Linda: out(t 1,...,t n )beregner alle tuppelelementene og legger det ferdige tuppelet i det felles tuppel-lageret. eval(t 1,...,t n )fungerer som out, men tuplene beregnes i parallell etter at tuppel er lagret. Mens beregningene foregår kalles tuppelet et aktivt tuppel. in(t 1,...,t n )henter et tuppel som «passer»; prosessen blokkeres inntil et slik tuppel eksistrerer. rd(t 1,...,t n )fungerer som in, men lar kopi av tuppelet bli liggende i lageret. Forelesning 3.5.2000 Ark 23 av 27

Operasjonene in og rd leter etter tupler som passer med det som er oppgitt som parameter. Et tuppel passer hvis det er passivt, har like mange elementer, hvert tilsvarende element er av samme type, og hvert tilsvarende element har samme verdi, eller det ene er en potensiell verdi. Enkel bruk av Linda Følgende lille program vil beregne kvadratroten av tre tall i parallell: float a, b, c;. eval("kvadrot",sqrt(9.0),sqrt(16.0),sqrt(25.0)); in ("Kvadrot",?a,?b,?c); Forelesning 3.5.2000 Ark 24 av 27

Dette vil skje: 1. Først vil kallet på eval legge det aktive tuppelet (med 4 elementer) i tuppel-lageret. 2. Så startes 4 nye prosesser som vil gå parallelt for å beregne de fire parametrene. 3. Når alle beregningene er gjort, registreres tuppelet som passivt. 4. Kallet på in vil lete etter tupler med 4 elementer: en tekst og 3 float-verdier; teksten skal ha verdien "Kvadrot". (Hvis dette kallet kommer før beregningene av de tre kvadratrøttene er ferdig, blir det blokkert inntil alt er klart.) 5. Resultatene kopieres over i variablene: a blir 3.0, b blir 4.0 og c blir 5.0. Forelesning 3.5.2000 Ark 25 av 27

Beskyttelse av kritisk region Følgende enkle teknikk kan benyttes til å beskytte en kritisk region: out("kritreg1"); /* Initiering */. in("kritreg1"); Kritisk region 1 out("kritreg1");. Oppsummering + Rimelig enkelt å implementere (men ikke så enkelt som meldinger). + Lett å bruke, men allikevel kraftig. Ideene om ulikt antall parametre og potensielle verdier kan skape problemer vis-a-vis programmeringsspråket. Ennå ikke veldig utbredt. Forelesning 3.5.2000 Ark 26 av 27

Oppsummering av teknikker Teknikk UNIX filer Synk Data Spesielt UNIX rør Forutsetter samme urprosess Delt lager Lettvektsprosesser Semaforer Meldinger Monitorer Lite brukt Linda Ennå lite brukt Forelesning 3.5.2000 Ark 27 av 27