Sincronización entre procesos Problemas clásicos

Anuncio
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 2014
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.)
¿Qué pasa si contamos con la primitiva broadcast()?.
Listing 6: 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 . broadcast ( ) ;
else
barrera . wait ( ) ;
b( i );
}
Esta solución no es correcta.
¿Qué está mal?
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) 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
(12) 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
(13) 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
acceso exclusivo . signal ();
mutex . s i g n a l ( ) ;
escritores .
}
Rodolfo Baader
Problemas clásicos de sincronización entre procesos
(14) 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
(15) Filósofos que cenan (Dining Quintuple/Philosophers)
Este problema lo inventó Dijkstra en 1965.
Tenemos 5 filósofos en una mesa circular, con 5 platos de
fideos y un tenedor entre cada plato. 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)
DEAD)
INAN)
CONC)
Sólo un filósofo tenga cada tenedor en cada momento.
No haya deadlock.
No haya inanición.
Más de un filósofo esté comiendo a la vez.
Rodolfo Baader
Problemas clásicos de sincronización entre procesos
(16) Gráficamente
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
Descargar