#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.
// 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);
// 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);
/* 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;
}