1 / 79

Les 4: Synchronisatie

Les 4: Synchronisatie. If debugging is the process of removing bugs, then programming must be the process of putting them in. (Edsger W. Dijkstra). Overzicht. Wat is synchronisatie? Software-oplossingen Hardware-oplossingen Semafoor Monitor Transactioneel geheugen Boodschappen Impasses.

ava-holt
Télécharger la présentation

Les 4: Synchronisatie

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Les 4: Synchronisatie If debugging is the process of removing bugs, then programming must be the process of putting them in.(Edsger W. Dijkstra)

  2. Overzicht • Wat is synchronisatie? • Software-oplossingen • Hardware-oplossingen • Semafoor • Monitor • Transactioneel geheugen • Boodschappen • Impasses

  3. Doelstelling • Het in goede banen leiden van de interactie tussen processen of draden • Doorgeven van informatie • Vastleggen van volgorde • Wederzijdse uitsluiting • Bij foute synchronisatie • Raceconditie (‘te weinig synchronisatie’) • Impasse (‘te veel synchronisatie’)

  4. Doorgeven van informatie • B.v.: “ls | wc” • Methoden: • Via bestanden, pipes, sockets • Via boodschappen (send/receive) • Via een blok gemeenschappelijk geheugen • Via kernstructuren (b.v. semaforen) • Bij draden is het gebruik van gemeenschappelijk geheugen het meest voor de hand liggend

  5. Volgorde vastleggen Proces 1 Proces 2 wacht [ A A → B [ signaleer [ B [ t t

  6. Wederzijdse uitsluiting De secties A en B zijn wederzijds uitgesloten Proces 1 Proces 2 Proces 1 Proces 2 [ [ A B [ [ of [ [ A → B A B → A B [ [ t t t t

  7. Gebruik van gemeenschappelijke data Draad 1 Draad 2 teller [ A: teller ++ [ load r1, teller add r1, 1 store teller, r1 load r1, teller sub r1, 1 store teller, r1 [ A → B B: teller-- [ raceconditie t t

  8. Raceconditie  fout resultaat Proces 1 Proces 2 Juist [ [ [ [ t t Fout Proces 1 Proces 2 [ [ [ [ t t Juist

  9. Raceconditie var ← 0 var ← 0 var ← 0 lees schrijf schrijf schrijf lees lees r ← var r ← var var ← 5 var ← 3 r ← var var ← 3 r = 0 ? 3 ? var = 3 ? 5 ? r = 0

  10. Kritieke Sectie

  11. Kritieke Sectie Ingangssectie Ingangssectie load r1,teller add r1, 1 store r1,teller load r1,teller sub r1, 1 store r1,teller Uitgangssectie Uitgangssectie

  12. Protocolvoorwaarden • wederzijdse uitsluiting garanderen slechts 1 proces per keer in een kritieke sectie • vooruitgang garanderen een lege sectie moet kunnen betreden worden • eindige wachttijden garanderen het aantal vóór te laten processen moet eindig zijn Er mogen geen veronderstellingen over snelheid of over het aantal processors gemaakt worden.

  13. Overzicht • Wat is synchronisatie? • Software-oplossingen • Hardware-oplossingen • Semafoor • Monitor • Transactioneel geheugen • Boodschappen • Impasses

  14. Oplossing met twee processen enteringCriticalSection(0) enteringCriticalSection(1) kritieke sectie 2 kritieke sectie 1 leavingCriticalSection(0) leavingCriticalSection(1) public interface MutualExclusion { public abstract void enteringCriticalSection(int turn); public abstract void leavingCriticalSection(int turn); }

  15. Beurtelings protocol public class Algorithm_1 implements MutualExclusion { private volatile int turn; public Algorithm_1() { turn = 0; } public void enteringCriticalSection(int t) { while (turn != t) Thread.yield(); } public void leavingCriticalSection(int t) { turn = 1 - t; } } Geen vooruitgang gegarandeerd

  16. Hoffelijk protocol public class Algorithm_2 implements MutualExclusion { private volatile boolean flag[2]; public Algorithm 2() { flag[0] = false; flag[1] = false; } public void enteringCriticalSection(int t) { flag[t] = true; while(flag[1-t] == true) Thread.yield(); } public void leavingCriticalSection(int t) { flag[t] = false; } } Geen vooruitgang gegarandeerd

  17. Algoritme van Peterson public class Algorithm_3 implements MutualExclusion { private volatile boolean flag[2]; private volatile int turn; public Algorithm 3() { flag[0] = false; flag[1] = false; turn = 1; } public void enteringCriticalSection(int t) { flag[t] = true; turn = 1-t; while (flag[1-t] == true && turn == 1-t) Thread.yield(); } public void leavingCriticalSection(int t) { flag[t] = false; } } Peterson, algoritme van

  18. Overzicht • Wat is synchronisatie? • Software-oplossingen • Hardware-oplossingen • Semafoor • Monitor • Transactioneel geheugen • Boodschappen • Impasses

  19. Hardware-oplossingen • Afzetten van de onderbrekingen • Read-modify-write instructies • SWAP • TAS • CAS

  20. Afzetten onderbrekingen cli cli kritieke sectie 2 kritieke sectie 1 sti sti

  21. Synchronisatieprotocol met SWAP en actieve synchronisatie locked LOADI R1,1 L: SWAP R1,locked COMPARE R1,1 JE L LOADI R1,1 L: SWAP R1,locked COMPARE R1,1 JE L kritieke sectie 2 kritieke sectie 1 LOADI R1,0 SWAP R1,locked LOADI R1,0 SWAP R1,locked Spin Lock swap r1, [n] ; x := mem[n]; mem[n] := r1; r1 := x;

  22. Synchronisatieprotocol met SWAP en zonder actieve synchronisatie locked LOADI R1,1 L: SWAP R1,locked COMPARE R1,1 JNE OK “CALL YIELD” JMP L OK: LOADI R1,1 L: SWAP R1,locked COMPARE R1,1 JNE OK “CALL YIELD” JMP L OK: kritieke sectie 2 kritieke sectie 1 LOADI R1,0 SWAP R1,locked LOADI R1,0 SWAP R1,locked Gevaar op LiveLock

  23. Synchronisatieprotocol met eindige wachttijd LOADI R1,1 SWAP R1,locked COMPARE R1,1 JNE OK “store draad_id” “call blokkeer” OK: LOADI R1,1 SWAP R1,locked COMPARE R1,1 JNE OK “store draad_id” “call blokkeer” OK: kritieke sectie 2 kritieke sectie 1 Indien  geblokkeerde draad deblokkeer oudste draad anders LOADI R1,0 SWAP R1,locked Indien  geblokkeerde draad deblokkeer oudste draad anders LOADI R1,0 SWAP R1,locked

  24. Overzicht • Wat is synchronisatie? • Software-oplossingen • Hardware-oplossingen • Semafoor • Monitor • Transactioneel geheugen • Boodschappen • Impasses Edsger Wybe Dijkstra (1930– 2002)

  25. Semafoor (Dijkstra, 1965)

  26. Semafoor s=1 acquire(s) acquire(s) kritieke sectie 2 kritieke sectie 1 release(s) release(s)

  27. Implementatie binaire semafoor LOADI R1,0 L: SWAP R1,sema COMPARE R1,0 JE L kritieke sectie LOADI R1,1 STORE R1,sema wederzijds uitgesloten vooruitgang geen eindige wachttijd

  28. Binaire semafoor vs. tellende semafoor • Tellende semafoor (Counting semaphore) • Geïnitialiseerd met een natuurlijk getal • Acquire() decrementeert; bij 0 wordt er geblokkeerd • Release() incrementeert • Binaire semafoor = tellende semafoor met initiële waarde = 1 • Mutex = binaire semafoor waarbij acquire() en release() door dezelfde draad moeten gebeuren

  29. Gebruik Semaforen D1 D2 D1 D2 D1 D2 I+A I I A A R R A R A A R R Wederzijdse uitsluiting (mutex) Wachten

  30. Problemen met semaforen • Ongestructureerd – kan leiden tot synchronisatiefouten zoals race condities en impasses.

  31. Klassieke synchronisatieproblemen • Eindige buffer • Lezers-schrijversprobleem • Dinerende filosofen • Barrier

  32. Eindige buffer met semaforen public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileObject[] buffer; private volatile int in, out; private volatileSemaphore insertmutex; private volatileSemaphore removemutex; private volatileSemaphore empty; private volatileSemaphore full;

  33. Eindige buffer met semaforen empty = 3 full = 2 4 public BoundedBuffer() { // buffer is initially empty in = 0; out = 0; buffer = new Object[BUFFER_SIZE]; insertmutex = new Semaphore(1); removemutex = new Semaphore(1); empty = new Semaphore(BUFFER_SIZE); full = new Semaphore(0); } 3 out=0 0 2 1 in=2

  34. Eindige buffer met semaforen public Object remove() { full.acquire(); removemutex.acquire(); // remove an item from the buffer Object item = buffer[out]; out = (out+1) % BUFFER_SIZE; removemutex.release(); empty.release(); return item; } public void insert(Object item) { empty.acquire(); insertmutex.acquire(); // add an item to the buffer buffer[in] = item; in = (in+1) % BUFFER_SIZE; insertmutex.release(); full.release(); }

  35. Lezers-schrijversprobleem: Interface public interface RWLock { public abstract void acquireReadLock(); public abstract void acquireWriteLock(); public abstract void releaseReadLock(); public abstract void releaseWriteLock(); }

  36. Dinerende filosofen Semaphore chopStick[] = new Semaphore[5];

  37. Dinerende filosofen public void philosopher(int i) { while (true) { // get left chopstick chopStick[i].acquire(); // get right chopstick chopStick[(i + 1) % 5].acquire(); eating(); // return left chopstick chopStick[i].release(); // return right chopstick chopStick[(i + 1) % 5].release(); thinking(); } }

  38. Barriers

  39. Overzicht • Wat is synchronisatie? • Software-oplossingen • Hardware-oplossingen • Semafoor • Monitor • Transactioneel geheugen • Boodschappen • Impasse

  40. Monitor monitor monitor-name { // variable declarations procedure p1(…) { … } procedure p2(…) { … } }

  41. Monitor Ingangssectie Ingangssectie insert(item) insert(item) Uitgangssectie Uitgangssectie

  42. Eindige buffer met monitor Monitor BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileObject[] buffer; private volatileint in, out, count; public BoundedBuffer() { in = 0; out = 0; count = 0; buffer = new Object[BUFFER_SIZE]; } public void insert(Object item) { if (count < BUFFER_SIZE) { count++; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; } else raise Exception.Create(“buffer vol”); } public Object remove() { if (count > 0) { Object item = buffer[out]; count--; out = (out + 1) % BUFFER_SIZE; return item; } else raise Exception.Create(“buffer leeg”); } } In pseudo-Java stijl

  43. Conditieveranderlijken condition x; x.wait() x.signal()

  44. Eindige buffer met monitor en condities Monitor BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileObject[] buffer; private volatile int in, out, count; private volatile Condition notempty, notfull; public BoundedBuffer() { in = 0; out = 0; count = 0; buffer = new Object[BUFFER_SIZE]; notempty = new Condition; notfull = new Condition; } public void insert(Object item) { while (count == BUFFER_SIZE) notfull.wait(); count++; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; if (count == 1) notempty.signal(); } public Object remove() { Object item; while (count == 0) notempty.wait(); count--; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; if (count == BUFFER_SIZE-1) notfull.signal(); return item; } } In pseudo-Java stijl

  45. Eindige buffer met Semaforen & condities public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileObject[] buffer; private volatileint in, out, count; private volatile Condition notempty, notfull; private volatile Semaphore mutex; public BoundedBuffer() { in = 0; out = 0; count = 0; buffer = new Object[BUFFER_SIZE]; notempty = new Condition; notfull = new Condition;mutex = new Semaphore(1); } public void insert(Object item) { mutex.acquire(); while (count == BUFFER_SIZE) { mutex.release(); notfull.wait(); mutex.acquire(); } count++; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; if (count == 1) notempty.signal(); mutex.release(); } public Object remove() { Object item; mutex.acquire(); while (count == 0) { mutex.release(); notempty.wait(); mutex.acquire(); } count--; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; if (count == BUFFER_SIZE-1) notfull.signal(); mutex.release(); return item; } } Lost signal race notfull.signal() Niet persistent

  46. Eindige buffer met semaforen en condities public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileObject[] buffer; private volatileint in, out, count; private volatile Condition notempty, notfull; private volatile Semaphore mutex; public BoundedBuffer() { in = 0; out = 0; count = 0; buffer = new Object[BUFFER_SIZE]; notempty = new Condition; notfull = new Condition; mutex = new Semaphore(1); } public void insert(Object item) { mutex.acquire(); while (count == BUFFER_SIZE) notfull.wait(mutex); count++; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; if (count == 1) notempty.signal; mutex.release(); } public Object remove() { Object item; mutex.acquire(); while (count == 0) notempty.wait(mutex); count--; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; if (count == BUFFER_SIZE-1) notfull.signal; mutex.release(); return item; } }

  47. Semaforen + wait/signal s=1 acquire(s) acquire(s) ... cond.wait(s) ... ... cond.signal() ... release(s) release(s)

  48. Eindige buffer met Java synchronisatie public class BoundedBuffer implements Buffer { private static final int BUFFER_SIZE = 5; private volatileint count, in, out; private volatileObject[] buffer; public BoundedBuffer() {// buffer is initially empty count = 0; in = 0; out = 0; buffer = new Object[BUFFER_SIZE]; } publicsynchronizedvoid insert(Object item) { … } publicsynchronizedObject remove() { … } } intrinsieke lock

  49. insert() met wait/notify methoden public synchronized void insert(Object item) { while (count == BUFFER_SIZE) { try { wait(); } catch (InterruptedException e) { } } ++count; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; notify(); }

  50. remove() met wait/notify methoden public synchronized Object remove() { Object item; while (count == 0) { try { wait(); } catch (InterruptedException e) { } } --count; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; notify(); return item; }

More Related