#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.
			
			
			
				Un detalle importante: Ponle mutex a los printf.
Y luego pues... Intenta darle un enfoque práctico al programa. A ti te puede ser más fácil visualizarlo así, y desde luego, a nosotros también (decir que es como un lector y un escritor no ayuda mucho).
Especifica qué quieres que haga el programa exactamente, y entonces será más fácil verlo.
			
			
			
				Lo solucioné así: 
#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;
}
De todos modos esta solución le da demasiada prioridad a los escritores que a los lectores, no sé por qué se debe eso.
¿Alguna idea?