SlideShare ist ein Scribd-Unternehmen logo
1 von 63
Downloaden Sie, um offline zu lesen
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 mateix
objecte (el compte corrent).
	
  
El	
  codi	
  té	
  dues	
  classes,	
  Comptecorrent,	
  i	
  
TascaTatiRicard.	
  
	
                                                                                             CompteCorrent
La	
   classe	
   TascaTatiRicard	
   implementa	
   un	
  	
  
Runnable i	
  representa	
  el	
  comportament	
  que	
  tenen	
                             int saldo
tant	
  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 compte
CompteCorrent	
   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 de
public	
  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 i
private	
  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 s'executa.
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
                 compte
El	
  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 és
aquella que succeix amb efectivitat en/
d’un sol vez. Una acció atòmica no es
pot aturar a mig fer (o succeeix
completament o no succeeix en
absolut).
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 synchronized
No	
  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 es
la	
   transacció	
   bancària.	
   Així,	
   un	
   fil	
   podrà	
                  d a d e s , h a u r e m d e
completar	
  tota	
  una	
  transacció	
  –	
  de	
  principi	
  a	
                 sincronitzar els mètodes que
                                                                                     actuïn sobre aquestes dades.
fi	
   –	
   inclús	
   si	
   el	
   fil	
   s'adormí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()	
  +"	
  s'adormirà");	
  
                                  Thread.sleep(500);	
  
                     }	
  catch(InterruptedExcepMon	
  ex)	
  {ex.printStackTrace();	
  }	
  
                     System.out.println	
  (Thread.currentThread().getName()	
  +	
  "	
  ja	
  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());	
  
                 }	
  
             }	
  
}	
  
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 l'equip a fer 2 passos per completar el
canvi en l'equilibri. En el món real, faríem aquest moviment particular
en una sola sentència: saldo++;

Ara bé, forçant-ho a 2 passos, poden aparèixer els problemes propis
d’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	
  d'estar	
  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	
  d'estar	
                                                                                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	
  s'uMlitza	
  la	
  paraula	
  clau	
  
synchronized	
  dins	
  d'un	
  mètode,	
  enlloc	
  
                                                                           	
  }	
  
d'una	
  declaració	
  de	
  mètode,	
  hem	
  de	
            }	
  
proporcionar	
  un	
  argument	
  que	
  és	
  
l'objecte	
  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	
  
                                  	
  

Weitere ähnliche Inhalte

Andere mochten auch

Memoria compartida distribuida expo grupo #8
Memoria compartida distribuida expo grupo #8Memoria compartida distribuida expo grupo #8
Memoria compartida distribuida expo grupo #8elianicorrea
 
Exclusión mutua
Exclusión mutuaExclusión mutua
Exclusión mutuatatyseli
 
Sincronizacion de Procesos
Sincronizacion de ProcesosSincronizacion de Procesos
Sincronizacion de Procesosmastermind87
 
Monitores-sistemas operativos
Monitores-sistemas operativosMonitores-sistemas operativos
Monitores-sistemas operativosDaniel Vargas
 
Comunicación y Sincronizacion de Procesos
Comunicación y Sincronizacion de ProcesosComunicación y Sincronizacion de Procesos
Comunicación y Sincronizacion de ProcesosLorena Ramos
 
Sistemas Operativos - Semáforos
Sistemas Operativos - SemáforosSistemas Operativos - Semáforos
Sistemas Operativos - SemáforosJuan Rojas
 

Andere mochten auch (6)

Memoria compartida distribuida expo grupo #8
Memoria compartida distribuida expo grupo #8Memoria compartida distribuida expo grupo #8
Memoria compartida distribuida expo grupo #8
 
Exclusión mutua
Exclusión mutuaExclusión mutua
Exclusión mutua
 
Sincronizacion de Procesos
Sincronizacion de ProcesosSincronizacion de Procesos
Sincronizacion de Procesos
 
Monitores-sistemas operativos
Monitores-sistemas operativosMonitores-sistemas operativos
Monitores-sistemas operativos
 
Comunicación y Sincronizacion de Procesos
Comunicación y Sincronizacion de ProcesosComunicación y Sincronizacion de Procesos
Comunicación y Sincronizacion de Procesos
 
Sistemas Operativos - Semáforos
Sistemas Operativos - SemáforosSistemas Operativos - Semáforos
Sistemas Operativos - Semáforos
 

Mehr von Oriol Torres

Economia col·laborativa, turisme col·laboratiu i KangApp
Economia col·laborativa, turisme col·laboratiu i KangAppEconomia col·laborativa, turisme col·laboratiu i KangApp
Economia col·laborativa, turisme col·laboratiu i KangAppOriol Torres
 
Presentation of Treat or Treat
Presentation of Treat or TreatPresentation of Treat or Treat
Presentation of Treat or TreatOriol Torres
 
Presentación pública Treat or Treat
Presentación pública Treat or TreatPresentación pública Treat or Treat
Presentación pública Treat or TreatOriol Torres
 
1213 Threads [5] Accés a fitxers
1213 Threads [5] Accés a fitxers1213 Threads [5] Accés a fitxers
1213 Threads [5] Accés a fitxersOriol Torres
 
1213 Threads [3] Semafors
1213 Threads [3] Semafors1213 Threads [3] Semafors
1213 Threads [3] SemaforsOriol Torres
 
1213 Threads [2] Programació concurrent
1213 Threads [2] Programació concurrent1213 Threads [2] Programació concurrent
1213 Threads [2] Programació concurrentOriol Torres
 
1213 serveis [5] Correu electronic i pagines web
1213 serveis [5] Correu electronic i pagines web1213 serveis [5] Correu electronic i pagines web
1213 serveis [5] Correu electronic i pagines webOriol Torres
 
1213 Sockets [4] Servidors i fils
1213 Sockets [4] Servidors i fils1213 Sockets [4] Servidors i fils
1213 Sockets [4] Servidors i filsOriol Torres
 
1213 Sockets [1] Introducció
1213 Sockets [1] Introducció1213 Sockets [1] Introducció
1213 Sockets [1] IntroduccióOriol Torres
 
1213 Sockets [2] Arquitectura client - servidor
1213 Sockets [2] Arquitectura client - servidor1213 Sockets [2] Arquitectura client - servidor
1213 Sockets [2] Arquitectura client - servidorOriol Torres
 
1213 Sockets [3] Programació
1213 Sockets [3] Programació1213 Sockets [3] Programació
1213 Sockets [3] ProgramacióOriol Torres
 
1213 Threads [1] Programació concurrent, processos i fils
1213 Threads [1] Programació concurrent, processos i fils1213 Threads [1] Programació concurrent, processos i fils
1213 Threads [1] Programació concurrent, processos i filsOriol Torres
 
Appetite apps stats market
Appetite apps stats marketAppetite apps stats market
Appetite apps stats marketOriol Torres
 

Mehr von Oriol Torres (13)

Economia col·laborativa, turisme col·laboratiu i KangApp
Economia col·laborativa, turisme col·laboratiu i KangAppEconomia col·laborativa, turisme col·laboratiu i KangApp
Economia col·laborativa, turisme col·laboratiu i KangApp
 
Presentation of Treat or Treat
Presentation of Treat or TreatPresentation of Treat or Treat
Presentation of Treat or Treat
 
Presentación pública Treat or Treat
Presentación pública Treat or TreatPresentación pública Treat or Treat
Presentación pública Treat or Treat
 
1213 Threads [5] Accés a fitxers
1213 Threads [5] Accés a fitxers1213 Threads [5] Accés a fitxers
1213 Threads [5] Accés a fitxers
 
1213 Threads [3] Semafors
1213 Threads [3] Semafors1213 Threads [3] Semafors
1213 Threads [3] Semafors
 
1213 Threads [2] Programació concurrent
1213 Threads [2] Programació concurrent1213 Threads [2] Programació concurrent
1213 Threads [2] Programació concurrent
 
1213 serveis [5] Correu electronic i pagines web
1213 serveis [5] Correu electronic i pagines web1213 serveis [5] Correu electronic i pagines web
1213 serveis [5] Correu electronic i pagines web
 
1213 Sockets [4] Servidors i fils
1213 Sockets [4] Servidors i fils1213 Sockets [4] Servidors i fils
1213 Sockets [4] Servidors i fils
 
1213 Sockets [1] Introducció
1213 Sockets [1] Introducció1213 Sockets [1] Introducció
1213 Sockets [1] Introducció
 
1213 Sockets [2] Arquitectura client - servidor
1213 Sockets [2] Arquitectura client - servidor1213 Sockets [2] Arquitectura client - servidor
1213 Sockets [2] Arquitectura client - servidor
 
1213 Sockets [3] Programació
1213 Sockets [3] Programació1213 Sockets [3] Programació
1213 Sockets [3] Programació
 
1213 Threads [1] Programació concurrent, processos i fils
1213 Threads [1] Programació concurrent, processos i fils1213 Threads [1] Programació concurrent, processos i fils
1213 Threads [1] Programació concurrent, processos i fils
 
Appetite apps stats market
Appetite apps stats marketAppetite apps stats market
Appetite apps stats market
 

1213 Threads [4] Sincronització

  • 1. PROGRAMACIÓ   CONCURRENT   4   Sincronització  
  • 2. 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.  
  • 3. 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!!  
  • 4. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet   Variable compartida Tasca a realitzar
  • 5. 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!!
  • 6. 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!!  
  • 7. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account   Què  ha  passat?   Runnable   2 fils (Ricard i Tatiana) comparteixen un mateix objecte (el compte corrent).   El  codi  té  dues  classes,  Comptecorrent,  i   TascaTatiRicard.     CompteCorrent La   classe   TascaTatiRicard   implementa   un     Runnable i  representa  el  comportament  que  tenen   int saldo tant  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 compte CompteCorrent   que   representa   el   seu   propi   compte  corrent  comparMt.   run() retirarDiners()
  • 8. 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( );
  • 9. 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 ( ); } }
  • 10. 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 de public  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();   }  
  • 11. 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 i private  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 s'executa.
  • 12. 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é.  
  • 13. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant    
  • 14. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  2:  Two  people,  one  account  –  Codi  resultant     Necessiten un cadenat per gestionar l’accés al compte El  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.
  • 15. 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.  
  • 16. 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.
  • 17. 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.  
  • 18. 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 és aquella que succeix amb efectivitat en/ d’un sol vez. Una acció atòmica no es pot aturar a mig fer (o succeeix completament o no succeeix en absolut).
  • 19. 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 synchronized No  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 es la   transacció   bancària.   Així,   un   fil   podrà   d a d e s , h a u r e m d e completar  tota  una  transacció  –  de  principi  a   sincronitzar els mètodes que actuïn sobre aquestes dades. fi   –   inclús   si   el   fil   s'adormís   a   meitat   del   mètode.  
  • 20. 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()  +"  s'adormirà");   Thread.sleep(500);   }  catch(InterruptedExcepMon  ex)  {ex.printStackTrace();  }   System.out.println  (Thread.currentThread().getName()  +  "  ja  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());   }   }   }  
  • 21. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  -­‐  Solució   La  sincronització  permet  definir  ordres   estrictes  d’accés  i  execució.      
  • 22. 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.  
  • 23. 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 l'equip a fer 2 passos per completar el canvi en l'equilibri. En el món real, faríem aquest moviment particular en una sola sentència: saldo++; Ara bé, forçant-ho a 2 passos, poden aparèixer els problemes propis d’un procés no atòmic.
  • 24. 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.  
  • 25. 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  ();        }      }  
  • 26. 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!!  
  • 27. 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;        }    }    
  • 28. 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
  • 29. 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; } }
  • 30. 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..  ]  
  • 31. É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  d'estar  sincronitzat.  
  • 32. 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  d'estar   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  s'uMlitza  la  paraula  clau   synchronized  dins  d'un  mètode,  enlloc    }   d'una  declaració  de  mètode,  hem  de   }   proporcionar  un  argument  que  és   l'objecte  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.  
  • 33. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA   Exemple  1:  Molta  llet  –  Solució  2  
  • 34. 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); }
  • 35. 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.  
  • 36. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     Fil esperant Fil actiu
  • 37. 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); } }
  • 38. 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); } }
  • 39. 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”.    
  • 40. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA     §  Escenari  “productor  –  consumidor”   §  El   PRODUCTOR   genera   un   canal   de   dades   que   és   consumit  pel  CONSUMIDOR.   Productor   Consumidor  
  • 41. 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.  
  • 42. 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.  
  • 43. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 44. 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  
  • 45. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 46. 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   .    
  • 47. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 48. 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    .  .  .  
  • 49. 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    .  .  .  
  • 50. 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().    
  • 51. 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().    
  • 52. 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  
  • 53. 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.    
  • 54. 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().    
  • 55. 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.  
  • 56. 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.  
  • 57. 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.  
  • 58. 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.  
  • 59. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 60. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 61. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 62. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA    
  • 63. PROCESSOS  CONCURRENTS  I  MEMÒRIA   COMPARTIDA