Práctica 11: El problema de los Lectores/Escritores

Pr´actica 11: El problema de los Lectores/Escritores
Gustavo Romero L´
opez
Arquitectura y Tecnolog´ıa de Computadores
15 de mayo de 2015
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
1 / 18
Objetivos
Resolver el problema de los lectores/escritores de la forma
m´as justa y/o eficiente posible.
Para ello utilice cualquiera de los mecanismos de
sincronizaci´on y exclusi´on mutua vistos hasta ahora
adem´as de probar los cerrojos espec´ıficos de
lectura/escritura de pthread.
Para facilitar el proceso de arranque partiremos de
analizar un par de soluciones:
Una incorrecta con condiciones de carrera: le.cc.
Otra incorrecta sin condiciones de carrera: le-mutex.cc.
Puede comparar las diferentes versiones con la ayuda del
Makefile (“make all” o “make stat”).
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
2 / 18
Makefile
https://pccito.ugr.es/~gustavo/as/practicas/11/Makefile
Makefile
1
2
SHELL = / b i n / b a s h
DIR = $ ( s h e l l f i n d −m i n d e p t h 1 −maxdepth 1 −t y p e d )
3
4
5
SRC = $ ( w i l d c a r d ∗ . c ∗ . c c )
EXE = $ ( basename $ ( SRC ) )
6
7
8
9
CFLAGS = − I . −O3 −p t h r e a d −W a l l −Wl,−−no−as−n e e d e d
CXXFLAGS = $ ( CFLAGS ) −D GLIBCXX USE NANOSLEEP −D
GLIBCXX USE SCHED YIELD −−s t d=c++0x
LDFLAGS = − l p t h r e a d − l r t
10
11
d e f a u l t : $ (EXE)
12
13
all :
stat
Mediante ”make all” o ”make stat” podr´a comparar f´acilmente
las soluciones que vaya programando.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
3 / 18
Sem´aforos (POSIX)
#include <semaphore.h> Cabecera C/C++.
sem t Tipo sem´aforo.
sem init(sem, attr, valor) Crea un sem´aforo sem
inicializado a valor y con los atributos attr.
sem destroy(sem) Destruye el sem´aforo sem.
sem wait(sem) Si el valor del sem´aforo sem es positivo lo
decrementa y retorna inmediatamente. En otro se
bloquea hasta poder hacerlo.
sem trywait(sem) Versi´
on no bloqueante de sem wait(sem). En
cualquier caso retorna inmediatamente. Es necesario
comprobar la salida antes de continuar.
sem post(sem) Incrementa el valor del sem´aforo sem. En caso de
cambiar a un valor positivo desbloquea a alguno de
los llamadores bloqueados en sem wait(sem).
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
4 / 18
Barreras (pthread)
pthread barrier t Tipo barrera.
pthread barrier init(barrier, attr, n) Inicializa la barrera
barrier con los atributos attr para que funcione
con n hebras.
pthread barrier destroy(barrier) Destruye la barrera
barrier.
pthread barrier wait(barrier) Bloque a la hebra llamadora
hasta que se n hebras ejecuten
pthread barrier wait(barrier).
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
5 / 18
Mutex (pthread)
#include <pthreads.h> Cabecera C/C++.
pthread mutex t Tipo mutex, inicializable a
PTHREAD MUTEX INITIALIZER.
pthread mutex init(mutex, attr) Crea e inicializa mutex con
los atributos attr.
pthread mutex destroy(mutex) Destruye mutex.
pthread mutex lock(mutex) Adquiere mutex en caso de estar
libre. En otro caso bloquea la hebra.
pthread mutex unlock(mutex) Desbloquea mutex.
pthread mutex trylock(mutex) Intenta bloquear mutex y en
caso de no poder continua sin bloquear la hebra.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
6 / 18
Variables condici´on (pthread)
pthread cond t Tipo variable condici´
on. Inicializable a
PTHREAD COND INITIALIZER.
pthread cond init(cond,attr) Inicializa la variable condici´
on cond con los
atributos attr.
pthread cond destroy(cond) Destruye la variable condici´
on cond.
pthread cond wait(cond, mutex) Bloque a la hebra llamadora hasta que se
se˜
nale cond. Esta funci´
on debe llamarse mientras mutex
est´
a ocupado y ella se encargar´
a de liberarlo autom´
aticamente
mientas espera. Despu´es de la se˜
nal la hebra es despertada y el
cerrojo es ocupado de nuevo. El programador es responsable de
desocupar mutex al finalizar la secci´
on cr´ıtica para la que se
emplea.
pthread cond signal(cond) Funci´
on para despertar a otra hebra que espera
que se se˜
nale sobre la variable condici´
on cond. Debe llamarse
despu´es de que mutex est´e ocupado y se encarga de liberarlo
en pthread cond wait(cond, mutex).
pthread cond broadcast(cond) Igual que la funci´
on anterior para el caso de
que queramos desbloquear a varias hebras que esperan.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
7 / 18
Cerrojos Lector/Escritor (pthread)
pthread rwlock t Tipo cerrojo lector/escritor.
pthread rwlock init(rwlock, attr) Inicializa el cerrojo
lector/escritor rwlock con los atributos attr.
pthread rwlock destroy(rwlock) Destruye el cerrojo rwlock.
pthread rwlock rdlock(rwlock) Adquiere el cerrojo rwlock para
lectura.
pthread rwlock tryrdlock(rwlock) Intenta adquirir el cerrojo
rwlock para lectura.
pthread rwlock wrlock(rwlock) Adquiere el cerrojo rwlock para
escritura.
pthread rwlock trywrlock(rwlock) Intenta adquirir el cerrojo
rwlock para escritura.
pthread rwlock unlock(rwlock) Libera el cerrojo rwlock en funci´on
de la versi´
on de aquisici´
on ejecutada con anterioridad, ya
sea lector o escritor.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
8 / 18
Sem´aforos binarios en C++11
#include <mutex> Cabecera.
std::mutex Nombre de la clase.
lock() Adquiere el sem´aforo. Si otra hebra lo ha
bloqueado previamente entonces bloquea a la
hebra actual hasta que la propietaria del sem´aforo
lo deja libre.
unlock() Desbloquea el sem´aforo.
std::lock guard Envoltorio que permite adquirir un
sem´aforo en el bloque de ejecuci´on.
std::unique lock Envoltorio que adem´as de permitir
adquirir un sem´aforo en un bloque de ejecuci´on
permite el traspaso de su propiedad.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
9 / 18
Variables condici´on en C++11
#include <condition variable> Cabecera.
std::condition variable Nombre de la clase.
wait(lock, pred) Bloquea a la hebra llamadora hasta que
se se˜nale la condici´on o se produzca un despertar
enga˜noso. Mediante pred podemos verificar que
se cumple la condici´on:
cv.wait(lock, pred);
while (! pred )
cv . wait ( lock ) ;
notify one() Funci´on para despertar a otra hebra que
espera que se se˜nale sobre la variable condici´on.
notify all() Funci´on para despertar a todas las hebras que
esperan que se se˜nale sobre la variable condici´on.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
10 / 18
Ejemplo: le.cc I
https://pccito.ugr.es/~gustavo/as/practicas/11/le.cc
Copie el programa le.cc y verifique que la secuencia de ejecuci´on
no es correcta porque existen condiciones de carrera.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#i n c l u d e <c h r o n o>
#i n c l u d e <i o s t r e a m >
#i n c l u d e <t h r e a d>
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
u s i n g namespace s t d ;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void s e c c i o n c r i t i c a ( char c )
{
f o r ( c h a r i = 0 ; i < 1 0 ; ++i )
c o u t << c++;
c o u t << e n d l ;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( )
{
const unsigned N = 10;
t h r e a d l e c t o r e s [N] ,
e s c r i t o r e s [N ] ;
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
11 / 18
Ejemplo: le.cc II
https://pccito.ugr.es/~gustavo/as/practicas/11/le.cc
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
a u t o f i n = c h r o n o : : h i g h r e s o l u t i o n c l o c k : : now ( ) + c h r o n o : : s e c o n d s ( 1 ) ;
f o r ( t h r e a d& i : l e c t o r e s )
i = thread ([&]
{
w h i l e ( c h r o n o : : h i g h r e s o l u t i o n c l o c k : : now ( ) < f i n )
seccion critica ( ’0 ’ ) ;
}) ;
f o r ( t h r e a d& i : e s c r i t o r e s )
i = thread ([&]
{
w h i l e ( c h r o n o : : h i g h r e s o l u t i o n c l o c k : : now ( ) < f i n )
seccion critica ( ’a ’) ;
}) ;
f o r ( t h r e a d& i :
i . join () ;
lectores )
f o r ( t h r e a d& i :
i . join () ;
escritores )
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
12 / 18
Ejemplo: le-mutex.cc
https://pccito.ugr.es/~gustavo/as/practicas/11/le-mutex.cc
Copie el programa le-mutex.cc y verifique que est´a libre de
condiciones de carrera aunque es una soluci´
on incorrecta.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#i n c l u d e
#i n c l u d e
#i n c l u d e
#i n c l u d e
<c h r o n o>
<i o s t r e a m >
<mutex>
<t h r e a d>
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
u s i n g namespace s t d ;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
mutex m;
void s e c c i o n c r i t i c a ( char c )
{
m. l o c k ( ) ;
f o r ( c h a r i = 0 ; i < 1 0 ; ++i )
c o u t << c++;
c o u t << e n d l ;
m. u n l o c k ( ) ;
}
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
13 / 18
Ejemplo: le-lg.cc
https://pccito.ugr.es/~gustavo/as/practicas/11/le-lg.cc
Copie el programa le-lg.cc y verifique que est´a libre de
condiciones de carrera aunque es una soluci´
on incorrecta.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#i n c l u d e
#i n c l u d e
#i n c l u d e
#i n c l u d e
<c h r o n o>
<i o s t r e a m >
<mutex>
<t h r e a d>
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
u s i n g namespace s t d ;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
mutex m;
void s e c c i o n c r i t i c a ( char c )
{
l o c k g u a r d <mutex> l g (m) ;
f o r ( c h a r i = 0 ; i < 1 0 ; ++i )
c o u t << c++;
c o u t << e n d l ;
}
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
14 / 18
Trabajo: le-pe.cc
Copie el programa le.cc en el fichero le-pe.cc.
Modifique le-pe.cc de forma que siga libre de
condiciones de carrera y adem´as permita el
paralelismo entre escritores.
Pista: a lo mejor le puede venir bien un
interruptor.
Compare su soluci´on con la de Stallings.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
15 / 18
interruptor.h
https://pccito.ugr.es/~gustavo/as/practicas/11/interruptor.h
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class interruptor
{
public :
i n t e r r u p t o r ( ) : c o n t a d o r ( 0 ) {}
v o i d l o c k ( s t d : : mutex& l l a v e )
{
s t d : : u n i q u e l o c k <s t d : : mutex> l o c k (m) ;
i f (++c o n t a d o r == 1 )
l l a v e . lock () ;
}
v o i d u n l o c k ( s t d : : mutex& l l a v e )
{
s t d : : u n i q u e l o c k <s t d : : mutex> l o c k (m) ;
i f ( −−c o n t a d o r == 0 )
l l a v e . unlock () ;
}
private :
int contador ;
s t d : : mutex m;
};
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
16 / 18
Trabajo: le-li.cc
La soluci´on anterior, le-pe.cc, ¿est´a libre de inanici´on?
Compru´ebelo poniendo especial atenci´
on a los escritores.
Copie el programa le.cc en el fichero le-li.cc.
Modifique le-li.cc de forma que siga libre de condiciones de
carrera, permita el paralelismo entre escritores y est´e libre de
inanici´on.
Pista: a lo mejor le puede venir bien un torno.
ejemplo de torno
sem´a f o r o s = 1 ;
...
s . esperar () ;
s . se n
˜ alar () ;
...
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
17 / 18
Trabajo: le-justa.cc
Copie el programa le.cc en el fichero le-justa.cc.
Modifique le-justa.cc de forma que funcione
permitiendo una ejecuci´on equilibrada de
lectores y escritores.
Evite expl´ıcitamente las versiones que favorecen
a unos u otros.
Gustavo Romero L´
opez
Pr´
actica 11: El problema de los Lectores/Escritores
18 / 18