18/01/2020, 18:06:40 pm *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.

Ingresar con nombre de usuario, contraseña y duración de la sesión
Noticias: ¡Atención! Hay que poner la matemática con LaTeX, y se hace así (clic aquí):
 
 
Páginas: [1]   Ir Abajo
  Imprimir  
Autor Tema: Lectores y escritores - PTHREAD  (Leído 1359 veces)
0 Usuarios y 1 Visitante están viendo este tema.
dresuer
Pleno
****

Karma: +0/-0
Desconectado Desconectado

Sexo: Masculino
Argentina Argentina

Mensajes: 112



Ver Perfil
« : 06/05/2017, 18:17:13 pm »

Código: (c)
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t MyMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t seguir2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t seguir = PTHREAD_COND_INITIALIZER;

#define N 5

int aloja = 0;
int sigo = 0;



/*
Cuando un thread -que debe tener el mutex ya tomado- llama a wait(), suelta el mutex y
entra en espera bloqueante.

DEBE TENER EL MUTEX YA TOMADO!



Cuando un thread llama a signal(), otro thread en espera, de haberlo, se despierta de su wait()
CON EL MUTEX YA ADQUIRIDO

CON EL MUTEX YA ADQUIRIDO!

*/

void *freno (void *a)
{
for (;;){

// Tomo el mutex.
pthread_mutex_lock(&MyMutex);

// Hey!, quiero entrar, terminá lo que estás haciendo, te espero.
aloja = 1;

// Espero hasta que se "apague" la función avanzar.
// Cuando se apaga, AUTOMATICAMENTE TOMO YO EL MUTEX!!
while (sigo != 0){printf ("me llego la señal.\n"); pthread_cond_wait(&seguir,&MyMutex);}

// Si llegué hasta acá es porque yo tengo el mutex nadie mas lo puede tomar.
printf ("Estoy en freno\n");

// Terminé de hacer todo lo que quería hacer.
aloja = 0; // Por más que lo ponga el 0, "avanzar" no puede entrar todavía, porque
// yo tengo el mutex!


/* Libero el mutex, es decir, ahora la función avanzar sí puede tomar el mutex, PERO
a la vez no ya que está dentro de un wait esperando un SIGNAL no que libere un mutex.
Aunque no está demás recordar que solo 1 puede tomar el mutex a la vez. */
pthread_mutex_unlock(&MyMutex);

/*
Cuando un thread llama a signal(), otro thread en espera, de haberlo, se despierta de su wait
CON EL MUTEX YA TOMADO!

pthread_cond_signal(&seguir2);

*/

/*
Cuando un thread llama a broadcast(), todos los threads en espera, de haberlo, se despiertan de su
wait CON EL MUTEX YA TOMADO, es decir en este caso, se pelean por quien toma el mutex.
*/

pthread_cond_broadcast(&seguir2);
}
}


void *avanzar (void *b)
{
for (;;){
// Tomo yo el mutex, nadie más lo puede tomar.
pthread_mutex_lock(&MyMutex);
sigo++;
// Libero, ahora si puede tomar el mutex la función "freno".
pthread_mutex_unlock(&MyMutex);

//sleep(3);
printf ("estoy en sigo.\n");

// No puedo tomar el mutex hasta que la función freno recién llegue a la linea donde entra en espera!
pthread_mutex_lock(&MyMutex);
sigo--;
// Libero el mutex, recien ahora pueden ejecutarse más funciones "freno", antes no porque yo tenía el
// mutex tomado.
pthread_mutex_unlock(&MyMutex);

printf("Avanzar: %d\n",sigo);

/* Esta señal está esperando "freno" para poder continuar, pero además de esperar la señal espera
también que la cantidad de "sigo" sea igual a 0 */

/*
Si sigo es un número mayor a 0, entonces de todos modos va a seguir esperando.
*/
pthread_cond_signal(&seguir);

/*PERO! a la vez yo me bloqueo. Esperando ahora que "freno" me desbloque. */
/* Y a su vez freno está esperando que yo lo desbloquee. */
while (aloja != 0)pthread_cond_wait(&seguir2,&MyMutex);

/*
¿Qué pasaría si avanzar toma el mutex e incrementa en 1 la variable "sigo" y al toque "freno" pone
en 1 la variable aloja?

Lo que pasaría es que la variable sigo se incrementa luego suelta el mutex, lo toma la función"freno"
pone en 1 aloja pero como sigo es mayor que cero entonces SUELTA el mutex automáticamente y deja
que siga funcionando "avanzar", entonces pueden pasar cosas!:

Primero de todo, no se pueden ejecutar dos "frenos" a a la vez pero si se pueden ejecutar "avanzar"
muchas veces.

Entonces, avanzar toma el mutex y decrementa en 1 la variable
sigo y al momento lo suelta, PERO "freno" todavía no puede hacer nada porque está esperando un
signal,  no está esperando que suelte el mutex (explicado anteriormente)

Entonces yo le doy el signal y suponiendo que el numero de sigo es igual a 0, se ejecuta freno y yo
entro en espera hasta que freno termine.


*/
}

}

int main (void)
{
int i;
pthread_t prueba1[N],prueba2[N];

for (i=0; i<N; i++){
pthread_create(&prueba1[i],0,freno,"aloja");
pthread_create(&prueba2[i],0,avanzar,"chau");
}

pthread_join(prueba1[0],0);
return 0;
}

El programa sigue está logica aunque las funciones no se llamen lector y escritor.

1. No puede haber un lector accediendo al arreglo al mismo tiempo que un escritor.
2. Varios lectores pueden acceder al arreglo simult´aneamente.
3. S´olo puede haber un escritor a la vez.

Y además cuando los lectores que están leyendo terminen su lectura pero no se puedan empezar nuevas lecturas hasta que el escritor escriba.

freno = escritor.
avanzar = lector.

Aunque en este caso no escriben ni leen nada solo muestran texto.

El problema es que no funciona y no sé que es lo que estoy pensando mal, el programa se congela es decir en algún momento queda esperando algo que nunca llega.



Lo solucioné así:

Código:
#include <stdio.h>
#include <pthread.h>

#define N 15
#define ARRLEN 1024

pthread_mutex_t MyMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t seguir = PTHREAD_COND_INITIALIZER;
pthread_cond_t seguir2 = PTHREAD_COND_INITIALIZER;

int arr[ARRLEN];

// Cantidad de funciones "lectores" que se están ejecutando.
int lectores = 0;
// Variable utilizada por si quiero escribir.
int wannawrite = 0;


void *escritor(void *arg)
{
  int i;
  int num = *((int *)arg);
  for (;;) {
    /*
       Escribo el mutex al principio y este está tomando toda la función porque no pueden
       haber más de 1 escritor a la vez.
    */
    pthread_mutex_lock(&MyMutex);

    /* Hey!!, quiero escribir!!, ahora todos deben dormir hasta que termine de escribir.*/
    wannawrite = 1;
   
    /* Espero hasta que todos los que estan leyendo, terminen de leer y se pogan a dormir
       De no ser así libero el mutex.

       wait(): Si tiene la señal, entonces despierta con EL MUTEX YA ADQUIRIDO.
    */
    while (lectores != 0) pthread_cond_wait(&seguir,&MyMutex);

    //sleep(random()%3);
    for (i=0; i<ARRLEN; i++) {
      arr[i] = num;
    }

    // Terminé de escribir.
    wannawrite = 0;

    // Heeyy!!, despertá todos los lectores que tuvieron que dormir para que pueda escribir.
    pthread_cond_broadcast(&seguir2);
    pthread_mutex_unlock(&MyMutex);
  }
  return NULL;
}

void *lector(void *arg)
{
  int v, i, err;
  int num = *((int *)arg);
  for (;;) {
    /* En este caso si pueden haber más lectores a la vez entonces no voy a bloquear toda la función con un mutex,
     solo la bloquearé por partes. */

    pthread_mutex_lock(&MyMutex);
    lectores++;
    pthread_mutex_unlock(&MyMutex);
   
    //sleep(random()%3);
    err = 0;
    v = arr[0];
    for (i=1; i<ARRLEN; i++) {
      if (arr[i]!=v) {
        err=1;
        break;
      }
    }
    if (err) printf("Lector %d, error de lectura\n", num);
    else printf("Lector %d, dato %d\n", num, v);

    pthread_mutex_lock(&MyMutex);
    lectores--;

    /* si pondría un unlock acá, podría pasar cualquier cosa hasta que mande
       la señal de que yo terminé de leer y luego esperar. Por eso el unlock lo pongo al final.
       Si yo tengo el mutex por más que el otro tenga la señal y los lectores sean 0
       no puede tomar el mutex por lo tanto se queda bloqueado hasta que lo libero.  */

    /* Mando una señal que un thread terminó de leer. */
    pthread_cond_signal(&seguir);

    // Si quiere escribir, entonces me bloqueo hasta que me avise que terminó de escribir.
    while(wannawrite == 1) pthread_cond_wait(&seguir2,&MyMutex);

    // Ahora si suelto el mutex.
    pthread_mutex_unlock(&MyMutex);

  }
  return NULL;
}

int main()
{
  int i;
  pthread_t lectores[N], escritores[N];
  int arg[N];

  for (i=0; i<ARRLEN; i++) {
    arr[i] = -1;
  }
  for (i=0; i<N; i++) {
    arg[i] = i;
    pthread_create(&lectores[i], NULL, lector, (void *)&arg[i]);
    pthread_create(&escritores[i], NULL, escritor, (void *)&arg[i]);
  }
  pthread_join(lectores[0], NULL); /* Espera para siempre */
  return 0;
}

En línea
Páginas: [1]   Ir Arriba
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.4 | SMF © 2006, Simple Machines LLC XHTML 1.0 válido! CSS válido!