interbloqueo CP

download interbloqueo CP

of 30

description

introduccion interbloqueo cp

Transcript of interbloqueo CP

  • Introduccin a Concurrencia II.Interbloqueo y Condiciones

    Juan Quintela. Javier Pars.{quintela, javier.paris}@udc.es

  • Interbloqueo (Deadlock)

    int protected_add(int *v1, mutex *m1, int *v2, mutex *m2) {

    int x;

    lock(m1);

    lock(m2);

    x=v1+v2;

    unlock(m2);

    unlock(m1);

    return x;

    }

    Interbloqueo es una situacin en que dos o ms procesos estn esperando por recursos que tiene ocupado el otro.

    Ejemplo con una funcin que devuelve la suma de dos variables protegidas:

  • Interbloqueo

    Desde dos threads distintos se llama a la funcin con las mismas variables pero en orden cambiado:

    int valor1, valor2; // Dos variables compartidas

    mutex m_valor1, m_valor2; // Mutex para proteger las variables valor1 y valor2 respectivamente

    thread1:

    protected_add(&valor1, &m_valor1, &valor2, &m_valor2); thread2:

    protected_add(&valor2, &m_valor2, &valor1, &m_valor1);

  • InterbloqueoThread 1:

    int protected_add(

    int *v1 (=valor1),

    mutex *m1(=m_valor1),

    int *v2(=valor2),

    mutex *m2 (=m_valor2))

    {

    int x;

    lock(m1);

    lock(m2);

    x=v1+v2;

    unlock(m2);

    unlock(m1);

    return x;

    }

    Thread 2:

    int protected_add(

    int *v1 (=valor2),

    mutex *m1(=m_valor2),

    int *v2(=valor1),

    mutex *m2 (=m_valor1))

    {

    int x;

    lock(m1);

    lock(m2);

    x=v1+v2;

    unlock(m2);

    unlock(m1);

    return x;

    }

  • Interbloqueo

    Thread 1:

    int protected_add(

    int *v1 (=valor1),

    mutex *m1(=m_valor1),

    int *v2(=valor2),

    mutex *m2 (=m_valor2))

    {

    int x;

    lock(m_valor1);

    lock(m_valor2);

    x=valor1+valor2;

    unlock(m_valor2);

    unlock(m_valor1);

    return x;

    }

    Thread 2:

    int protected_add(

    int *v1 (=valor2),

    mutex *m1(=m_valor2),

    int *v2(=valor1),

    mutex *m2 (=m_valor1))

    {

    int x;

    lock(m_valor2);

    lock(m_valor1);

    x=valor2+valor1;

    unlock(m_valor1);

    unlock(m_valor2);

    return x;

    }

    Cambiamos los nombres de las variables en el cdigo para ver ms clara la ejecucin.

  • Interbloqueo

    Thread 1:

    int protected_add(

    int *v1 (=valor1),

    mutex *m1(=m_valor1),

    int *v2(=valor2),

    mutex *m2 (=m_valor2))

    {

    int x;

    lock(m_valor1);

    lock(m_valor2);

    x=valor1+valor2;

    unlock(m_valor2);

    unlock(m_valor1);

    return x;

    }

    Thread 2:

    int protected_add(

    int *v1 (=valor2),

    mutex *m1(=m_valor2),

    int *v2(=valor1),

    mutex *m2 (=m_valor1))

    {

    int x;

    lock(m_valor2);

    lock(m_valor1);

    x=valor2+valor1;

    unlock(m_valor1);

    unlock(m_valor2);

    return x;

    }

    El thread 1 bloquea m_valor1, y el thread 2 bloquea m_valor2

  • Interbloqueo

    Thread 1:

    int protected_add(

    int *v1 (=valor1),

    mutex *m1(=m_valor1),

    int *v2(=valor2),

    mutex *m2 (=m_valor2))

    {

    int x;

    lock(m_valor1);

    lock(m_valor2); // Espera eterna

    x=valor1+valor2;

    unlock(m_valor2);

    unlock(m_valor1);

    return x;

    }

    Thread 2:

    int protected_add(

    int *v1 (=valor2),

    mutex *m1(=m_valor2),

    int *v2(=valor1),

    mutex *m2 (=m_valor1))

    {

    int x;

    lock(m_valor2);

    lock(m_valor1); // Espera eterna

    x=valor2+valor1;

    unlock(m_valor1);

    unlock(m_valor2);

    return x;

    }

    El thread 2 intenta bloquear m_valor2, pero est bloqueado por el thread 2, y el thread 2 intenta bloquear m_valor1, pero est bloqueado por el thread 1.=> El thread 1 y el thread 2 estn en interbloqueo, porque cada uno espera por el otro.

  • Interbloqueo

    Condiciones necesarias para que exista: Exclusin mutua: existen recursos no compartibles. Hold and wait: se permite que un proceso tenga

    recursos reservados mientras espera para reservar otros.

    No apropiacin: El sistema operativo no puede liberar recursos reservados.

    Espera circular: Los procesos esperan por recursos reservados por procesos que esperan por los primeros.

    Negar cualquiera de estas condiciones lo evita.

  • Interbloqueo: Tratamiento.

    El interbloqueo se puede tratar mediante varias tcnicas, algunas aplicadas por el sistema operativo, otras por el propio sistema concurrente.

    Algunos sistemas operativos (como Unix o Windows) ignoran el problema. Es tarea del programador de espacio de usuario evitar que se produzca.

  • Interbloqueo: Deteccin

    En deteccin se permite que ocurran interbloqueos, y se corrigen despus.

    Como el sistema operativo conoce que recursos tiene reservados un proceso, y por que recursos espera puede saber cuando se produce interbloqueo.

    Una vez detectado puede Matar a los procesos involucrados. Apropiar recursos reservados y drselos a otro

    proceso para resolver la situacin.

  • Interbloqueo: Prevencin

    En prevencin se trata de evitar que una de las 4 condiciones necesarias se produzca: Exclusin mutua, impidiendo que los procesos tengan acceso

    exclusivo a los recursos. Evitar hold and wait:

    Haciendo que los procesos reserven todos los recursos necesarios de una vez en vez de mantener reservados unos mientras esperan.

    Haciendo que los procesos liberen los recursos reservados si no pueden reservar ms.

    Evitar la no apropiacin. Es necesario implementar algn mecanismo de roll-back.

    La espera circular se puede evitar con una reserva ordenada de recursos.

  • Interbloqueo: Prevencin evitando hold and wait

    Ejemplo: evitar mantener recursos reservados.int protected_add(int *v1, mutex *m1, int *v2, mutex *m2) {

    int x;

    int success=0;

    do {

    lock(m1);if(try_lock(m2)) { // Si no reserva m2 libera m1 y vuelve a probar

    x=v1+v2;unlock(m2);success=1;

    }unlock(m1);

    } while(!success);

    return x;

    }

  • Interbloqueo: Prevencin con Reserva Ordenada

    Ejemplo reserva ordenada:int protected_add(int *v1, mutex *m1, int ordenv1, int *v2, int ordenv2, mutex *m2)

    {

    int x;

    if(ordenv1 < ordenv2) {

    lock(m1); lock(m2);} else {

    lock(m2); lock(m1);}

    x=v1+v2;

    unlock(m2);

    unlock(m1);

    }

  • Introduccin: Prevencin con Reserva Ordenada

    Para llamarlo definimos un orden en los recursos:#define ORDENV1 1

    #define ORDENV2 2

    int valor1, valor2; // Dos variables compartidas

    mutex m_valor1, m_valor2; // Mutex para proteger valor1 y valor2 thread1:

    protected_add(&valor1, &m_valor1, ORDENV1,

    &valor2, &m_valor2, ORDENV2); thread2:

    protected_add(&valor2, &m_valor2, ORDENV2,

    &valor1, &m_valor1, ORDENV1);

  • Interbloqueo: Evitacin

    En evitacin se intenta prevenir que el sistema entre en una situacin de interbloqueo conociendo el estado del sistema y los recursos que los procesos pueden reservar en el futuro.

    Requiere conocer a priori el uso de recursos que va a hacer un proceso, lo que limita mucho su uso.

  • Inanicin

    Un proceso puede estar esperando acceso a un recurso compartido sin conseguirlo. Esta situacin se denomina inanicin.

    Por ejemplo, si requerimos la reserva de todos los recursos simultneamente, los procesos que requieran una gran cantidad de recursos pueden quedar en este estado si hay muchos procesos que requieren pocos compitiendo por ellos.

  • InanicinEjemplo: Un thread que necesita bloquear muchos recursos.

    mutex *m1, *m2, *m3;

    void *bloqueo_mucho(void *arg) {while(1) {

    lock(m1);if (try_lock(m2)) {

    if(try_lock(m3)) {// Hacer algo con los recursos protegidos por m1, m2 y m3

    }

    unlock(m2);}unlock(m1);

    }

    }

    Se usa trylock porque si no se consigue bloquear m2 o m3 queremos

    minimizar el tiempo que se mantienen mutex bloqueados => implica que el

    thread se tiene que encontrar los 3 mutex libres para tener xito.

  • InanicinOtros threads solo necesitan un mutex:

    void *bloqueam1(void *arg) {lock(m1);

    // Hacer algo con el recurso protegido por m1

    unlock(m1);

    }

    void *bloqueam2(void *arg) {lock(m2);

    // Hacer algo con el recurso protegido por m2

    unlock(m2);

    }

    void bloqueam3(void *arg) {lock(m3);

    // Hacer algo con el recurso protegido por m3

    unlock(m3);

    }

  • Inanicin

    Que ocurre si hay muchos threads ejecutando bloquem1, bloqueam2 y bloqueam3? => Es muy probable que en todo momento alguno de los mutex est bloqueado.

    El thread que ejecuta bloqueamucho no es capaz de entrar en su seccin crtica => inanicin.

  • Sincronizacin por Condiciones

    Una condicin permite a los procesos/threads suspender su ejecucin hasta que se les despierte.

    Se disearon porque a veces es necesario interrumpir la ejecucin en medio de una seccin crtica hasta que el estado de un recurso compartido cambie por la accin de otro proceso.

    Ese otro proceso es el que debe encargarse de despertar a los que puedan estar esperando.

  • Sincronizacin por Condiciones

    En la librera pthread:

    pthread_cond_t

    int pthread_cond_init(pthread_cond_t *, pthread_condattr_t *);

    int pthread_cond_signal(pthread_cond_t *);

    int pthread_cond_broadcast(pthread_cond_t *);

    int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);

    int pthread_cond_timedwait(pthread_cond_t *,

    pthread_mutex_t *, const struct timespec *);

  • Sincronizacin por Condiciones

    Ejemplo: Threads que comparten una cach en memoria guardada en un array indexado por un hash. Las posiciones se reservan hasta que se liberen explcitamente.

    dato cache[CACHE_SIZE];

    int reservado[CACHE_SIZE];

    pthread_mutex_t m;

    pthread_cond_t espera[CACHE_SIZE];

  • Sincronizacin por Condiciones

    void insert(dato d) {int pos = hash(d);

    pthread_mutex_lock(&m);

    while(reservado[pos])pthread_cond_wait(&espera[pos],&m);

    reservado[pos]=1;

    cache[pos]=d;

    pthread_mutex_unlock(&m);

    }

  • Sincronizacin por condiciones

    void liberar(dato d) {int pos = hash(d);

    pthread_mutex_lock(&m);

    reservado[pos]=0;

    pthread_cond_signal(&reservado[pos]);

    pthread_mutex_unlock(&m);

    }

  • Sincronizacin por Condiciones

    Internamente el wait hace de forma atmica:

    wait(cond *c, mutex *m) {unlock(m);

    espera(m);

    lock(m);

    }

    Atmico

  • Sincronizacin por Condiciones

    Por que es necesario bloquear el mutex para esperar y cuando se manda la seal? => Antes de esperar siempre se comprueba una condicin, y es necesario que la comprobacin no cambie hasta que el thread est esperando.

  • Sincronizacin por Condiciones

    void insert(dato d) {int pos = hash(d);

    while(reservado[pos])pthread_cond_wait(

    &espera[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=1;

    cache[pos]=d;

    pthread_mutex_unlock(&m);

    }

    void liberar(dato d) {

    int pos = hash(d);

    pthread_cond_signal(&reservado[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=0;

    pthread_mutex_unlock(&m);

    }

    Como ejemplo, en el caso anterior, quitando los bloqueos antes de comprobar:

  • Sincronizacin por Condiciones

    void insert(dato d) {int pos = hash(d);

    while(reservado[pos])pthread_cond_wait(

    &espera[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=1;

    cache[pos]=d;

    pthread_mutex_unlock(&m);

    }

    void liberar(dato d) {

    int pos = hash(d);

    pthread_cond_signal(&reservado[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=0;

    pthread_mutex_unlock(&m);

    }

    El primer thread comprueba la condicin, mientras el segundo calcula el hash.

  • Sincronizacin por Condiciones

    void insert(dato d) {int pos = hash(d);

    while(reservado[pos])pthread_cond_wait(

    &espera[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=1;

    cache[pos]=d;

    pthread_mutex_unlock(&m);

    }

    void liberar(dato d) {

    int pos = hash(d);

    pthread_cond_signal(&reservado[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=0;

    pthread_mutex_unlock(&m);

    }

    El primer thread hace la comprobacin, como el recurso est ocupado la condicin secumple y entra por el if. El segundo manda la seal, como nadie espera no pasa nada.

  • Sincronizacin por Condiciones

    void insert(dato d) {int pos = hash(d);

    while(reservado[pos])pthread_cond_wait(

    &espera[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=1;

    cache[pos]=d;

    pthread_mutex_unlock(&m);

    }

    void liberar(dato d) {

    int pos = hash(d);

    pthread_cond_signal(&reservado[pos]);

    pthread_mutex_lock(&m);

    reservado[pos]=0;

    pthread_mutex_unlock(&m);

    }

    El primer thread espera, pero como la seal ya se envi se queda esperandoindefinidamente. La seal se ha perdido (Lost Wakeup).