guia de ejercicios de semaforos binarios

13
UNIX Semáforos POSIX. Utilizaremos dos tipos de semáforos POSIX: los semáforos binarios y los semáforos generales. Semáforos POSIX binarios. Los semáforos binarios sólo pueden estar en uno de dos estados posibles. Se declaran como variables de tipo pthread_mutex_t y las funciones que los manejan son: pthread_mutex_loc k() Operación P pthread_mutex_des troy() Libera el semáforo pthread_mutex_unl ock() Operación V pthread_mutex_ini t() Inicializació n Si son declarados como variables externas, se pueden inicializar de forma estática sin necesidad de invocar a pthread_mutex_init(). Por ejemplo: // // Semaforo binario pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; Como las funciones lock() y unlock() modifican el semáforo recibirán como argumento de entrada su dirección; por ejemplo:

Upload: johanna-benitez

Post on 30-Nov-2015

86 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Guia de Ejercicios de Semaforos Binarios

UNIX

Semáforos POSIX.Utilizaremos dos tipos de semáforos POSIX: los semáforos binarios y los semáforos generales.

Semáforos POSIX binarios.

Los semáforos binarios sólo pueden estar en uno de dos estados posibles. Se declaran como variables de tipo pthread_mutex_t y las funciones que los manejan son:  

pthread_mutex_lock() Operación P

pthread_mutex_destroy() Libera el semáforo

pthread_mutex_unlock() Operación V

pthread_mutex_init() Inicialización

Si son declarados como variables externas, se pueden inicializar de forma estática sin necesidad de invocar a pthread_mutex_init(). Por ejemplo:  

// // Semaforo binario pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;

Como las funciones lock() y unlock() modifican el semáforo recibirán como argumento de entrada su dirección; por ejemplo:  

  pthread_mutex_lock(&buffer_lock);   *itemp = buffer[bufout];   bufout = (bufout + 1) % TAMBUF;   pthread_mutex_unlock(&buffer_lock);

La función pthread_mutex_destroy() libera la memoria asociada a dicho semáforo. Normalmente no existe tal estructura de memoria y en la mayor parte de los sistemas esta primitiva no hace nada. Puede obviarse.

Page 2: Guia de Ejercicios de Semaforos Binarios

Semáforos POSIX genéricos.

Se trata de semáforos diseñados para sincronizar hilos. El estándar tiene en cuenta la posibilidad de su utilización para la sincronización de procesos (además de hilos) pero esta posibilidad no está soportada en todas las implementaciones y por ello, en esta asignatura, sólo serán utilizados entre hilos de un mismo proceso.

Se declaran como variables de tipo sem_t. Se manejan con las siguientes funciones:  

int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_wait(sem_t * sem); int sem_post(sem_t * sem); int sem_destroy(sem_t * sem);

La función de inicialización recibe como segundo argumento un valor indicativo de si el semáforo sincronizará hilos del mismo o diferente proceso. Por defecto se pone un valor 0 a dicho valor ya que sólo serán usados dentro del mismo proceso. Análogamente al semáforo binario, la función sem_destroy() puede obviarse.

Veamos cómo se implementa un sistema productor-consumidor con búfer circular utilizando hilos, semáforos POSIX binarios y semáforos POSIX genéricos:

Ejercicio completo

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <semaphore.h>

#include <pthread.h>

#define TAMBUF 8 // Tamaño del búfer circular

#define NUMDATOS 100 // Número de datos a enviar

//

// El buffer circular y los correspondientes punteros

int buffer[TAMBUF];

int bufin = 0;

Page 3: Guia de Ejercicios de Semaforos Binarios

int bufout = 0;

//

// Semaforo binario

pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;

//

// Variable suma

unsigned long sum = 0;

//

// Semaforos generales

sem_t hay_datos;

sem_t hay_sitio;

//

// Funciones de escritura y lectura del buffer circular

void obten_dato(int *itemp)

{

pthread_mutex_lock(&buffer_lock);

*itemp = buffer[bufout];

bufout = (bufout + 1) % TAMBUF;

pthread_mutex_unlock(&buffer_lock);

return;

}

void pon_dato(int item)

{

pthread_mutex_lock(&buffer_lock);

buffer[bufin] = item;

Page 4: Guia de Ejercicios de Semaforos Binarios

bufin = (bufin + 1) % TAMBUF;

pthread_mutex_unlock(&buffer_lock);

return;

}

//

// Funciones productor-consumidor

void *productor(void *arg1)

{

int i;

for (i = 1; i <= NUMDATOS; i++) {

sem_wait(&hay_sitio);

pon_dato(i*i);

sem_post(&hay_datos);

}

pthread_exit( NULL );

}

void *consumidor(void *arg2)

{

int i, midato;

for (i = 1; i<= NUMDATOS; i++) {

sem_wait(&hay_datos);

obten_dato(&midato);

sem_post(&hay_sitio);

sum += midato;

}

Page 5: Guia de Ejercicios de Semaforos Binarios

pthread_exit( NULL );

}

//

// Funcion principal

main()

{

pthread_t tidprod, tidcons;

unsigned long i, total;

total = 0;

for (i = 1; i <= NUMDATOS; i++)

total += i*i;

printf("El resultado deberia ser %u\n", total);

//

// Inicializacion de semaforos

sem_init(&hay_datos, 0, 0);

sem_init(&hay_sitio, 0, TAMBUF);

//

// Se crean los hilos

pthread_create(&tidprod, NULL, productor, NULL);

pthread_create(&tidcons, NULL, consumidor, NULL);

//

// Se espera a que los hilos terminen

pthread_join(tidprod, NULL);

pthread_join(tidcons, NULL);

printf("Los hilos produjeron el valor %u\n", sum);

Page 6: Guia de Ejercicios de Semaforos Binarios

}

EJERCICIO #2

Para todo programa en C para UNIX se hace uso de operaciones con semáforos debe incluirse los siguientes ficheros de cabecera:  

#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>

La creación e inicialización de un semáforo se puede llevar a cabo con la siguiente función:  

inicia (valor) int valor; { int semval; int id; union semun {   int val;   struct semid_ds *buf;   ushort *array; } arg;

  if ((id=semget(IPC_PRIVATE, 1, (IPC_CREAT|0666))) == -1) {     perror("Error al crear el semáforo.");     return(-1);   }

  arg.val = valor;   if (semctl(id, 0, SETVAL, arg) == -1) {     perror("Error al inicializar el semáforo.");     return (-1); /*error en inicializacion*/   }

  return(id); }

Las operaciones elementales sobre semáforos (esperar y señalar) se pueden implantar con el siguiente código:  

/*Rutina P */

P (semaforo) int semaforo;

Page 7: Guia de Ejercicios de Semaforos Binarios

{   if ( semcall(semaforo, -1) == -1 )     perror("Error en operación P."); }  

/*Rutina V */

V (semaforo) int semaforo; {   if ( semcall(semaforo, 1) == -1 )     perror("Error en operación V."); }  

semcall (semaforo, operacion) int semaforo, operacion; {   struct sembuf sb;   sb.sem_num = 0;   sb.sem_op = operacion;   sb.sem_flg = 0;

  return ( semop(semaforo, &sb, 1) ); /*devuelve -1 si error */ }

Todo recurso de un sistema informático que ya no se va a necesitar ha de ser liberado. Si se trata de semáforos UNIX una posibilidad para hacer esto es:  

borra_s (semaforo) int semaforo; {

  if ( semctl(semaforo, 0, IPC_RMID, 0) == -1) {     perror("Error al eliminar el semáforo.");     return(-1);   }

}

Page 8: Guia de Ejercicios de Semaforos Binarios

Ejercicio completo

#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/time.h> #include <unistd.h> #include <errno.h>

#define ESPERA 1000 // Son los microsegundos de espera usados para asegurar                     // la finalización del quantum.

/**********************************************************************  *  * PROBAR EL SISTEMA CON Y SIN LAS OPERACIONES P Y V   * **********************************************************************/

main() { int pid;  /* identifica el proceso hijo */ int mutex;  /* semaforo binario */

mutex=inicia(1);

if (0==(pid=fork()))   proceso_hijo(mutex); else  proceso_padre(mutex);

borra_s(mutex); }

/**********************************************************************  *  * Tanto el proceso hijo como el padre escriben 30 secuencias de 80 caracteres

 * **********************************************************************/

proceso_hijo(critica) int critica; { /* escribe 30 ristras de 80 caracteres '+' */ int i,j;

for (i=0;i< 30; i++) { P(critica);

Page 9: Guia de Ejercicios de Semaforos Binarios

  for (j=0; j<80; j++) {     printf("+");     fflush(stdout);     // Provocamos la finalización del quantum de tiempo     retardo ();   }     printf("\n"); V(critica);  }

exit(); }  

proceso_padre(critica) int critica; { /* escribe 30 ristras de 80 caracteres '-' */ int i,j;

for (i=0;i< 30; i++) { P(critica);    for (j=0; j<80; j++) {     printf("-");     fflush (stdout);     // Provocamos la finalización del quantum de tiempo     retardo ();   } printf("\n"); V(critica); }  wait(0); /* espera a que finalice el hijo */ }

/**********************************************************************  *  * Provocamos la espera durante ESPERA microsegundos  * **********************************************************************/ retardo() {

struct timeval tiempo; struct timezone tz; unsigned long inicio, ahora;

gettimeofday(&tiempo, &tz); ahora = inicio = tiempo.tv_sec * 1000000 + tiempo.tv_usec;

//  ESPERA microsegs while (ahora < inicio + ESPERA) {   gettimeofday(&tiempo, &tz);

Page 10: Guia de Ejercicios de Semaforos Binarios

  ahora = tiempo.tv_sec * 1000000 + tiempo.tv_usec; }

}

/***********************************************************************   *   * Rutinas de manejo de semáforos   * ***********************************************************************/

inicia(valor) int valor; { int semval; int id; union semun {   int val;   struct semid_ds *buf;   ushort *array; } arg;

  if ((id=semget(IPC_PRIVATE, 1, (IPC_CREAT|0666))) == -1) {     perror("Error al crear el semáforo.");     return(-1);   }

  arg.val = valor;   if (semctl(id, 0, SETVAL, arg) == -1) {     perror("Error al inicializar el semáforo.");     return (-1); /*error en inicializacion*/   }   return(id); }

/*Rutina P */

P(semaforo) int semaforo; {   if ( semcall(semaforo, -1) == -1 )      perror("Error en operación P."); }

/*Rutina V */

V(semaforo) int semaforo; {   if ( semcall(semaforo, 1) == -1 )      perror("Error en operación V."); }

Page 11: Guia de Ejercicios de Semaforos Binarios

semcall(semaforo, operacion) int semaforo, operacion; {   struct sembuf sb;   sb.sem_num = 0;   sb.sem_op = operacion;   sb.sem_flg = 0;

  return ( semop(semaforo, &sb, 1) ); /*devuelve -1 si error */ }

borra_s(semaforo) int semaforo; {

  if ( semctl(semaforo, 0, IPC_RMID, 0) == -1) {     perror("Error al eliminar el semáforo.");     return(-1);   }

}