Concurrencia - Mutex
En esta entrada hablaremos acerca de la concurrencia.
En particular de los Mutex. Los mutex será el mecanismo que nos ayude en la
sincronización para proteger una sección crítica en nuestro código. Estas
secciones críticas serán los datos a los que se acceda de forma concurrente.
Por ejemplo si desde dos hilos diferentes leemos y escribimos en una variable
global la ejecución puede ser deficiente.
Supongamos que tenemos dos hilos (h1 y h2) que leen de
la variable 'valor' que inicialmente tiene un valor de 5. Si ambas desean
aumentar el valor de esta variable puedo ocurrir lo siguiente:
- El hilo h1 lee valor (5).
- El hilo h2 lee valor (5).
- El hilo h2 aumenta en 3 valor (5+3=8) y guarda.
- El hilo h1 aumenta en 2 valor (5+2=7) y guarda.
Una vez finalizado esto valor es igual a 7 cuando debería ser igual a 10. Para evitar esto empleamos como mecanismo de sincronización los mutex. Los mutex nos ayudaran a bloquear los accesos a datos, mientras un proceso ligero (hilo) este accediendo a una sección crítica otro proceso no podrá acceder a ella y esperará a que liberen el mutex para acceder a ella. Las variables mutex son del tipo pthread_mutex_t los métodos para emplear los mutex son los siguientes:
- int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t * attr);
- Inicializa el mutex
- int pthread_mutex_destroy(pthread_mutex_t *mutex) ;
- Destruye el mutex (lo elimina de la memoria).
- int pthread_mutex_lock(pthread_mutex_t *mutex);
- Bloquea el mutex si no lo tiene nadie. Si alguien tiene bloqueado el mutex el proceso espera hasta que el proceso que lo tiene bloqueado lo libera.
- int pthread_mutex_unlock(pthread_mutex_t *mutex);
- Libera el mutex.
Existe también un tipo de mecanismo de sincronización
llamado variables condición que veremos en una entrada posterior. Además
también existen los llamados semaforos, sin embargo es preferible emplear mutex
y variables condición (en conjunto). Los semaforos también se verán en próximas
entradas.
Para ver el uso de los mutex realizaré un ejemplo con
el famoso problema de concurrencia de lectores-escritores. En este problema
existen procesos escritores (modifican datos) y lectores que los leen. Las
especificaciones del problema son: tan solo puede haber 1 escritor escribiendo,
para escribir no puede haber ningún lector. Puede haber cualquier número de
lectores siempre y cuando no se esté escribiendo. Como crear hilos en una entrada anterior
int dato = 5; /* recurso */ int lectores = 0; /* numero de lectores, es también un recurso, tan solo para los lectores */ pthread_mutex_t mutexG; /* controlar el acceso a dato */ pthread_mutex_t mlectores; /* controla acceso n_lectores */ int main(int argc, char *argv[]) { pthread_t th1, th2, th3, th4; pthread_mutex_init(&mutexG, NULL); pthread_mutex_init(&mlectores, NULL); pthread_create(&th1, NULL, (void*)Lector, NULL); pthread_create(&th2, NULL, (void*)Escritor, NULL); pthread_create(&th3, NULL, (void*)Lector, NULL); pthread_create(&th4, NULL, (void*)Escritor, NULL); pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); pthread_join(th4, NULL); pthread_mutex_destroy(&mutexG); pthread_mutex_destroy(&mlectores); exit(0); } /* * Código del escritor */ void Escritor(void) { pthread_mutex_lock(&mutexG); dato = dato + 2; /* aumenta el dato*/ pthread_mutex_unlock(&mutexG); pthread_exit(0); } /* * Código del lector */ void Lector(void) { pthread_mutex_lock(&mlectores); lectores++; if (lectores == 1) pthread_mutex_lock(&mutexG); pthread_mutex_unlock(&mlectores); printf("%d\n", dato); /* leemos el dato dato */ pthread_mutex_lock(&mlectores); lectores--; if (lectores == 0) pthread_mutex_unlock(&mutexG); pthread_mutex_unlock(&mlectores); pthread_exit(0); }
Podemos ver como se bloquea el mutex general cuando se
va a escribir. Esto hace que mientras que se esté escribiendo no se pueda
realizar ninguna otra acción y tan solo exista 1 escritor escribiendo a la vez.
Por otra parte en los lectores tenemos un mutex que bloquea el acceso a la
variable que cuenta el número de lectores. Si es el primer lector bloquea el
mutex general para que no se pueda escribir mientras se está leyendo. Cuando el
último lector a finalizado de leer libera el mutex para que se pueda comenzar a
escribir.
Con esto espero que haya quedado claro. Si tenéis
alguna duda podéis escribir un comentario.
gracias por este post....
ResponderEliminarsaludos
de nada...
ResponderEliminarsaludos
gracias pero no encuentro su "post promesa" de semáforos por ningún lado, si existe agradecería si pudiese facilitarme el enlace.
ResponderEliminarEstos Post fueron realizados para ayudar a compañeros de clase. En esos momentos me pidieron otra serie de post, pero me lo apunto a mi lista de cosas pendientes. En cuanto termine los exámenes me pongo a ello. Gracias por tu comentario =)
Eliminargracias a ti por estos posts, me han sido de mucha utilidad
EliminarGracias por este post. Aunque me gustaría que hicieses el de semáforos
ResponderEliminarGran post, gracias
ResponderEliminarExcelentes posts muy claros y entendibles
ResponderEliminar