You are on page 1of 11

http://sopes1usac.wordpress.

com/2012/11/05/5-2-problemas-clasicossemaforos/

5.2 Problemas clsicos. (Semaforos)


Posted on November 5, 2012 by capitangeek Lectores y escritores: Problema Hay un objeto de datos(fichero de texto) que es utilizado por varios procesos, unos leen y otro que escribe. Solo puede utilizar el recurso un proceso y solo uno, es decir, o bien un proceso estar escribiendo o bien leyendo, pero nunca ocurrir simultneamente (teniendo en cuenta que si no lo esta utilizando nadie, tendr preferencia el escritor ante el lector). Se considera a cada usuario(lector y escritor) como dos procesos y al fichero en cuestin como un recurso. De modo que, para que un proceso acceda al recurso que necesita, tenemos que considerar a cada usuario (lector y escritor) como dos semforos. Estos semforos son binarios y valen 0 si el recurso (fichero) est siendo utilizado por otro proceso y 1 si dicho recurso est disponible. La solucin de este problema se basa en implementar un algoritmo eficiente (vase algoritmo) en el manejo de semforos y memoria compartida que seguidamente describimos. A lo largo del programa se utilizan funciones necesarias para el manejo de memoria compartida (vase rshmem.h Y rshmem.c) manejo de semforos (vase semaph.c .) Para que el problema est bien resuelto se tiene que cumplir: - No se puede hacer esperar a ningn proceso lector si ningn proceso escritor accede al recurso. - Cuando un escritor debe realizar su tarea, debe ocurrir cuanto antes, sin que deban interferir los procesos lectores.(Para ello se establecen prioridades). Funcin Main Creacin de un proceso padre y de su proceso hijo (lectores, escritores). Descripcin

escribir( ); Esta funcin implementa el acceso a un recurso compartido, que ser la variable que contabiliza el total de veces que el usuario escribe. En esta funcin se han incluido varias llamadas al macro TP. Este macro implementa un retardo aleatorio con el fin de dar cierto tiempo a que ocurran interrupciones que puedan detener la ejecucin del proceso en su cuanto de tiempo asignado por el S.O.. En nuestro caso, es necesario realizar unas cuantas llamadas para dar tiempo a que todos los usuarios tengan oportunidad de escribir.

lectura( ); Permite que el lector pueda acceder al recurso. Una vez que acaba de leer se encarga de dejar el recurso para que sean de nuevo utilizado (por l o por otros). Para ello se basa en funciones de manejo de semforos y memoria compartida.

Utiliza las siguientes funciones: Manejo de semaforos: semWait ( ) semSignal ( ) semOpen ( ) semClose ( ) Manejo de memoria compartida: Cada vez que escribe un usuario lo refleja en el incremento de la variable de memoria compartida. Cuando los lectores y escritores han realizado la tarea que desean(leer y escribir) un nmero M de veces prefijado (3) se lo comunican al padre, no sin antes haber cerrado adecuadamente todos los semforos utilizados en esta funcin. Solucin #include rshmem.h #include <string.h> #include <stdio.h> int main(int argc, char *argv[]){ /*DECLARACION DE VARIABLES*/ int contador=0; FILE *fpl,*fpe; int i,n; char texto [250],c; int mutex_s; /*semforo 1*/ int mutex_w; /*semforo 2*/ key_t claveMutex_s; /*clave semforo 1*/ key_t claveMutex_w; /*clave semforo 2*/ /*CONTROL DEL PASO DE ARGUMENTOS*/ if(argc!=2){ fprintf(stderr,main:error en el paso de argumentos\n); exit(3); } /*obtener una clave cualquiera para el recurso ipc*/ if((key_t)-1==(claveMutex_s = ftok(lectores.c,s'))){ fprintf(stderr,main:Error al crear la clave con ftok\n); exit(1); }

if((key_t)-1==(claveMutex_w = ftok(lectores.c,s'))){ fprintf(stderr,main:Error al crear la clave con ftok\n); exit(1); } /*crear el semforo*/ if(-1==(mutex_s=semCreate(claveMutex_s,1))){ fprintf(stderr,main:No se puede crear el semforo 1\n); exit(1); } if(-1==(mutex_w=semCreate(claveMutex_w,1))){ fprintf(stderr,main:No se puede crear el semforo 2\n); exit(1); } /*crear zona de memoria compartida*/ if(!crearMemoria()) fprintf(stderr,Error al crear memoria compartida\n); if(0!=fork()){ /*PROCESO ESCRITOR*/ if((fpl=fopen(argv[1],r+))==NULL){ printf(Error en la apertura del fichero %s \n,argv[1]); exit(-1); semClose(mutex_w); } rewind(fpl); for(i=0;i<3;i++){ printf (Dime una frase que quieras escribir:); gets(texto); n=strlen(texto); semWait(mutex_w); fwrite(texto,(n*sizeof(char)),1,fpl); semSignal(mutex_w); semClose(mutex_w); exit(0); } fclose(fpl); } else{ /* PROCESO LECTOR*/ if((fpe=fopen(argv[1],w))==NULL){ fprintf(stderr,Error no se puede abrir el fichero %s \n,argv[1]); semClose(mutex_w); semClose(mutex_s);

exit(2); } for(i=0;i<3;i++) { semWait(mutex_s); contador ++; if(contador==1) semWait(mutex_w); while(!feof(fpe)){ semSignal(mutex_s); fread((char *)c,sizeof(char),1,fpe); semWait(mutex_s); printf(%c,c); } contador ; if(contador==0) semSignal(mutex_w); semSignal(mutex_s); semClose(mutex_s); semClose(mutex_w); /*CERRAMOS LOS FICHEROS*/ fclose(fpe); } /*eliminamos memoria compartida*/ if(!eliminarMemoria()){ fprintf(stderr,Error al eliminar la memoria compartida); exit(9); } } return (0); }

El barbero dormiln: Problema planteado por Dijkstra en 1971 Una peluquera en la que hay un barbero, una silla de peluquero y N sillas para que se sienten los clientes en espera, si es que los hay. Si no hay clientes presentes, el barbero se sienta en su silla de peluquero y se duerme. Cuando llega un cliente, ste debe despertar al barbero dormiln. Si llegan ms clientes mientras el barbero corta el cabello de un cliente, se sientan (si hay sillas desocupadas) o salen de la peluquera (si todas las sillas estn ocupadas). Programar al barbero y los clientes. Por lo que se ve, hay variables tipo bandera, que debe ser consultadas al iniciar un proceso, esto es clasico en los sitemas operativos multiprogramacin. El problema consiste en una barbera en la que trabaja un barbero que tiene un nico silln de barbero y varias sillas para esperar. Cuando no hay clientes, el barbero se sienta en una silla y se duerme. Cuando llega un nuevo cliente, ste o bien despierta al barbero o si el barbero est afeitando a otro cliente se sienta en una silla (o se va si todas las sillas estn ocupadas por clientes esperando). El problema consiste en realizar la actividad del barbero sin que ocurran condiciones de carrera. La solucin implica el uso de semforos y objetos de exclusin mutua para proteger la seccin critica . Un semforo es una variable protegida (o tipo abstracto de datos) que constituye el mtodo clsico para restringir o permitir el acceso a recursos compartidos (por ejemplo, un recurso de almacenamiento) en un entorno de multiprocesamiento.

Fuente(s):
#include <iostream.h> #include <conio.h> #include <stdio.h> void graficar(); char SB, op; /*SB =1 indica ocupada, 0 vacia */ int SC[6], i, j, cc, orden, t1; /* las sillas llevaran el turno */ void main(){ textmode(C80); textbackground(0); for(i=0; i<6; i=i+1)SC[i]=0; /*formateo lugares clientes*/ SB=1; cc=0; orden=0; do{ clrscr(); cout<<\n\n\n\tCODIGO DEL BARBERO DORMILON\n; cout<<\n\t I= Ingreso de un nuevo cliente\n;

cout<<\n\t T= Terminar la atencion a un cliente\n; cout<<\n\t F= Finalizar el programa\n; graficar(); op=getch(); if(op==i || op==I') { cc=0; if(SB==0)cout<<\n\tBARBERO TRABAJANDO; else cout<<\n\tBARBERO EN SU SILLA, DURMIENDO; if(SB==1){SB=0; cout<<\n\nSr Cliente, TIENE QUE DESPERTAR AL BARBERO; } else{ for(i=0; i<6; i=i+1){ if(SC[i]==0){cout<<\nSr Cliente, Pase Ud y ubiquese en la silla: <<i+1; orden=i; break;} }/*fin del for*/ /*Se verifica lugares ocupados*/ for(i=0; i<6; i=i+1)if(SC[i]!=0)cc=cc+1; if(cc<6)SC[orden]=cc+1; /*se le asigna el proximo turno*/ }/*del else por barbero dormido*/ cout<<\nSr Cliente: Vea que hay: <<cc<< clientes en espera; if(cc>5) cout<<\nEstimado Cliente, en este momento no hay lugar para Ud, vuelva mas tarde\no pruebe en otra barberia; getch(); }/*del if op ingreso del cliente */ if(op==t || op==T') { t1=7; /*se elige el turno mas bajo !=0 */ for(i=0; i<6; i=i+1) if(SC[i]<t1 && SC[i]!=0){t1 = SC[i];orden=i;} for(i=0; i<6; i=i+1) if(SC[i]==t1) cout<<\nEL Cliente ubicado en la silla: <<orden+1<< Sigue para atencion: ; /* actualiza los turnos */ for(i=0; i<6; i=i+1) if(SC[i]!=0) SC[i] = SC[i]-1; if(t1==7){ SB=1; cout<<\n\tNO HAY MAS CLIENTES; EL BARBERO SE VA A SU SILLA A DORMIR; } getch(); }/*del if op*/ }while (op!=f'&& op!=F'); }/*del main*/

void graficar() { /*Este codigo solo corre en turbo c++ de Borland*/ textbackground(11);textcolor(1); gotoxy(20,14);cprintf( GRAFICO DEL BARBERO DORMILON ); textbackground(2);textcolor(15); gotoxy(20,15);cprintf( ); gotoxy(20,16);cprintf( [ ] Silla Barbero); if(SB==1){gotoxy(24,16);cprintf( Zzzz..);} else {gotoxy(24,16);cprintf( ]WORKING!!!);} gotoxy(20,17);cprintf( ); gotoxy(20,18);cprintf(Sillas Clientes:[ ][ ][ ][ ][ ][ ]); gotoxy(20,19);cprintf( Turnos: ); gotoxy(20,20);cprintf( Ingrese Opcion: ); for(i=0; i<6; i=i+1){ if(SC[i]!=0){ textbackground(6); gotoxy(37+(i*3),18); cprintf( ); textbackground(2); gotoxy(37+(i*3),19); cprintf(%i, SC[i]); } else { gotoxy(28+(i*4),33); cprintf( ); } } textbackground(0); gotoxy(20,50); }

Filosofos Comensales Cinco Filsofos se sientan alrededor de una mesa y pasan su vida cenando y pensando. Cada filsofo tiene un plato de fideos y un tenedor a la izquierda de su plato. Para comer los fideos son necesarios dos tenedores y cada filsofo slo puede tomar los que estn a su izquierda y derecha. Si cualquier filsofo coge un tenedor y el otro est ocupado, se quedar esperando, con el tenedor en la mano, hasta que pueda coger el otro tenedor, para luego empezar a comer. Si dos filsofos adyacentes intentan tomar el mismo tenedor a una vez, se produce una condicin de carrera: ambos compiten por tomar el mismo tenedor, y uno de ellos se queda sin comer. Si todos los filsofos cogen el tenedor que est a su derecha al mismo tiempo, entonces todos se quedarn esperando eternamente, porque alguien debe liberar el tenedor que les falta. Nadie lo har porque todos se encuentran en la misma situacin (esperando que alguno deje sus tenedores). Entonces los filsofos se morirn de hambre. Este bloqueo mutuo se denomina interbloqueo o deadlock. El problema consiste en encontrar un algoritmo que permita que los filsofos nunca se mueran de hambre. Algunas Posibles Soluciones

Por turno cclico

Se empieza por un filsofo, que si quiere puede comer y despus pasa su turno al de la derecha. Cada filsofo slo puede comer en su turno. Problema: si el nmero de filsofos es muy alto, uno puede morir de hambre antes de su turno.

Varios turnos

Se establecen varios turnos. Para hacerlo ms claro supongamos que cada filsofo que puede comer (es su turno) tiene una ficha que despus pasa a la derecha. Si por ejemplo hay 7 comensales podemos poner 3 fichas en posiciones alternas (entre dos de las fichas quedaran dos filsofos). Se establecen turnos de tiempo fijo. Por ejemplo cada 5 minutos se pasan las fichas (y los turnos) a la derecha. En base al tiempo que suelen tardar los filsofos en comer y en volver a tener hambre, el tiempo de turno establecido puede hacer que sea peor solucin que la anterior. Si el tiempo de turno se aproxima al tiempo medio que tarda un filsofo en comer esta variante da muy buenos resultados. Si adems el tiempo medio de comer es similar al tiempo medio en volver a tener hambre la solucin se aproxima al ptimo.

Colas de tenedores

Cuando un filsofo quiere comer se pone en la cola de los dos tenedores que necesita. Cuando un tenedor est libre lo toma. Cuando toma los dos tenedores, come y deja libre los tenedores. Visto desde el otro lado, cada tenedor slo puede tener dos filsofos en cola, siempre los mismos. Esto crea el problema comentado de que si todos quieren comer a la vez y todos empiezan tomando el tenedor de su derecha se bloquea el sistema (deadlock).

Resolucin de conflictos en colas de tenedores

Cada vez que un filsofo tiene un tenedor espera un tiempo aleatorio para conseguir el segundo tenedor. Si en ese tiempo no queda libre el segundo tenedor, suelta el que tiene y vuelve a ponerse en cola para sus dos tenedores. Si un filsofo A suelta un tenedor (porque ha comido o porque ha esperado demasiado tiempo con el tenedor en la mano) pero todava desea comer, vuelve a ponerse en cola para ese tenedor. Si el filsofo adyacente B est ya en esa cola de tenedor (tiene hambre) lo toma y si no vuelve a cogerlo A. Es importante que el tiempo de espera sea aleatorio o se mantendr el bloqueo del sistema.

El portero del comedor

Se indica a los filsofos que abandonen la mesa cuando no tengan hambre y que no regresen a ella hasta que vuelvan a estar hambrientos (cada filsofo siempre se sienta en la misma silla). La misin del portero es controlar el nmero de filsofos en la sala, limitando su nmero a n-1, pues si hay n-1 comensales seguro que al menos uno puede comer con los dos tenedores. Solucin Por Semforos
/* Solucion a la cena de los filosofos mediante semaforos. */ #define TRUE1 #define N5 #define LEFT(x)(((x)-1)%N) #define RIGHT(X)(((X)+1)%N) typedef struct { int value; /* Lista de procesos. */ } semaphore; typedef enum { THINKING, HUNGRY, EATING } status; /* Estado de cada filosofo. */ status estado[N]; /* Semaforo para exclusion mutua. */ semaphore mutex, /* Semaforo para bloquear los filosofos adyacentes. s[N]; main () { extern status estado[N]; extern semaphore mutex, s[N]; int i, sw = 1; void Philosopher (int); /* Inicializamos los semaforos. */ InitSemaphore (mutex, 1); for (i = 0; i < N; i++) InitSemaphore (s[i], 0); /* Inicializamos los estados. */

*/

for (i = 0; i < N; i++) estado[i] = THINKING; /* Inicializamos los filosofos. */ for (i = 0; (i < N) && (sw); i++) if (!(sw = fork ())) Philosopher (i); } void Philosopher (int i) { void think (), eat (), TakeForks (int), PutForks (int); while (TRUE) { think (); /* Obtiene dos tenedores o se bloquea. */ TakeForks (i); eat (); PutForks (i); } } void TakeForks (int i) { void test (int); extern semaphore mutex, s[N]; extern status estado[N]; /* Acceso a seccion critica. */ wait (mutex); estado[i] = HUNGRY; /* Intenta tomar los dos tenedores. */ test (i); signal (mutex); /* Se bloquea si no consiguio los tenedores. */ wait (s[i]); } void PutForks (int i) { void test (int); extern semaphore mutex; extern status estado[N]; /* Acceso a seccion critica. */ wait (mutex); estado[i] = THINKING; /* Comprueba si el vecino izquierdo puede comer ahora. */ test (LEFT (i)); /* Comprueba si el vecino derecho puede comer ahora. */ test (RIGHT (i)); signal (mutex); } void test (int i) { extern semaphore s[N]; extern status estado[N]; if (estado[i] == HUNGRY && estado[LEFT (i)] != EATING && estado[RIGHT (i)] != EATING) { estado[i] = EATING; signal (s[i]); }

You might also like