PROBLEMA PRODUCTOR CONSUMIDOR.
Cuando se comparten recursos en una PC, tal es el caso de un Buffer lo mas común es que exista un proceso que se encargue de llenar el Buffer de información y otro proceso que saque información de este Buffer para procesarla, es en esta situación donde se origina el problema del productor y consumidor, a continuación se resolverá este problema usando el método de los semáforos en lenguaje C.
>> Implantación de semáforos: #define N 100 /* número de ranuras en el buffer */ typedef int semaphore; /* los semáforos son un tipo especial de int */ semaphore mutex = 1; /* controla el acceso a la región crítica */ semaphore empty = N; /* cuenta ranuras vacías */ semaphore full = 0; /* cuenta ranuras completas */ >>Productor: producer() { int item; while (TRUE){ produce_item(&item); produce_it em(&item); down(empty); down(mutex); enter_item(); enter_item( ); up(mutex); up(full); up(full ); } }
/* repetir indefinidamente */ /* generar el siguiente elemento */ /* disminuir disminui r el conteo vacío */ /* entrar en región crítica */ /* colocar un elemento en el buffer */ /* salir de la región crítica */ /* incrementar ranuras completas */
>> Consumidor: consumer() { int item; while (TRUE){
/* repetir indefinidamente */
produce_item(&item); down(full); down(mutex); remove_item(); up(mutex); up(empty); consume_item(); }
/* generar el siguiente elemento */ /* disminuir el conteo completo */ /* entrar en región crítica */ /* tomad un elemento del buffer */ /* salir de la región crítica */ /* incrementar ranuras vacías */ /* hacer algo con el elemento */
}
Acontinuacion se presenta una idea de la solucion de este problema clasico usando contador de eventos que es una solucion alternativa a este problema tan conocido:
#include “prototypes.h” #define N 100 typedef int event_counter; event_counter in = 0; event_counter out = 0;
void producer(void) { int item, sequence = 0; while (TRUE) { sequence = sequence + 1; await(in, sequence);
/*número de entradas en el almacén (buffer)*/ /*event_counter son un tipo especial de int*/ /*cuenta los elementos insertados en el almacén (buffer) */ /*cuenta los elementos retirados del almacén (buffer)*/
/*ciclo infinito*/ /*número de elemento a eliminar del almacén (buffer)*/ /*espera a que esté presente el elemento del
espacio*/ /*retira al elemento de la entrada (sequence – 1) % N */ /*deja que el productor se entere de que el elemento ha sido retirado*/ /*hace algo con el elemento*/
remove_item(&item); Advance(&out); consume_item(item) } }
LA CENA DE LOS FILOSOFOS
#include #include #include #include #include #include
/* Ejemplo 2.1 Programa para el problema de la cena de los filósofos. Cuando se invoca al programa se debe hacer con un argumento que indique el número de filósofos que queremos considerar. El programa debe reservar los recursos a compartir. Después generará tantos filósofos como procesos hijos como se le halla indicado en el argumento. Como máximo se permitirán 10 procesos hijos compitiendo por los recursos para no sobrecargar el sistema. */ #define IZQ (i+nfil-1)%nfil #define DER (i+1)%nfil #define PENSANDO #define HAMBRE #define COMIENDO
/* Vecinos izquierdos de i */ /* Vecinos derechos de i */
0 1 2
int nfil=5; /* Número de filósofos */ int shmid, /* Identificador de la memoria compartida */ semid; /* Identificador de los semaforos */ int *estado; /* Array para ver el estado de cada filósofo */ void sintaxis(void) { printf("Uso: filosofo \n"); return; } void muestra_estados(void)
{ struct sembuf op; int i; op.sem_num=0; op.sem_op=-1; op.sem_flg=0; semop(semid, &op, 1);
/* down(&mutex); */
for(i=0;i
/* up(&mutex); */
}
void probar(int i) { struct sembuf op; if(estado[i] == HAMBRE && estado[IZQ]!=COMIENDO && estado[DER]!=COMIENDO) { estado[i]=COMIENDO; op.sem_num=i+1; op.sem_op=1; op.sem_flg=0; semop(semid, &op, 1);
/* up(&s[i]); */
} } void tomar_palillos(int i) { struct sembuf op; op.sem_num=0; op.sem_op=-1; op.sem_flg=0; semop(semid, &op, 1);
/* down(&mutex); */
estado[i]=HAMBRE; probar(i); op.sem_num=0; op.sem_op=+1; op.sem_flg=0; semop(semid, &op, 1);
/* up(&mutex); */
op.sem_num=i+1; op.sem_op=-1; op.sem_flg=0; semop(semid, &op, 1);
/* down(&s[i]); */
} void dejar_palillos(int i) { struct sembuf op; op.sem_num=0; op.sem_op=-1; op.sem_flg=0; semop(semid, &op, 1);
/* down(&mutex); */
estado[i]=PENSANDO; probar(IZQ); probar(DER); op.sem_num=0; op.sem_op=+1; op.sem_flg=0; semop(semid, &op, 1);
/* up(&mutex); */
}
void pensar(void) { muestra_estados(); sleep(1); /* Estan pensando un segundo */ } void comer(void) { /* muestro el nuevo estado de todos */ muestra_estados(); sleep(1); /* Estan comiendo un segundo */ } int main(int argc, char *argv[]) { int i,a; struct sembuf op; if(argc!=2) { sintaxis(); exit(0); } nfil=atoi(argv[1]); if(nfil<2 | nfil>10) { printf("Parámetro incorrecto\n"); printf("El número de filósofos debe estar entre 2 y 10\n"); sintaxis(); exit(0); } /* Primero reservamos los recursos */
/* Reservamos un arreglo compartido para ver el estado de cada uno este arreglo sustituye a la declaración int estado[N] de Tanenbaum */ shmid=shmget(IPC_PRIVATE,nfil*sizeof(int), IPC_CREAT | 0600); if(shmid==-1) { perror("No pude reservar memoria compartida.\n"); exit(0); } /* Ahora reservamos un semáforo para cada filósofo y uno más para la exclusión mutua. Este último es siempre el semáforo número cero. */ semid=semget(IPC_PRIVATE, nfil+1, IPC_CREAT | 0600); if(semid==-1) { perror("No pude reservar los semaforos.\n"); exit(0); } /* Ponemos el mutex a uno */ op.sem_num=0; op.sem_op=1; op.sem_flg=0; semop(semid, &op, 1);
/* down(&mutex); */
/* Se crean nfil hijos */ for(i=0;i