Pasar al contenido principal

Práctica 7

Versión para impresiónSend by email

En esta práctica se usan semáforos para utilizar una caja de 5 posiciones en la que se introducen (una hebra) y sacan (otra hebra) datos, esperando si no caben más o si no hay nada.

 


pcsem.c - Crea dos hebras, una productora y otra consumidora, que introducen y sacan datos de un array de datos (Caja)

#define _REENTRANT

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>

#define Longitud 5
#define Cantidad 10

int Caja[Longitud];    
unsigned Primero = 0; 
unsigned Ultimo = 0;
sem_t hayelementos;            // Semaphore type
sem_t hayhuecos;
sem_t cerrojo;

/* Pone en entero en la cola, deteniéndose si no cabe */
void Pon(int X) {

  sem_wait(&hayhuecos);
  sem_wait(&cerrojo);
  Caja[Ultimo] = X;
  Ultimo = (Ultimo + 1) % Longitud;
  sem_post(&cerrojo);
  sem_post(&hayelementos);
  return;
}

/* Toma un entero de la cola, deteniéndose si no hay */

void Toma(int *pX) {
  sem_wait(&hayelementos);
  sem_wait(&cerrojo);
  *pX = Caja[Primero];
  Primero = (Primero + 1) % Longitud;
  sem_post(&cerrojo);
  sem_post(&hayhuecos);
  return;
}

/* Proceso que produce enteros y los encola */

void *Productor (void *pId) {                            // Hebra productora
  unsigned Id = *(unsigned*)pId;                         // Cojo mi Id
  unsigned long Periodo = Id * 1000;                     // Calculo el periodo (Id * 1000)
  int i;
  for (i = 1; i <= Cantidad; i++) {                      // Para 20 elementos
      Pon(i + Id);                                       // Introducimos el id+i en la caja, espero si no cabe
      printf("---- Productor  %6d produce %6d\n",        // Y lo informo
              Id, i+Id);
      usleep(Periodo);                                   // Esperamos un poco
  }  
  return NULL;
}

/* Proceso que consume enteros */

void *Consumidor(void *pId) {                            // Hebra consumidora
  unsigned Id = *(unsigned*)pId;                         // Cojo mi Id
  unsigned long Periodo = Id * 1000;                     // Calculo el periodo
  int Dato;
  int j;
  for (j = 1; j <= Cantidad; j++) {                       // Para 20 elementos
      Toma(&Dato);                                        // Cojo el primer dato disponible, espero si no hay
      printf("**** Consumidor %6d consume %6d\n", Id, Dato);    // y lo informo
      usleep(Periodo);                                    // Espero un poco
  }  
  return NULL;
}

 
int main(void) {
   pthread_t productorid;                             // hebra productora
   pthread_t consumidorid;                            // hebra consumidora
   unsigned Id_Productor=1000;
   unsigned Id_Consumidor=5000;

   /* preparar los semaforos - Argumentos (semaforo, entero indicando si se comparte, valor) */
   sem_init(&hayelementos, 0, 0);                    // inicializamos hayelementos a 0
   sem_init(&hayhuecos, 0, Longitud);                // inicializamos hayhuecos a longitud
   sem_init(&cerrojo, 0, 1);                         // inicializamos cerrojo a 1

   /* crear las hebras */
   pthread_create(&productorid, NULL,                // Creamos la hebra Productor
                  Productor, &Id_Productor);
   pthread_create(&consumidorid, NULL,
                  Consumidor, &Id_Consumidor);       // Creamos la hebra Consumidor

   /* esperar a que acaben las hebras */
   pthread_join(productorid, NULL);                  // Esperamos a la finalizacion
   pthread_join(consumidorid, NULL);                 // de ambas hebras
   exit(0);
}				        				        					 

 
Ejecución

merlin1@merlins1:~/Escritorio/Practicas/7$ gcc pcsem.c -o pcsem -l pthread
merlin1@merlins1:~/Escritorio/Practicas/7$ ./pcsem
---- Productor 1000 produce 1001
**** Consumidor 5000 consume 1001
---- Productor 1000 produce 1002
---- Productor 1000 produce 1003
---- Productor 1000 produce 1004
---- Productor 1000 produce 1005
**** Consumidor 5000 consume 1002
---- Productor 1000 produce 1006
---- Productor 1000 produce 1007
**** Consumidor 5000 consume 1003
---- Productor 1000 produce 1008
**** Consumidor 5000 consume 1004
---- Productor 1000 produce 1009
**** Consumidor 5000 consume 1005
---- Productor 1000 produce 1010
**** Consumidor 5000 consume 1006
**** Consumidor 5000 consume 1007
**** Consumidor 5000 consume 1008
**** Consumidor 5000 consume 1009
**** Consumidor 5000 consume 1010
merlin1@merlins1:~/Escritorio/Practicas/7$

 

Resultados Pedidos:

Explicación del funcionamiento:

Productor Consumidor HayElementos HayHuecos Cerrojo Elem. Caja
Inicio Inicio 0 10 1 0
Resto a HayHuecos y Cerrojo Me suspendo 0 9 0 0
Introduzco Dato en Caja - 0 9 0 1
Despierto a Consumidor
y Sumo a HayElementos
Resto a HayElementos
y Cerrojo
0 9 0 0
. Saco Dato de Caja 0 9 0 0
Resto a HayHuecos
y me suspendo
Despierto a Productor
y sumo a HayHuecos
0 9 0 0
Introduzco Dato en Caja . 0 9 0 1
Sumo a Cerrojo y HayElementos . 1 9 1 1
Resto a HayHuecos y Cerrojo . 1 8 0 1
Introduzco Dato en Caja . 1 8 0 2
Sumo a Cerrojo y HayElementos . 2 8 1 2
Resto a HayHuecos y Cerrojo . 2 7 0 2
Introduzco Dato en Caja . 2 7 0 3
Sumo a Cerrojo y HayElementos . 3 7 1 3
... ... ... ... ... ...

 

 Como podemos ver en la ejecución, productor introduce datos (bloqueando el acceso), cada segundo, hasta que se llena la caja. Consumidor saca un dato de la caja cada 5 segundos, bloqueando el acceso y levantando a Productor de su suspensión en la que espera a que se vacíe algún hueco de la caja.


Lo mismo pero con tres productores y dos consumidores:

pcsem2.c - Crea cinco hebras, tres productoras y dos consumidoras, que introducen y sacan datos de un array de datos (Caja)

#define _REENTRANT

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>

#define Longitud 5 
#define Cantidad 10

int Caja[Longitud];     
unsigned Primero = 0;  
unsigned Ultimo = 0;
sem_t hayelementos;			// Semaphore type
sem_t hayhuecos;
sem_t cerrojo;

/* Pone en entero en la cola, deteniéndose si no cabe */
void Pon(int X) {

  sem_wait(&hayhuecos);
  sem_wait(&cerrojo);
  Caja[Ultimo] = X;
  Ultimo = (Ultimo + 1) % Longitud;
  sem_post(&cerrojo);
  sem_post(&hayelementos);
  return;
}

/* Toma un entero de la cola, deteniéndose si no hay */

void Toma(int *pX) {
  sem_wait(&hayelementos);
  sem_wait(&cerrojo);
  *pX = Caja[Primero];
  Primero = (Primero + 1) % Longitud;
  sem_post(&cerrojo);
  sem_post(&hayhuecos);
  return;
}

/* Proceso que produce enteros y los encola */

void *Productor (void *pId) {						// Hebra productora
  unsigned Id = *(unsigned*)pId;					// Cojo mi Id
  unsigned long Periodo = Id * 1000;				        // Calculo el periodo (Id * 1000)
  int i;
  for (i = 1; i <= Cantidad; i++) {					// Para 20 elementos
      Pon(i + Id);							// Introducimos el id+i en la caja, espero si no cabe
      printf("---- Productor  %6d produce %6d\n", 		        // Y lo informo
              Id, i+Id);
      usleep(Periodo);							// Esperamos un poco
  }   
  return NULL;
}

/* Proceso que consume enteros */

void *Consumidor(void *pId) {					        // Hebra consumidora
  unsigned Id = *(unsigned*)pId;				        // Cojo mi Id
  unsigned long Periodo = Id * 1000;					// Calculo el periodo
  int Dato;
  int j;
  for (j = 1; j <= Cantidad; j++) {					// Para 20 elementos
      Toma(&Dato);							// Cojo el primer dato disponible, espero si no hay
      printf("**** Consumidor %6d consume %6d\n", Id, Dato);	        // y lo informo
      usleep(Periodo);						        // Espero un poco
  }   
  return NULL;
}

 
int main(void) {
   pthread_t productorid;							// hebra productora
   pthread_t productorid2;							// hebra productora
   pthread_t productorid3;							// hebra productora
   pthread_t consumidorid;							// hebra consumidora
   pthread_t consumidorid2;							// hebra consumidora
   unsigned Id_Productor=1000;
   unsigned Id_Consumidor=5000;

   /* preparar los semaforos - Argumentos (semaforo, entero indicando si se comparte, valor) */
   sem_init(&hayelementos, 0, 0);					// inicializamos hayelementos a 0
   sem_init(&hayhuecos, 0, Longitud);				        // inicializamos hayhuecos a longitud
   sem_init(&cerrojo, 0, 1);						// inicializamos cerrojo a 1

   /* crear las hebras */
   pthread_create(&productorid, NULL,				// Creamos la hebra Productor
                  Productor, &Id_Productor);
   pthread_create(&productorid2, NULL,				// Creamos la hebra Productor
                  Productor, &Id_Productor);
   pthread_create(&productorid3, NULL,				// Creamos la hebra Productor
                  Productor, &Id_Productor);
   pthread_create(&consumidorid, NULL,
                  Consumidor, &Id_Consumidor);		// Creamos la hebra Consumidor
   pthread_create(&consumidorid2, NULL,
                  Consumidor, &Id_Consumidor);		// Creamos la hebra Consumidor

   /* esperar a que acaben las hebras */
   pthread_join(productorid, NULL);			        // Esperamos a la finalizacion
   pthread_join(productorid2, NULL);				// Esperamos a la finalizacion
   pthread_join(productorid3, NULL);				// Esperamos a la finalizacion
   pthread_join(consumidorid, NULL);				// de ambas hebras
   pthread_join(consumidorid2, NULL);				// de ambas hebras
   exit(0);
}

 
Ejecución

merlin1@merlins1:~/Escritorio/Practicas/7$ gcc pcsem2.c -o pcsem2 -l pthread
merlin1@merlins1:~/Escritorio/Practicas/7$ ./pcsem2
---- Productor 1000 produce 1001
---- Productor 2000 produce 2001
**** Consumidor 4000 consume 1001
---- Productor 3000 produce 3001
**** Consumidor 5000 consume 2001
---- Productor 1000 produce 1002
---- Productor 2000 produce 2002
---- Productor 1000 produce 1003
---- Productor 3000 produce 3002
**** Consumidor 4000 consume 3001
---- Productor 1000 produce 1004
**** Consumidor 5000 consume 1002
---- Productor 2000 produce 2003
**** Consumidor 4000 consume 2002
---- Productor 1000 produce 1005
**** Consumidor 5000 consume 1003
---- Productor 3000 produce 3003
**** Consumidor 4000 consume 3002
---- Productor 2000 produce 2004
**** Consumidor 5000 consume 1004
---- Productor 1000 produce 1006
**** Consumidor 4000 consume 2003
---- Productor 3000 produce 3004
**** Consumidor 5000 consume 1005
---- Productor 2000 produce 2005
**** Consumidor 4000 consume 3003
---- Productor 1000 produce 1007
**** Consumidor 4000 consume 2004
---- Productor 3000 produce 3005
**** Consumidor 5000 consume 1006
---- Productor 1000 produce 1008
**** Consumidor 4000 consume 3004
---- Productor 2000 produce 2006
**** Consumidor 5000 consume 2005
---- Productor 1000 produce 1009
**** Consumidor 4000 consume 1007
---- Productor 3000 produce 3006
**** Consumidor 5000 consume 3005
---- Productor 2000 produce 2007
**** Consumidor 4000 consume 1008
---- Productor 1000 produce 1010
**** Consumidor 5000 consume 2006
---- Productor 3000 produce 3007
**** Consumidor 5000 consume 1009
---- Productor 2000 produce 2008
^C
merlin1@merlins1:~/Escritorio/Practicas/7$

 
Funciona igual que el programa principal, excepto que existen tres productores y dos consumidores.

Como podemos ver, el programa nunca termina, porque los consumidores consumen 20 elementos (10 cada uno) y en cambio los productores producen 30 elementos (10 cada uno). Sin embargo la caja sólo tiene 5 huecos, por lo que la caja se acaba llenando y los productores se quedan esperando a que se saque algún elemento.

 

AdjuntoTamaño
pcsem2.c3.67 KB