El algoritmo de Dekker (alternancia estricta): es un algoritmo de programacin concurrente para
exclusin mutua, que permite a dos procesos o hilos de ejecucin compartir un recurso sin conflictos. Fue uno de los primeros algoritmos de exclusin mutua inventados, implementado por Edsger Dijkstra. Si ambos procesos intentan acceder a la seccin crtica simultneamente, el algoritmo elige un proceso segn una variable turno. Si el otro proceso est ejecutando en su seccin crtica, deber esperar su finalizacin. Existen cinco versiones del algoritmo Dekker, teniendo ciertos fallos los primeros cuatro. La versin 5 es la que trabaja ms eficientemente, siendo una combinacin de la 1 y la 4. Primer algoritmo Garantiza la exclusin mutua, pero su desventaja es que acopla los procesos fuertemente, esto significa que los procesos lentos atrasan a los procesos rpidos. Repeat Hace_Cosas(); While turno =2 Do; REGION_CRITICA(); turno = 2; Hace_mas_cosas(); Until Fin Repeat Hace_Cosas(); While turno = 1 Do; REGION_CRITICA(); turno = 1; Hace_mas_cosas(); Until Fin
Segundo algoritmo Problema interbloqueo. No existe la alternancia, aunque ambos procesos caen a un mismo estado y nunca salen de ah. PROGRAMA DOS; Variables P1QE, P2QE: Bool; Inicializacin P1QE = false; P2QE = false; Repeat Hace_Cosas(); P1QE = true; While P2QE Do; REGION_CRITICA(); P1QE = False; Hace_mas_cosas(); Until Fin repeat Hace_Cosas(); P2QE = true; While P1QE Do; REGION_CRITICA(); P2QE = False; Hace_mas_cosas(); Until Fin
Tercer algoritmo Colisin regin crtica no garantiza la exclusin mutua. Este algoritmo no evita que dos procesos puedan acceder al mismo tiempo a la regin crtica. PROGRAMA TRES; Variables P1A, P2A: Bool; Inicializacin P1A = false; P2A = false; Repeat Hace_Cosas(); While P2A Do; P1A = true; REGION_CRITICA(); P1A = False; Hace_mas_cosas(); Until Fin Repeat Hace_Cosas(); While P1A Do; P2A = true; REGION_CRITICA (); P2A = False; Hace_mas_cosas(); Until Fin Cuarto algoritmo Postergacin indefinida. Aunque los procesos no estn en interbloqueo, un proceso o varios se quedan esperando a que suceda un evento que tal vez nunca suceda. PROGRAMA CUATRO; Variables P1QE, P2QE: Bool; Inicializacin P1QE = false; P2QE = false; Repeat Hace_Cosas(); P1QE = true; While P2QE Do Begin P1QE = false; Delay (random()); P1QE = true; end; REGION_CRITICA(); P1QE = False; Hace_mas_cosas(); Until Fin Repeat Hace_Cosas (); P1QE = true; While P2QE Do Begin P2QE = false; Delay (random()); P2QE = true; end; REGION_CRITICA(); P2QE = False; Hace_mas_cosas(); Until Fin
Quinto Algoritmo
El quinto algoritmo de Dekker es la versin optimizada y que no presenta problemas como las cuatro versiones anteriores, para su estructuracin se hace una combinacin de dos algoritmos de acuerdo al orden de prioridad de desempeo y funcionamiento de las cuatro versiones conocidas.
PROGRAMA CINCO; Variables P1QE, P2QE: Bool; turno: Entero; Inicializacin P1QE = false; P2QE = false; turno = 1 Repeat Hace_Cosas(); P1QE = true; While P2QE Do Begin if(turno = 2) Begin P1QE = false; Delay (random()); P1QE = true; end; end; REGION_CRITICA(); turno = 2; P1QE = False; Hace_mas_cosas(); Until Fin Repeat Hace_Cosas(); P2QE = true; While P1QE Do Begin if(turno = 1) Begin P2QE = false; Delay (random()); P2QE = true; end; end; REGION_CRITICA(); turno = 1; P2QE = False; Hace_mas_cosas(); Until Fin
Ejemplo:
Planteamiento: Los n procesos llegan a la vez a la memoria (seccin crtica), o desean entrar en ella. El algoritmo de espera activa regula la entrada de los procesos. Los procesos comparten la variable 'recurso', y se bebe evitar que mientras un proceso est accediendo a la variable, otro proceso la est modificando al mismo tiempo. Mediante el algoritmo de DEKKER se consigue: Exclusin mutua con respecto al recurso Se concede a cada proceso el acceso en un tiempo finito Se libera el recurso en un tiempo finito Existe espera activa Para el programa hemos elegido que el nmero de procesos sea cuatro, aunque el nmero de ellos puede variar a conveniencia, modificndolo en el #define.
Solucin Para controlar el acceso al recurso disponemos de dos tipos de variable: o n variables de cerradura (expresan la iniciativa de cada proceso para entrar en su seccin crtica). Para el programa, dichas variables son: entrarSC[] Los valores que toman estas variables son: T: El proceso quiere acceder a su seccin crtica F: El proceso no quiere acceder a su seccin crtica Nota: Inicialmente todas las variables cerradura toman el valor F, es decir, ningun proceso desea acceder a su seccin crtica. o una variable turno (variable de alternancia que permite el acceso de un proceso a su seccin crtica). Inicialmente deja entrar al proceso primigenio (*turno=0).
Disponemos de las siguientes funciones para controlar la exclusin mutua: pHijoQuiere(): comprueba si algun proceso quiere acceder a su seccion critica: recorre "entrarSC[]" si alguna componente es "T", en cuyo caso devuelve "T", de otro modo "F". elSiguiente(): busca el proceso que tiene intencion de entrar en su SC, en la lista "entrarSC[]", a partir del proceso actual. Si no encuentra ninguno se toma el anterior.
Tambin tenemos una funcin que vara el contenido de la variable compartida recurso. Esta funcin es incrementa().
Programa:
#include <stdio.h> #include <sys/wait.h> #include "rshmem.h" /* constantes logicas */ #define F 0 #define T 1 /* Numero de procesos en total */ #define N 4 /* Numero de iteraciones para la tarea de cada proceso */ #define NITER 500
* definicion de funciones */ *void incrementa() *incrementa el valor del contenido del recurso compartido en tantas *unidades como se indique en la variable k. void incrementa(int *mem, int k){ int i; i=*mem; TP i=i+k; TP *mem=i; } * pHijoQuiere() * comprueba si algun proceso quiere acceder a su seccion critica: * recorre "intencion[]" (menos "proc") si alguna componente es "T", en cuyo * caso devuelve "T", de otro modo "F".
int pHijoQuiere (int intencion[], int proc, int NProc){ int i; for (i=1; i<NProc; i++) if (intencion[(proc+i)%NProc]==T ) return T; return F; /* ninguno tiene intencion de entrar */ }
* elSiguiente() * busca el proceso que tiene intencion de entrar en su SC, en la lista * "intencion[]", a partir del proceso "proc". Si no encuentra ninguno * se toma (proc+NProc-1)%NProc (el anterior mod NProc).
int elSiguiente (int intencion[], int proc, int NProc){ int j; for (j=1; j<NProc-1; j++) if (intencion[(proc+j)%NProc] == T) return (proc+j)%NProc ; return (proc+NProc-1)%NProc ; } int main(){ int i; /* variable auxiliar contador*/ int *recurso; /* recurso compartido*/ int idProc ; /* identificador de proceso para uno mismo */ int *entrarSC; /* entrarSC[idProc]=T : idProc quiere entrar en s.c. entrarSC[idProc]=F : idProc no quiere */ int *turno; /* turno de cada proceso (idProc) */ /*crea zona de memoria compartida*/ if (!crearMemoria()) { fprintf(stderr, "error de crearMemoria\n"); exit(-1) ; } /* asignacion de memoria a los punteros*/ recurso = (int *) memoria; memoria += sizeof(int); turno = (int *) memoria; memoria += sizeof(int); entrarSC = (int *) memoria; memoria += sizeof(int)*N; /* inicializacion de variables en memoria compartida */ *recurso = 0; /* ningun proceso quiere entrar en su seccion critica todavia */ for (i=0; i<N-1; i++) entrarSC[i]=F; *turno=0; /* el turno es del padre */ /* creacion de procesos */ idProc = 0; /* para el proceso primigenio */ while (idProc<N-1) { if (fork()) { /**** proceso padre */ /* tarea de cada proceso */ for (i=0; i<NITER; i++){ /********seccion entrada********/ if ( pHijoQuiere(entrarSC, idProc, N)== F ) *turno=idProc; entrarSC[idProc]=T; while(pHijoQuiere(entrarSC, idProc, N)){ if(*turno != idProc){ /* si no es su turno */ entrarSC[idProc]=F; while(*turno != idProc); /* mientras no sea su turno */ entrarSC[idProc]=T; } } /********fin seccion entrada******* */ incrementa(recurso,-10); /********seccion critica********/ /********seccion salida******* */ *turno = elSiguiente(entrarSC, idProc, N); entrarSC[idProc]=F; /* *******fin seccion salida********/ } /* fin for (tarea) */ (void) wait(NULL) ; printf("Elrecurso valia 0 y ahora vale %d\n", *recurso); if (idProc == 0) /* el proceso primigenio debe borrar la memoria */ if (!eliminarMemoria()) fprintf(stderr, "error de eliminarMemoria\n"); exit(0); } else { /**** proceso hijo */ idProc++; } }/*idProc=N-1*/ /*Tarea del proceso nieto de todos los procesos*/ for (i=0; i<NITER; i++){ /********seccion entrada******* */ entrarSC[idProc]=T; while(pHijoQuiere(entrarSC, idProc, N)){ if(*turno != idProc){ /* si no es su turno */ entrarSC[idProc]=F; while(*turno != idProc); /* mientras no sea su turno */ entrarSC[idProc]=T; } } /* *******fin seccion entrada********/ incrementa(recurso,-10); /********seccion critica********/ /********seccion salida******* */ *turno = elSiguiente(entrarSC, idProc, N); entrarSC[idProc]=F; /* *******fin seccion salida********/ } /* fin for (tarea) */ exit(0); }/*main*/