Práctica 11: El problema de los Lectores/Escritores
Transcription
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