Sie sind auf Seite 1von 22

Sincronización entre procesos

Problemas clásicos

Rodolfo Baader

Departamento de Computación, FCEyN,


Universidad de Buenos Aires, Buenos Aires, Argentina

Sistemas Operativos, segundo cuatrimestre de 2012

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(2) Siempre los mismos problemas...
En muchas áreas de la computación hay problemas clásicos.
Eso significa que aparecen una y otra vez bajo diferentes
formas, pero son básicamente el mismo problema.
En el caso de sincronización entre procesos también sucede
que muchos de estos problemas nos suelen inducir a pensar en
“soluciones” incorrectas.
Por eso está bueno estudiarlos y conocer buenas formas de
solucionarlos.
Además, analizarlos suele aportar una mirada bastante
profunda sobre problemas fundamentales de la computación, y
a veces, del razonamiento humano.
OJO: conocer los problemas clásicos y sus soluciones no debe
ser una excusa para la pereza. Los problemas concretos tienen
particularidades y contextos que hacen necesario evaluarlos de
manera individual y pensar en cada caso. ∆ !
Dicho de otra forma, el conocimiento no reemplaza a la
inteligencia. Ambos se complementan.
Rodolfo Baader Problemas clásicos de sincronización entre procesos
(3) Los turnos

Problema:
Tenemos una serie de procesos Pi , i ∈ {1 . . . N} que se están
ejecutando en simultáneo (supongamos que tenemos N CPUs).
Cada proceso i tiene una sentencia si.
Queremos que en el sistema global se ejecuten s1, s2, . . . , sN.
¿De qué nos disfrazamos?
Podemos utilizar semáforos.

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(4) Los turnos (cont.)

Listing 1: Inicialización
proc i n i t ()
{
f o r ( i= 0 ; i <N+1; i ++)
s e m a f o r o s [ i ]= new S e má f o r o ( 0 ) ;

f o r ( i= 0 ; i <N ; i ++)
f o r k P( i ) ;

semaforos [ 0 ] . s i g n a l ( ) ;
}

Listing 2: Proceso Pi
p r o c P( i )
{
s e m a n t= s e m a f o r o s [ i ] ;
s e m s i g= s e m a f o r o s [ i + 1 ] ;
sem ant . wait ( ) ;
s( i );
sem sig . s i g n a l ( ) ;
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(5) Barrera - Rendezvous

Otro problema muy común es el de rendezvous (punto de


encuentro), o barrera de sincronización.
Dados Pi = [a(i); b(i)], i ∈ {1 . . . N}, asegurarse que los b(i)
se ejecuten recién después de que se ejecutaron todos los a(i).
Es decir, queremos poner una barrera entre los a y los b.
Sin embargo, no hay que restringir de más: no hay que
imponer ningún orden entre los a(i) ni entre los b(i).

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(6) Rendezvous (cont.)

Listing 3: Inicialización
proc i n i t ()
{
e n b a r r e r a= 0 ; // Cant . de p r o c s en l a b a r r e r a .
mutex= new S e má f o r o ( 1 ) ; // P e r m i t o empezar de i n m e d i a t o .
b a r r e r a= new S e má f o r o ( 0 ) ;

f o r ( i= 0 ; i <N ; i ++) f o r k P( i ) ;
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(7) Rendezvous (cont.)

Listing 4: Proceso Pi
p r o c P( i )
{
a( i );

mutex . w a i t ( ) ; // A c c e s o a v a r . c o m p a r t i d a .
e n b a r r e r a ++;
b o o l t o d o s e n b a r r e r a= ( e n b a r r e r a==N ) ;
mutex . s i g n a l ( ) ;

i f ( todos en barrera )
// Todos e s t á n l i s t o s p a r a c o n t i n u a r . Que s i g a n .
barrera . signal ();

barrera . wait ( ) ;

b( i );
}

Esta solución no es correcta.


¿Qué está mal?
Rodolfo Baader Problemas clásicos de sincronización entre procesos
(8) Rendezvous (cont.)
En el ejemplo anterior habı́a deadlock. ∆
!

Listing 5: Proceso Pi (correcto)


p r o c P( i )
{
a( i );

mutex . w a i t ( ) ; // A c c e s o a v a r . c o m p a r t i d a .
e n b a r r e r a ++;
b o o l t o d o s e n b a r r e r a= ( e n b a r r e r a==N ) ;
mutex . s i g n a l ( ) ;

i f ( todos en barrera )
// Todos e s t á n l i s t o s p a r a c o n t i n u a r . Que s i g a n .
barrera . signal ();

barrera . wait ( ) ;
barrera . signal ();

b( i );
}

Notar que hay un signal() de más.


Rodolfo Baader Problemas clásicos de sincronización entre procesos
(9) Rendezvous (cont.)

Otra solución, si contamos con la primitiva broadcast().

Listing 6: Proceso Pi (correcto)


p r o c P( i )
{
a( i );

mutex . w a i t ( ) ; // A c c e s o a v a r . c o m p a r t i d a .
e n b a r r e r a ++;
b o o l t o d o s e n b a r r e r a= ( e n b a r r e r a==N ) ;
mutex . s i g n a l ( ) ;

i f ( todos en barrera )
// Todos e s t á n l i s t o s p a r a c o n t i n u a r . Que s i g a n .
barrera . broadcast ( ) ;
else
barrera . wait ( ) ;

b( i );
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(10) Sección crı́tica de a k

Siguiente problema. N procesos, sólo k ejecutan a la vez la


sección crı́tica sc(i).
Es fácil:

Listing 7: Inicialización
proc i n i t ()
{
sem= new S e má f o r o ( k ) ;

f o r ( i= 0 ; i <N ; i ++) f o r k P( i ) ;
}

Listing 8: Proceso Pi
p r o c P( i )
{
sem . w a i t ( ) ;
sc ( i ) ;
sem . s i g n a l ( ) ;
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(11) Apareamiento

Vamos a presentar una versión no clásica de un problema


clásico.
Está el Crucero de Noel, donde queremos guardar parejas de
distintas especies (no sólo una por especie).
Hay una puerta por cada especie.
Los animales forman fila en cada puerta, en dos colas, una por
sexo.
Queremos que entren en parejas.
Tarea: programar el código de cada proceso P(i, sexo). Pista:
usar dos semáforos y la función entrar(i).
Tarea adicional: una única puerta, pero tiene que coincidir la
especie. ¡Ojo con el deadlock!

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(12) Lectores/escritores

Otro problema más. Se da mucho en bases de datos.


Hay una variable compartida.
Los escritores necesitan acceso exclusivo.
Pero los lectores pueden convivir.
¿Cómo podrı́a solucionarse?

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(13) Lectores/escritores (cont.)

Listing 9: Inicialización
proc i n i t ()
{
v a r i a b l e c o m p a r t i d a ; // É s t a e s l a que t o d o s s e d i s p u t a n .
mutex= new S e má f o r o ( 1 ) ;
a c c e s o e x c l u s i v o= new S e má f o r o ( 1 ) ;
i n t l e c t o r e s= 0 ;

f o r ( i= 0 ; i <N ; i ++) f o r k L e c t o r ( i ) ;
f o r ( i= 0 ; i <M; i ++) f o r k E s c r i t o r ( i ) ;
}

Los escritores necesitan acceso exclusivo, sin vueltas:


Listing 10: Escritores
proc E s c r i t o r ( i )
{
a c c e s o e x c l u s i v o . wait ( ) ;
E s c r i b i r ( compartida ) ;
acceso exclusivo . signal ();
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(14) Lectores/escritores (cont.)

Listing 11: Lectores


proc Lector ( i )
{
mutex . w a i t ( ) ;
l e c t o r e s ++;
i f ( l e c t o r e s ==1)
// Soy e l p r i m e r o , r e c l a m o a c c e s o ” e x c l u s i v o ” p a r a
// t o d o s l o s l e c t o r e s .
a c c e s o e x c l u s i v o . wait ( ) ;
mutex . s i g n a l ( ) ;

Leer ( compartida ) ;

mutex . w a i t ( ) ;
l e c t o r e s −−;
i f ( l e c t o r e s ==0)
// Soy e l ú l t i m o , d e j o que e n t r e n l o s escritores .
acceso exclusivo . signal ();
mutex . s i g n a l ( ) ;
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(15) Lectores/escritores (cont.)

¿Puede haber deadlock?


No, pero puede haber inanición de escritores.
Tarea: pensar cómo evitarlo.

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(16) Filósofos que cenan
Este problema lo inventó Dijkstra en 1965.
Tenemos 5 filósofos en una mesa circular, con fideos en el
medio y un tenedor entre cada filósofo. Para comer necesitan
dos tenedores.
Los filósofos hacen:
p r o c F i l ó s o f o ( i )
while ( true )
{
pensar ( ) ;
conseguir tenedores ( i );
comer ( ) ;
dejar tenedores ( i );
}

Problema: programar conseguir tenedores() y


dejar tenedores() de manera tal que:
EXCL) Sólo un filósofo tenga cada tenedor en cada momento.
DEAD) No haya deadlock.
INAN) No haya inanición.
CONC) Más de un filósofo esté comiendo a la vez.
Rodolfo Baader Problemas clásicos de sincronización entre procesos
(17) Filósofos que cenan

Empecemos por algunas definiciones básicas:


Macros cómodas para los tenedores:
izq(i) = i
der(i) = (i + 1) mod 5
¿Qué son los tenedores?
Seguro que hay que garantizar acceso exclusivo a ellos:
Un arreglo: tenedores[i]= new Semáforo(1)

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(18) Solución ingénua

Empecemos por la idea más elemental:


func c o n s e g u i r t e n e d o re s ( i )
{
tenedores [ izq ( i ) ] . wait ( ) ;
tenedores [ der ( i ) ] . wait ( ) ;
}

func d e j a r t e n e d o r e s ( i )
{
tenedores [ izq ( i ) ] . signal ();
tenedores [ der ( i ) ] . s i g n a l ( ) ;
}

¿Está bien?
Esta solución garantiza EXCL, pero falla con DEAD.
¿Cómo rompemos el deadlock? Pensemos en las condiciones.
Tarea: pensar en soluciones para este problema. Buscar las ya
existentes.

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(19) Barbero

Otro problema clásico:


En una peluquerı́a hay dos salas, una de espera, con n sillas y
otra donde está la única silla donde el único peluquero corta el
pelo.
Si no hay clientes, el peluquero se duerme una siesta.
Si entra un cliente, y no se puede sentar a esperar, se va.
Si el peluquero está dormido, lo despierta.

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(20) Barbero (cont.)

Vamos a usar tres semáforos:


a l g u n c l i e n t e= new S e má f o r o ( 0 ) ;
p a s a r= new S e má f o r o ( 0 ) ;
mutex= new S e má f o r o ( 1 ) ;
c l i e n t e s= 0 ;

El peluquero es sencillo:
proc Peluquero
while ( true )
{
a l g u n c l i e n t e . wait ( ) ;
pasar . s i g n a l ( ) ;
cortar pelo ();
}

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(21) Barbero (cont.)
Veamos a los clientes:
proc C l i e n t e ()
// ¿Hay l u g a r ? C a p a c i d a d = n + 1 ( a l que l e c o r t a n )
mutex . w a i t ( ) ;
i f ( c l i e n t e s==n+1)
// No , me v o y .
mutex . s i g n a l ( ) ;
r e t i r a r s e ( ) ; // No v u e l v e
// Sı́ hay l u g a r , e n t r o .
c l i e n t e s ++;
mutex . s i g n a l ( ) ;

// ”A v i s o ” que l l e g u é .
algun cliente . signal ();
// E s p e r o a que me d e j e n p a s a r .
pasar . wait ( ) ;

e n t r a r a c o r t a r s e e l p e l o ( ) ; // ¡Todo p a r a e s t o !

// S a l g o .
mutex . w a i t ( ) ;
c l i e n t e s −−;
mutex . s i g n a l ( ) ;

Rodolfo Baader Problemas clásicos de sincronización entre procesos


(22) Bibliografı́a

“The Little Book of Semaphores”, Second Edition. Allen B.


Downey. http://greenteapress.com/semaphores/
“Cooperating sequential processes”. Edgar W. Dijkstra.
Technical Report 123, Univ. Texas. http://www.cs.utexas.
edu/users/EWD/transcriptions/EWD01xx/EWD123.html.

Rodolfo Baader Problemas clásicos de sincronización entre procesos

Das könnte Ihnen auch gefallen