1213 Threads [4] Sincronització
Upcoming SlideShare
Loading in...5
×
 

1213 Threads [4] Sincronització

on

  • 170 views

 

Statistics

Views

Total Views
170
Views on SlideShare
170
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

1213 Threads [4] Sincronització 1213 Threads [4] Sincronització Presentation Transcript

  • PROGRAMACIÓ   CONCURRENT   4   Sincronització  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Els   fils   (threads)   tenen   un   costat   f o s c :   P o d e n d o n a r l l o c a problemes de concurrència.     Els problemes de concurrència   donen   lloc   a   “condicions   de   carrera“  (race  condi*ons).  Les  “condicions  de  carrera”  donen   lloc  a  dades  corruptes.       Hem   arribat   a   una   situació   fa1dica:   Dos   o   més   fils   accedint   a   les   dades  d’un  únic  objecte.       Quan  un  fil  no  està  acMu  o  corrent  és  com  si  esMgués  inconscient.   Quan  (de  nou)  és  acMvat  no  sap  que  ha  estat  aturat.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  Hora   Persona  1   Persona  2  15:00   Mirar  en  la  nevera:  No  hi  ha   llet!!  15:05   SorMr  al  carrer  15:10   Arribar  a  la  boMga   Mirar  en  la  nevera:  No  hi  ha  llet!!  15:15   Comprar  un  tetra-­‐brick  de  llet   SorMr  al  carrer  15:20   Posar  el  brick  de  llet  en  la   Arribar  a  la  boMga   nevera  15:25   Comprar  un  tetra-­‐brick  de  llet  15:30   Posar  el  brick  de  llet  en  la  nevera.     Ep!!  Ja  n’hi  ha!!  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  Variable compartida Tasca a realitzar
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet   Iniciem els fils d’execució amb la tasca a realitzar. Comparteixen el mateix objecte nevera!!
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account   En  Ricard  s’adorm  després  d’haver   La   TaMana   -­‐   parella   de’n   comprovat   el   saldo   del   compte   Ricard   -­‐   se’n   va   a   un   corrent   (100€)   però   abans   de   caixer   per   treure   diners   confirmar   l’execució   d’un     traspàs   (90€).     Consulta   el   saldo     de  90€  a  un  altre  compte  corrent.   per   confirmar   que   tot   està   correcte   (100€).   I   treu  els  diners.  Quan   en   Ricard   es   desperta,   immediatament   finalitza   l’execució   del   traspàs   de   diners  sense  haver  comprovar  (un  altre  cop)  el  saldo  del  compte  corrent.   →  El  saldo  del  compte  corrent  passa  a  estar  en  números  vermells!!  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  Què  ha  passat?   Runnable  2 fils (Ricard i Tatiana) comparteixen un mateixobjecte (el compte corrent).  El  codi  té  dues  classes,  Comptecorrent,  i  TascaTatiRicard.     CompteCorrentLa   classe   TascaTatiRicard   implementa   un    Runnable i  representa  el  comportament  que  tenen   int saldotant  en  Ricard  com  la  TaMana  –  comprovar  el  saldo  del   compte   i   reMrar   diners   –.   Lògicament,   cada   fil   mostraSaldo()(thread)  cau  adormit  entre  les  dues  comprovacions   retirar()del  saldo  i,  de  fet,  quan  es  fa  la  reMrada  de  diners.   TascaTatiRicard  La   classe   TascaTatiRicard   té   una   variable   de   Mpus   compteCorrent compteCompteCorrent   que   representa   el   seu   propi  compte  corrent  comparMt.   run() retirarDiners()
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    q  Creem una instància de TascaTatiRicard.   La  classe  TascaTatiRicard  és  el  Runnable  (la  feina  a  fer)  I,  donat  que  tant   la   TaM   com   en   Ricard   fan   el   mateix   (comprovar   el   saldo   I   reMrar   diners),   necessitem  realitzar  una  única  instància.     tascaTatiRicard laTasca = new tascaTatiRicard ();q  Creem 2 fils amb el mateix Runnable (la instància TascaTatiRicard)   thread u = new Thread (laTasca); thread dos = new Thread (laTasca);q  Anomenem i arranquem els fils (threads) u.setName (”Ricard”); dos.setName (”Tatiana”) ; u.start( ); dos.start( );
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    q  Observem com els fils executen el mètode run () (comprovar el saldo I retirar diners) Un  fil  representa  en  Ricard  I  l’altre  representa  la  TaMana.  Els   dos   fils   estan   congnuament   comprovant   el   saldo   i   realitzen   una  reMrada  de  diners  sempre  I  quan  sigui  possible.     if (CompteCorrent.mostrarSaldo ( ) ≥ quantitat) { try { Thread.sleep(500); } catch (InterruptedException ex) {ex.printstackTrace ( ); } }
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    class  compteCorrent  {   El compte comença  private  int  saldo  =  100;   amb un saldo depublic  int  mostrarSaldo  ()  {   100€. return  saldo;   }  public  void  reMrar  (int  quanMtat)  {   saldo  =  saldo  -­‐  quanMtat;   Únicament hi haurà UNA instància }   de tascaTatiRicard. Això vol dir}   solament UNA instància del compte corrent. Ambdós fils accediran a   aquest únic compte corrent.public  class  tascaTaMRicard  implements  Runnable  {    private  compteCorrent  compte  =  new  CompteCorrent();   Instanciem el Runnable (tasca)  public  staMc  void  main  (String  []  args)  {   tascaTaMRicard  laTasca  =  new  tascaTaMRicard  ();   Thread  u  =  new  Thread  (laTasca);   Construïm dos fils; donem a cadascun d’ells Thread  dos  =  new  Thread  (laTasca);   la mateixa feina del Runnable. Ambdós fils u.setName(“Ricard”);   accediran a la variable de instància de dos.setName(“TaMana”);   compte en la classe Runnable. u.start();   dos.start();  }  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    public  void  run  ()  {   En el mètode run (), un fil entra en un bucle i for  (int  x  =  0;  x  <  10;  x++)  {   intenta fer una retirada amb cada iteració. reMrarDiners  (10)  ;   Després de la retirada de diners, comprova el if  (compteCorrent.mostraSaldo()  <  0)  {   saldo un cop més per comprovar si el compte System.out.println(“Números  vermells");   està en números vermells. }   }   Comprovem el saldo del compte i, si no hi ha prou }   diners, mostrem un missatge. Si hi ha prou diners,   ens anem a dormir; posteriorment, ens despertem iprivate  void  reMrarDiners  (int  quanMtat)  {   acabem la retirada (tal i com va fer en Ricard). if  (compte.mostrarSaldo()  >=  quanMtat)  {   System.out.println(Thread.currentThread()  .getName()  +  “  està  a  punt  de  reMrar  diners”);   try  {   System.out.println  (Thread  .  currentThread()  .getName()  +  “  s’adormirà”);   Thread  .sleep(500);   }  catch(InterruptedExcepMon  ex)  {ex.printStackTrace();  }   System.out.println  (Thread.  currentThread()  .getName()  +  “  s’ha  despertat”);   compte.reMrar(quanMtat);   System.out.println  (Thread.  currentThread()  .getName()  +  “  Completa  la  reMrada”);   }   else  {   System.out.println(“Ho  senMm,no  hi  ha  fons  per  ”  +  Thread.currentThread().getName());   }   }   Imprimim per pantalla un grapat de declaracions per poder veure el que està succeint}   mentre sexecuta.
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant     El  mètode  reMrarDiners()  sempre  comprova  el  saldo  abans  de  realitzar  la   reMrada   de   diners;   tot   i   això,   el   compte   sempre   es   queda   en   números   vermells.     Un possible escenari: En   Ricard   comprova   el   saldo,   mira     que   hi   ha   prou   diners   i,   llavors,   s’adorm.     Mentrestant,  la  TaMana  va  i  comprova  el  saldo.  Ella,  també,  veu  que  hi  ha   prou   diners.   No   té   ni   idea   que   en   Ricard   es   despertarà   I   completarà   la   reMrada  de  diners.     En  Ricard  es  desperta  i  enllesteix  la  reMrada  de  diners.     La  TaM  “es  desperta”  I  completa  la  seva  reMrada.  Gran  problema!!  Entre  el   moment   en   que   ella   ha   comprovat   el   saldo   i   que   ha   fet   la   reMrada,   en   Ricard  s’ha  despertat  i  ha  reMrat  diners  del  compte..       La  comprovació  del  compte  per  part  de  la  TaMana  no  és  vàlida  perquè  en   Ricard  ja  havia  comprovat  I  estava  enmig  de  la  realització  de  la  reMrada.     L’accés  al  compte  per  part  de  la  TaMana  s’hagués  hagut  d’aturar  fins  que   en   Ricard   hagués   despertat   I   hagués   finalitzat   la   seva   transacció.   I   a   l’inrevés,  també.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant     Necessiten un cadenat per gestionar l’accés al compteEl  cadenat  treballaria  tal  I  com  segueix:    1 Hi   hauria   un   cadenat   associat   amb   les   transaccions   dels   comptes   bancaris   (comprovació  del  saldo  i  reMrada  de  diners).   Solament   hi   hauria   una   clau   que   es   manMndria   amb   el   cadenat   fins   que   algú   La transacció del volgués  accedir  al  compte.   compte bancari està oberta quan ningú està utilitzant el compte.
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant      2 Quan   en   Ricard   volgués   accedir   al   compte  corrent  del  banc  (per  comprovar   el   saldo   i   realitzar   una   reMrada   de   diners),  tancaria  el  cadenat  I  es  guardaria   la  cau  a  la  butxaca.     Quan en Ricar d vol accedir al compte,   tanca el cadenat i es queda amb la clau. En   conseqüència,   ningú   més   podria   accedir   al   compte   donat   que   la   clau   ja   no  estaria  disponible.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant      3 En  Ricard  manKndria  la  clau  a  la  butxaca  fins   que   finalitzés   la   transacció.   Com   que   ell   Mndria   l’única   clau   pel   cadenat,   la   TaMana   no   podria  accedir  al  compte  (o  a  la  comprovació)   fins  que  en  Ricard  hagués  deixat  el  cadenat,  de   nou,  obert.     Inclús  si  en  Ricard  caigués  adormit  després  de   Quan en Ricard acaba, obre el cadenat i comprovar  el  saldo,  Kndria  la  garanKa  de  que   retorna la clau. Ara la el   saldo   seria   el   mateix   quan   es   despertés   clau està disponible per la Tati o per en perquè   mentre   hagués   dormit,   hauria   Kngut   Ricard per si, de nou, la  clau  guardada  en  la  seva  butxaca.   vol accedir al compte.
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant     Necessitem  que  el  mètode  reMrarDiners  ()   funcioni  com  quelcom  atòmic.  Necessitem  assegurar-­‐nos  de  que,  un  cop  que  el  fil  entri  en  el  mètode  reMrarDiners  (),  pugui  finalitzar  el  mètode  abans  de  que  qualsevol  altre  fil  pugui  entrar-­‐hi.    És  a  dir,  que  un  cop  que  un  fil  hagi  comprovat  el  saldo,  aquest   Mndrà   la   garanMa   de   que   pot   adormir-­‐se   i  despertar  més  tard  i  finalitzar  la  reMrada  de  diners  abans  de  que  qualsevol  altre  fil  pugui  comprovar  el  saldo.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant     Necessitem  que  el  mètode  reMrarDiners  ()   funcioni  com  quelcom  atòmic.  En programació, una acció ATÒMICA ésaquella que succeix amb efectivitat en/d’un sol vez. Una acció atòmica no espot aturar a mig fer (o succeeixcompletament o no succeeix enabsolut).
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    Si   uMlitzem   la   paraula   clau   synchronized  podrem   modificar   un   mètode   perquè   tant  sols  un  fil  pugui  accedir-­‐hi.    En   el   cas   de   l’exemple,   serà   així   com  protegirem  el  compte  corrent  del  banc.     La paraula clau synchronizedNo  posarem  un  cadenat  al  compte  del  banc.     vol dir que un fil necessita   una clau per accedir al codi sincronitzat.Posarem  el  cadenat  al    que  realitza   Per pr ote gir les nostr esla   transacció   bancària.   Així,   un   fil   podrà   d a d e s , h a u r e m d ecompletar  tota  una  transacció  –  de  principi  a   sincronitzar els mètodes que actuïn sobre aquestes dades.fi   –   inclús   si   el   fil   sadormís   a   meitat   del  mètode.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    private    void  reMrarDiners  (int  quanMtat)  {     If  (compte.mostrarSaldo()  >=  quanMtat)  {   System.out.println(Thread.currentThread().getName()  +"  està  a  punt  de  reMrar  diners");   try  {   System.out.println  (Thread.currentThread().getName()  +"  sadormirà");   Thread.sleep(500);   }  catch(InterruptedExcepMon  ex)  {ex.printStackTrace();  }   System.out.println  (Thread.currentThread().getName()  +  "  ja  sha  despertat");   compte.reMrar(quanMtat);   System.out.println  (Thread.currentThread().getName()  +  "  completa  la  reMrada");   }   else  {   System.out.println("Ho  senMm,no  hi  ha  fons  per  "  +  Thread.currentThread().getName());   }   }  }  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  -­‐  Solució   La  sincronització  permet  definir  ordres   estrictes  d’accés  i  execució.      
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Cadenats  i  sincronització  •  Cada  objecte  de  Java  té  un  cadenat.  Un  cadenat  té  una   única  clau.  La  majoria  del  temps,  estan  oberts.  •  Els   cadenats   dels   objectes   entren   en   joc   quan   hi   ha   mètodes   sincronitzats.   Aquests   cadenats   és   el   que   coneixerem  com  a   .  •  La   finalitat   de   la   sincronització   és   protegir   les   dades   críMques.   No   protegirem   sota   cadenat   les   dades,   sincronitzarem   els   mètodes   que   accedeixin   a   aquestes   dades.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda  Hi  ha  un  altre  problema  clàssic  de  concurrència  que  prové  del  món  de  les  bases  de  dades.  L’actualització  perduda  gira  al  voltant  d’un  procés:   Pas 1: Agafa el saldo del compte int i = saldo; Pas 2: Suma 1 a aquest saldo saldo = i + 1;El truc per mostrar això és forçar lequip a fer 2 passos per completar elcanvi en lequilibri. En el món real, faríem aquest moviment particularen una sola sentència: saldo++;Ara bé, forçant-ho a 2 passos, poden aparèixer els problemes propisd’un procés no atòmic.
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda  Imaginem   que,   enlloc   dels   passos   trivials  “obMngues   el   saldo   i   suma-­‐hi   1”,   els   dos   (o   més  passos)  d’aquest  mètode  són  molt  més  complexos  i,  per  tant,  no  es  pot  fer  amb  una  única  sentència.  En  el  problema  de  l’actualització  perduda,  tenim  2  fils,  ambdós  intentant  incrementar  el  saldo.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda  class  TestSync  implements  Runnable  {      private  int  saldo;   Cada  fil  corre  50  cops,     incrementant  el  saldo    public  void  run  ()  {      for  (int  i=0;  i<50;  i++)  {   amb  cada  iteració.      increment  ();      System.out.println(“El  saldo  és  “  +  saldo);      }    }     Aquí  hi  ha  el  punt  crucial!!  Incrementem    public  void  increment  ()  {   el  saldo  afegint  1  a  sigui  quin  sigui  el      int  I  =  saldo;   valor  del  saldo    en  el  moment  de  llegir-­‐    saldo  =  I  +  1;        }   ho  (enlloc  d’afegir  1  a  sigui  quin  sigui  el    }   valor  actual).      public  class  TestSyncTest  {      public  staMc  void  main  (String[]  args)  {        TestSync  tasca  =  new  TestSync  ();        Thread  a  =  new  Thread  (tasca);        Thread  b  =  new  Thread  (tasca);        a.start  ();        b.start  ();        }      }  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda    1 El  fil  A  funciona  durant  un  temps:    2 El  fil  B  funciona  durant  un  temps:   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  La  variable  saldo  és  0,  per  tant,  i  ara  és  0.   •  La  variable  saldo  és  2,  per  tant,  i  ara  és  2.   •  Actualitzem  saldo  amb  el  resultat  de  i+1.   •  Actualitzem  saldo  amb  el  resultat  de  i+1.   •  Ara,  saldo  és  1.   •  Ara,  saldo  és  3.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  La  variable  saldo  val  1,  per  tant,  i  ara  és  1.   •  La  variable  saldo  val  3,  per  tant,  i  ara  és  3.   •  Actualitzem  saldo  amb  el  resultant  de  i+1.   [Ara  el  fil  B  és  enviat  de  tornada  cap  a  runnable;   •  Ara  saldo  val  2.   abans  de  que  posi  el  valor  de  saldo  a  4].    3 El  fil  A  arrenca  de  nou  a  parMr  del    4 El  fil  B  arrenca  de  nou  a  parMr  del   punt  on  ho  havia  deixat:   punt  on  ho  havia  deixat:   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  La  variable  saldo  és  3,  per  tant,  i  ara  és  3.   •  Ara,  saldo  és  4.   •  Actualitzem  saldo  amb  el  resultat  de  i+1.   •  Ara,  saldo  és  4.   Ep!   El   fil   A   el   va   actualitzar   a   5,   •  Posem  el  valor  de  saldo  en  la  variable  i.   però   ara   ha   tornat   el   B   al   •  La  variable  saldo  val  4,  per  tant,  i  ara  és  4.   començament   de   l’actualització   •  Actualitzem  saldo  amb  el  resultant  de  i+1.   de   l’A   com   si   aquest   no   hagués   •  Ara  saldo  val  5.   fet  res!!  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda:  Solució  Sincronitzant  el  mètode  increment  ()  solucionem  el  problema  de  l’actualització  perduda”  perquè  manté  els  dos  passos  en  el  mètode  com  una  única  i  sòlida  unitat.    public    void  increment  ()  {      int  i  =  saldo;      saldo  =  I  +  1;        }    }    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  4:  Interferència  entre  fils  class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } Dos fils A i B poden espatllar-ho: public int valor() { return c; } } Fil A: Recuperar c (0) Fil B: Recuperar c (0) c++  està  compost  de:   Fil A: Increment c (1) 1)  Obtenir  el  valor  de  c   Fil B: Decrement c (-1) 2)  Incrementar  c  en  1   Fil A: Emmagatzemar c (1) 3)  Emmagatzemar  el  valor  de  c   Fil B: emmagatzemar c (-1)     c-­‐-­‐  està  compost  de:     4)  Obtenir  el  valor  de   5)  Decrementar  c  en  1   6)  Emmagatzemar  el  valor  de  c
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  4:  Interferència  entre  fils  class Counter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public int valor() { return c; } }
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  3:  El  temut  problema  de  l’actualització  perduda    1 El  fil  A  funciona  durant  un  temps:    2 El  fil  B  és  seleccionat  per  funcionar:   •  Prova  d’accedir  al  mètode  increment  ().   •  Prova  d’accedir  al  mètode  increment  ().   •  El  mètode  està  sincronitzat;  agafa  la  clau   Com  que  el  mètode  està  sincronitzat,   per  aquest  objecte.   necessitem  agafar  la  clau.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  La  clau  no  es  troba  disponible.   •  La  variable  saldo  és  0  i,  ara  i  és  0.   [Ara  el  fil  B  és  enviat  a  una  “sala  de  cadenats   •  Posem  a  saldo  el  resultat  de  i  +  1.   d’objecte  no  disponible”].   •  Ara  saldo  val  1.   •  Retornem  la  clau  (això  completa  el  mètode    3 El  fil  B  arrenca  de  nou  a  parMr  del  punt  on   increment  ().   ho  havia  deixat  (encara  té  la  clau):   •  Tornem  a  entrar  en  el  mètode  increment  ()  i   •  Posa  a  saldo  el  resultat  de  i+1.   agafem  la  clau.   •  Ara,  saldo  és  2.   •  Posem  el  valor  de  saldo  en  la  variable  i.   •  Retorna  la  clau.   •  Ara  saldo  val  1;  per  tant,  ara  i  val  1.   [Ara  el  fil  A  és  retornat  a  runnable  però,  com   [Ara  el  fil  A  és  retornat  a  runnable,  però  com   que  ja  ha  completat  el  mètode  increment  (),  el   que  no  ha  completat  el  mètode  sincronitzat,   fil  no  manté  la  clau].   manté  la  clau]    4 El  fil  B  és  seleccionat  per  funcionar:   •  Prova  d’accedir  al  mètode  increment  ().  El  mètode  està  sincronitzat.   Necessitem  la  clau.   •  Aquest  cop,  la  clau  està  disponible.  L’agafem.   •  Posem  el  valor  de  saldo  en  la  variable  i.   [ConMnua  funcionant..  ]  
  • És  una  bona  idea  sincronitzar-­‐ho  tot?  Per  si  de  cas..   •  No;  els  mètodes  sincronitzats  comporten  despeses  generals.   Quan  el  codi  arriba  a  un  mètode  sincronitzat,  hi  ha  un  impacte  en  el  rendiment  –   normalment,  no  es  percep  –  mentre    es  confirma  si  “la  clau  del  cadenat”    està   disponible.   •  Un  mètode  pot  alenMr  el  programa  per  les  restriccions  que  defineix.   Un  mètode  sincronitzat  força  a  la  resta  de  fils  a  estar  disponibles  i  esperar  el  seu   torn.   •  Els  mètodes  sincronitzats  poden  donar  lloc  a  un  punt  mort.   Una  regla  d’or  a  seguir  és   sincronitzar  només  el  mínim  del  que   ha  destar  sincronitzat.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    Una  regla  d’or  a  seguir  és   fesFeina  ()  no  necessita  sincronitzar  només  el  mínim   ser  sincronitzat;  per  del  que  ha  destar   tant,  no  sincronitzarem   public  void  go  ()  {   tot  el  mètode  sencer.  sincronitzat.    fesFeina  ();     synchronized(this)  {  Ara,  només  aquestes  dues  crides  als    feinaCriMca  ();  mètodes  s’agrupen  en  una  unitat    mesFeinaCriMca  ();  atòmica.  Quan  suMlitza  la  paraula  clau  synchronized  dins  dun  mètode,  enlloc    }  duna  declaració  de  mètode,  hem  de   }  proporcionar  un  argument  que  és  lobjecte  la  clau  del  qual  el  fil  ha  d’aconseguir.   Tot  i  que  hi  ha  altres  maneres  per  fer-­‐ho,   quasi  sempre  sincronitzarem  l’objecte   actual  (this).  De  fet,  és  el  mateix  objecte   que  tancariem  (lock)  si  sincronitzessim  el   mètode  sencer.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  –  Solució  2  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    Codi  sincronitzat  •  Enlloc   de   sincronitzar   tot   un   mètode   podem   sincronitzar  una  porció  de  codi.     public void addName(String name) { synchronized(this); { lastName=name; nameCount++; } nameList.add(name); }
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  Java   uMlitza   monitors   per   la   sincronització   de   fils.  •  Tot  objecte  amb  mètodes    és  un   monitor.  •  El   monitor   solament   permet   a   un   fil   per   ocasió   executar   un   mètode     sobre   l’objecte.  •  Los   mètodes   que   hagin   d’accedir   al   mateix   objecte,   s’han   de   declarar     per   aconseguir  el  bloqueig.  •  L’execució   de   dos   mètodes   sincronitzats   és   mútuament  excloent.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     Fil esperant Fil actiu
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    //Aquest programa no està sincronitzat. class Sincro {class Crida { public static void main(String[] args){ void crit (String msg){ Crida objectiu = new Crida(); System.out.print("["+msg); ElQueCrida ob1 = new ElQueCrida(objectiu, "Hola"); try { ElQueCrida ob2 = new ElQueCrida(objectiu, "Mon"); Thread.sleep(1000); ElQueCrida ob3 = new }catch(InterruptedException e) ElQueCrida(objectiu, "Sincronitzat"); {;} System.out.print("]"); //Esperem a que els fils acabin } try {} ob1.t.join(); ob2.t.join(); ob3.t.join();public class ElQueCrida extends Thread { }catch(InterruptedException e){;} String msg; } Crida objectiu; } Thread t; public ElQueCrida(Crida objectiu, String msg) { this.objectiu = objectiu; this.msg = msg; t = new Thread(this); On  haig  d’aplicar  el  monitor?   t.start(); } public void run() { objectiu.crit(msg); }}
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Sincronització:  Monitors  –  Exemple  //Aquest programa no està sincronitzat. class Sincro {class Crida { public static void main(String[] args){ void crit (String msg){ Crida objectiu = new Crida(); System.out.print("["+msg); ElQueCrida ob1 = new ElQueCrida(objectiu, "Hola"); try { ElQueCrida ob2 = new ElQueCrida(objectiu, "Mon"); Thread.sleep(1000); ElQueCrida ob3 = new }catch(InterruptedException e) ElQueCrida(objectiu, "Sincronitzat"); {;} System.out.print("]"); //Esperem a que els fils acabin } try {} ob1.t.join(); ob2.t.join(); ob3.t.join();public class ElQueCrida extends Thread { }catch(InterruptedException e){;} String msg; } Crida objectiu; } Thread t; public ElQueCrida(Crida objectiu, String msg) { this.objectiu = objectiu; this.msg = msg; On  haig  d’aplicar  el  monitor?   t = new Thread(this); class Crida { t.start(); synchronized void crit(String msg){ } //… public void run() { } objectiu.crit(msg); }}
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    §  (Fins ara..)  Casos/Exemples  amb  fils  asíncrons  i   independents   §  Cada   fil   conté   totes   les   dades   i   els   mètodes   necessaris   i   no   requereix  recursos  externs.   §  Els  fils  s’executen  en  el  seu  propi  espai;  no  els  influeix  l’estat   o  l’acMvitat  d’altres  fils  que  s’execuMn  de  forma  concurrent.    §  (Noves situacions)   Fins   concurrents   que   comparteixen   dades   i   han   de   considerar   l’estat   i   l’acMvitat   d’altres   fils.   §  Escenaris  “productor/consumidor”.    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    §  Escenari  “productor  –  consumidor”   §  El   PRODUCTOR   genera   un   canal   de   dades   que   és   consumit  pel  CONSUMIDOR.   Productor   Consumidor  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  Podem   imaginar   una   aplicació   JAVA   on   un   fil   (PRODUCTOR)   escriu   dades   en   un   arxiu   mentre   que   un   segon   fil   (CONSUMIDOR)  llegeix  les  dades  del  mateix    arxiu.  •  si  teclegem  caràcters  en  el  teclat,  el  fil   PRODUCTOR  situa  les   polsacions  en  una  pila  d’esdeveniments  i  el  fil   CONSUMIDOR   llegeix  els  esdeveniments  de  la  mateixa  pila.  •  Aquests   dos   exemples   uMlitzen   fils   concurrents   que   comparteixen   un   recurs   comú;   el   primer   comparteix   un   arxiu  i  el  segon  una  pila  d’esdeveniments.  •  Com   que   els   fils   comparteixen   un   recurs   comú,   s’han   de   sincronitzar.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     EXEMPLE  §  El   PRODUCTOR genera   un   enter   entre   0   i   9,   l’emmagatzema   en   un   objecte     i   imprimeix  el  número  generat.  §  A   més,   el   PRODUCTOR   dorm   durant   un   temps   aleatori   entre   0   i   100   milisegons   abans   de   repeMr  el  cicle  de  generació  de  números.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     EXEMPLE  §  Com   que   el   CONSUMIDOR està   famèlic,   consumeix   tots   els   enters   de   l’objecte     tant   ràpid   com   sigui   possible   –   quan   el   número   generat   està   disponible,   l’agafa  –.   Productor   Consumidor  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    §  El   PRODUCTOR i   el CONSUMIDOR comparteixen   dades   per   mitjà   d’un   objecte   en   comú   ( ).§  Cap   dels   dos   fa   cap   esforç   per   assegurar-­‐se   de   que   el   CONSUMIDOR   obMngui   cada   valor   produït   un  únic  cop.  §  La  sincronització  entre  aquests  dos  fils  es  dóna   en   un   nivell   inferior,   dins   dels   mètodes   get()   i   put()  de  l’objecte   .    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    I  si  els  fils  no  esMguessin  sincronitzats?  •  Un   problema   seria   quan   el   PRODUCTOR   fos   més   ràpid   que   el   CONSUMIDOR  i  generés  dos  números  abans  de  que  el  CONSUMIDOR   Mngués  una  possibilitat  de  consumir  el  primer  número.  Així,  el   CONSUMIDOR  es  saltaria  un  número.  •  Part  de  la  sorMda  seria..:    .  .  .   Consumidor  #1  obté:  3   Productor  #1  posa:  4   Productor  #1  posa:  5   Consumidor  #1  obté:  5    .  .  .  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    I  si  els  fils  no  esMguessin  sincronitzats?  •  Un  altre  problema  que  podria  aparèixer  seria  si  el  CONSUMIDOR   fos  més  ràpid  que  el  PRODUCTOR  i  consumís  el  mateix  valor  dos   o  més  cops.    •  En  conseqüència,  el  CONSUMIDOR  imprimiria  el  mateix  valor  dos   cops.  •  Part  de  la  sorMda  seria..:    .  .  .   Productor  #1  posa:  4   Consumidor  #1  obté:  4   Consumidor  #1  obté:  4   Productor  #1  posa:  5    .  .  .  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  Per   prevenir   els   problemes   que   sorgeixen   en   l ’ e x e m p l e   P R O D U C T O R / C O N S U M I D O R ,   l’emmagatzematge  d’un  nou  enter  a  CubbyHole  per   part   del   PRODUCTOR   ha   d’estar   sincronitzat   amb   la   recuperació  per  part  de    CONSUMIDOR.  •  El   programa   PRODUCTOR/CONSUMIDOR   uMlitza   dos   mecanismes   diferents   per   sincronitzar   els   fils:   els   monitors  i  els  mètodes    noKfy()  i  wait().    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  El   programa   PRODUCTOR/CONSUMIDOR   uMlitza   dos   mecanismes   diferents   per   sincronitzar   els   fils:   els   monitors   i   els   mètodes     noKfy()  i  wait().    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  A  Java  s’associa  un  únic  monitor  per   cada   objecte   que   té   un   mètode   sincronitzat.  •  La  classe  té  2  mètodes  sincronitzats:   ü  El   mètode   put()   s’uMlitza   per   canviar  el  valor  de  CubbyHole.   ü  El   mètode   get()   s’uMlitza   per   recuperar  el  valor  actual.  •  És   així   com   el   sistema   associa   un   únic  monitor  amb  cada  exemplar  de   CubbyHole.     Sincronització   dels  fils  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     El  mateix  fil  pot  cridar  a  una  mètode  sincronitzat  d’un   objecte  pel  que  ja  té  el  monitor,  és  a  dir,  pot  tornar  a  adquirir  el  monitor.•  Sempre   que   el   PRODUCTOR   crida   al   mètode   put()   de   CubbyHole,   adquireix   el   monitor   de   l’objecte   CubbyHole,   i   així   evita   que   el   consumidor   pugui   cridar   al   mètode   get()  de  CubbyHole.  •  E l   m è t o d e   w a i t ( )   a l l i b e r a   temporalment  el  monitor.  •  Quan   el   mètode   put()   retorna,   el   PRODUCTOR   allibera   el   monitor   i   desbloqueja  l’objecte  CubbyHole.    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     El  mateix  fil  pot  cridar  a  una  mètode  sincronitzat  d’un   objecte  pel  que  ja  té  el  monitor,  és  a  dir,  pot  tornar  a  adquirir  el  monitor.•  Sempre   que   el   CONSUMIDOR     crida   al   mètode   get()   de   C u b b y H o l e ,   a d q u i r e i x   e l   monitor  d’aquest  objecte  i,  per   tant,   evita   que   el   PRODUCTOR   pugui  cridar  al  mètode  put().    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     Els  mètodes    i    poden  ser  invocats  únicament  des  de  dins  d’un  mètode   sincronitzat  o  dins  d’un  bloc  o  una  sentència  sincronitzada.  •  Mètode     El   mètode     fa   que   el   fil   actual   esperi   (probablement,   per   sempre)   fins  que  un  altre  fil  li  ho  noMfiqui  o  que  canviï  una  condició.     El   mètode   s’uMlitza   en   conjunció   amb   el   mètode     per   coordinar  l’acMvitat  de  varis  fils  que  uMlitzen  els  mateixos  recursos.     Quan   el   fil   entra   en   el   mètode   ,   el   monitor   és   alliberat   automàMcament,  i  quan  el  fil  surt  del  mètode   ,  s’adquereix  de  nou  el   monitor.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     Els  mètodes    i    poden  ser  invocats  únicament  des  de  dins  d’un  mètode   sincronitzat  o  dins  d’un  bloc  o  una  sentència  sincronitzada.  •  Mètode     El   mètode     escull   un   fil   que   està   esperant   el   monitor   posseït   pel   fil   actual  i  el  desperta.  Normalment,  el  fil  que  es  troba  a  l’espera,  capturarà   el  monitor  i  procedirà.  •  Mètode     El   mètode     permet   desbloquejar   tots   els   fils   que   s’hagin   bloquejat  amb  la  invocació  del  mètode   .  Quan  envia  la  noMficació  a   tots   els   fils,   aquests   comencen   a   compeMr   per   tancar   el   candau   i,   en   conseqüència,  per  executar-­‐se.     Normalment,   optem   per   uKlitzar     en   detriment   de     donat   que   no   sabem  es  pot  donar  una  situació  de  coexistència  de  varis  fils  en  el  futur.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  El  fil   CONSUMIDOR  crida  al  mètode   g e t ( ) ,   p e l   q u e   e l   m è t o d e   CONSUMIDOR   posseeix   el   monitor   de   CubbyHole   durant   l’execució   del  mètode  get().  •  Al  final  del  mètode  get(),  la  crida   al   mètode   noKfy()   desperta   al   fil   PRODUCTOR   que   obté   el   monitor   de  CubbyHole  i  procedeix.  •  Si   existeixen   varis   fils   esperant   per   un   monitor,   el   sistema   d’execució   Java   escull   un   d’aquests   fils   sense   cap   compromís   ni   garanMa  sobre  el  fil  que  serà  escollit.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    •  El   bucle   while   conté   la   crida   a   wait().   Aquest   mètode   espera   indefinidament   fins   que   arribi   una  noMficació  del  fil  PRODUCTOR.  •  Quan   el   mètode   put()   crida   a   noKfy(),   el   CONSUMIDOR   desperta   de   l’estat   d’espera   i   conMnúa   amb  el  bucle.  •  Presumiblement,   el   PRODUCTOR   ja   ha   generat   un   nou   número   i   el   métode   get()   cau   al   final   del   bucle  i  procedeix.  
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA