! " # " # $% & ' '()*+ #* *' ++,-"./" [Ben90] Ben-Ari, M. Concurrent and Distributed Programming Prentice Hall, 1990. [Capítulos 3, 4, 5, 6 7 y 8 ] [Ray83] Raynal, M. Algorithms for Mutual Exclusion. MIT Press, 1986. [Pal03] Palma, J. et al. Programación Concurrente. [Capítulos 4, 5 y 6] [Tom03] Tomeu, A. Apuntes de Prog. Concurrente. [Tema 3]
Niveles de Exclusión Mutua-Sincronización LENGUAJE SISTEMA MONITORES, REGIONES CRÍTICAS SEMÁFOROS MEMORIA ESPERA OCUPADA
1 ) (! * #',# '' ( * (2 2! 3)( 1 '!''" #! #&' 4& 5 ( 2&6 '' 4* #&' '
! # 2 3' # 2 )6 ## % 71! 2 8' " #99((:4(: (#5-(,' 4% ) 57 *1#)&'
" # $ Turno: integer range 1..2 := 1; task body P2 is loop Resto_código_2; loop exit when Turno = 2; Sección_Crítica_2; Turno := 1; end P2; task body P1 is loop Resto_código_1; loop exit when Turno = 1; Sección_Crítica_1; Turno := 2; end P1;
l5 l6 l1 l3 l2 t1 TEOREMA: LA SOLUCIÓN DE TURNOS CONSERVA LA EM SOBRE LAS SECCIONES CRÍTICAS Y ESTÁ LIBRE DE INTERBLOQUEOS -Demostración: transformar a RdP pura, extraer sistemas de ecuaciones y resolver PA para E.M. e INTREBLOQUEO t3 l4 t2 t4
" # $ C1, C2: integer range 0..1 := 1; task body P1 is loop RC1 t1 L1 t2 SC1 Resto_código_1; loop exit when C2 = 1; C1 := 0; Sección_Crítica_1; C1 := 1; t3 end P1; task body P2 is loop RC2 t4 L2 t5 SC2 Resto_código_2; loop exit when C1 = 1; C2 := 0; Sección_Crítica_2; C2 := 1; t6 end P2;
c1=1 c2=1 RC1 RC2 t1 t4 L1 L2 t2 t5 SC1 SC2 t3 c1=0 c2=0 t6
% & +,"3"3",3;".";3"3" TEOREMA: LA RdP ANTERIOR NO CONSERVA LA EM SOBRE LAS SECCIONES CRÍTICAS -Demostración: transformar a RdP pura, extraer sistema de ecuacione y resolver PA para E.M <""=">""?"".";" 3"
'" # ( $ C1, C2: integer range 0..1 := 1; task body P1 is loop Resto_código_1; C1 := 0; loop exit when C2 = 1; Sección_Crítica_1; C1 := 1; end P1; RC1 T1 L1,t2 SC1 t3 task body P2 is loop Resto_código_2; C2 := 0; loop exit when C1 = 1; Sección_Crítica_2; C2 := 1; end P2; RC2 T4 L1,t5 SC2 t3
c1=0 c2=0 RC1 RC2 t1 t4 L1 L2 TEOREMA: AMBOS PROCESOS SE INTERBLOQUEAN EN SUS LAZOS DE ESPERA OCUPADA (L1 y L2) t2-demostración: transformar a RdP pura, extraer sistema t5 de ecuaciones y resolver PA para interbloqueo SC1 SC2 t3 c1=1 c2=1 t6
)" #* +* C1, C2: integer range 0..1 := 1; task body P1 is loop Resto_código_1; C1 := 0; loop exit when C2 =1; C1 := 1; C1 := 0; Sección_Crítica_1; C1 := 1; end P1; task body P2 is loop Resto_código_2; C2 := 0; loop exit when C1 = 1; C2 := 1; C2 := 0; Sección_Crítica_2; C2 := 1; end P2;
)" #* +* Respeta la exclusión mutua Presenta una forma de bloqueo débil (livelock) dada por una secuencia de entrelazado cuál es? Puede haber procesos hambrientos Ejercicio: Extraer RdP y verificar su análisis
%,--.,--/01234 Turno : Integer range 0..1 := 1; C1, C2: integer range 1..2 := 1; task body P1 is loop Resto_código_1; C1 := 0; loop exit when C2=1; if Turno=2 then C1:=1; loop exit when Turno:=1; C1 := 0; end if; Sección_Crítica_1; C1 := 1; Turno := 2; end P1; task body P2 is loop Resto_código_2; C2 := 0; loop exit when C1=1; if Turno=1 then C2:=1; loop exit then Turno=2; C2 := 0; end if; Sección_Crítica_2; C2 := 1; Turno := 1; end P2;
% %,-- Exclusión Mutua Libertad de Interbloqueos No hay procesos hambrientos Hay progreso en la ejecución Generalizable a n procesos [Dijkstra] Complejo y poco intuitivo
%. /01504 C1, C2: boolean := false; Turno : integer range 1..2; task body P1 is RC1 u1 u2, u3 u4, u5 SC1 u6 loop Resto_código_1; C1 := true; Turno := 2 ; while (C2 and Turno=2)do; Sección_Crítica_1; C1 := false; end P1; RC2 v1 task body P2 is loop Resto_código_2; C2 := true; Turno := 1; while (C1 and Turno=1)do; Sección_Crítica_2; C2 := false; end P2; v2, v3 v, v5 SC2 v6
C1:=false C2:=false RC1 RC2 u6 u1 C1:=true v1 C2:=true v6 u2 TEOREMA: CONSERVA LA E.M. Y ESTÁ LIBRE DE INTERBLOQUEOS. v2 u3 Turno:=1 -Demostración: transformar a RdP pura, extraer sistemas de ecuaciones y resolver PA en ambos casos v3 COROLARIO: NO HAY PROCESOS HAMBRIENTOS Y LA EJECUCIÓN PROGRESA SIEMPRE u5 v5 u4 v4 SC1 Turno:=2 SC2
% 6.6 /01224 var flag: array [0..1] of boolean; (*inicialmente FALSE*) turn: 0..1 := 0; INCORRECTO! repeat flag[0]:= true; while turn <> 0 do while flag[1] do end do; turn:= 0; enddo; 4 <seccion critica>; flag[0]:= false; until false; 3 repeat 1 flag[1]:= true; while turn <> 1 do 2 while flag[0] do end do; 5turn:= 1; enddo; 6<seccion critica>; flag[1]:= false; until false;
% 7 var c: array[0..n-1] of (pasivo, solicitando, en-cs); (*inicialmente 'pasivo'*) turn0: 0..n-1; (*valor 0 ó 1, inicialmente*) repeat c[i]:=solicitando; j:=turno //j es local a cada proceso while j<>i do if c[j]<>pasivo then j:=turno else j:= (j-1) mod n;endif; end; c[i]:=en-sc; k:=0; while (k<n) and (k=i or c[k]<> en-sc) do j:=j+1 enddo; until k>=n; turno:=i; <seccion critica>; turn:= (i-1) mod n; c[i]:=pasivo;
% 7 var flag: array[0..1] of boolean; (*inicialmente FALSE*) turn: array[0..1] of 0..1; (*valor 0 ó 1, inicialmente*) repeat flag[0]:= true; turn[0]:= turn[1] + 0 mod 2; while (flag[1] and turn[0]= turn[1] + 0 mod 2) do nothing end do; <seccion critica> flag[0]:= false; until false; repeat flag[1]:= true; turn[1]:= turn[0] + 1 mod 2; while (flag[0] and turn[1]= turn[0] + 1 mod 2) do nothing end do; <seccion critica> flag[1]:= false; until false;
% 8 N1, N2: Integer := 0; task body P1 is loop Resto_código_1; N1 := 1; N1 := N2+1; loop exit when N2=0 or N1<=N2; Sección_Crítica_1; N1 := 0; end P1; task body P2 is loop Resto_código_2; N2 := 1; N2 := N1+1; loop exit when N1=0 or N2<N1; Sección_Crítica_2; N2 := 0; end P2;
% 8+.8 9:4 Choosing: array (1..N) of integer (others=>0); Number: array (1..N) of integer (others=>0); task body Pi is I: constant integer :=..., task id loop Resto_código_I; choosing(i):=1; number (I)=1+max(number); choosing(i):=0; for J in 1..N loop if J<>I then loop exit when chossing(j)=0; loop exit when number(j)=0 or number(i)<number(j) or (number(i)=number(j) and i<j); end loop, end if; Sección_Crítica_I; number(i):=0; end Pi;
! "! 1! 4%
Swap cerradura : boolean := false; Swap (A,B) ";" Temp := B; B := A; A := Temp; Task body Pi is llave: boolean; //local RCi t1-4 L1-2 t2-5 SCi t3-6 loop Resto_Código_i; llave:=true; loop Swap(cerradura,llave); exit when llave=false; Sección_Crítica_i; cerradura:=false; end Pi;
cerradura:=false RC1 llave:=true llave:=true RC2 t1 t4 L1 t2 TEOREMA: t7 LA E.M. SE PRESERVA A NIVEL t8 DE SECCIONES CRITICAS. NO HAY INTERBLOQUEOS -Demostración: extraer sistemas de ecuaciones y resolver PA para E.M. e interbloqueo SC1 llave:=false llave:=false SC2 L2 t5 t3 t6
C: integer /*global*/ Test_and_Set (Li) ";" Li := C; C := 1; Task body Pi is Li: Integer range 0..1; //local loop Resto_Código_i; loop Test_and Set (Li); exit when Li := 0; Sección_Crítica_i; C := 0; end Pi;
(.,-/01234," #'!! 3 ) 2& *#* &* # &2 2 ) # 7
(#,(! 3&! 2! #!* 2 ) ' (1965)' Wait (S)@AB5C' ( ( ' Signal (S)4* '(BDC' Wait (S)=P(S) Signal (S)=V(S)
(#; Wait *Signal! & #! Signal #7( E4..F $ & # B@A & BA(C! 4 2 & = +
(#" Implementación Type semáforo=record of S: integer; L: lista_de_procesos; end;,!! &,(& BA* Wait 2 * G )( # 2,#7 #7 #'
(#" procedure inic(var sem:semaphore; s0:integer); sem.s:=s0; inicializar(sem.l); end; procedure wait(var sem:semaphore); if sem.s>0 then sem.s:=sem.s-1; else sem.l.insertar(proceso); bloquear (proceso); end; end; procedure signal(var sem:semaphore if not sem.l.vacia() then sem.l.eliminar (proceso); desbloquear (proceso); end; else sem.s:=sem.s+1; end;
(# SEMAFOROS CONJUNTO BLOQ. COLA BLOQUEADA ESPERA OCUPADA Wait(S):Inc. S si es mayor 0. Signal(s):Libera proc o dec. S Wait(S):Inc. S si es mayor 0. Signal(s):Libera proc o dec. S COLA FIFO Wait(S):Inc. S si es mayor 0. Signal(s):Libera proc o dec. S ESPERA OCUPADA
( C*H I S: semáforo := 1; Task body P1 is loop RC1 t1 SC1 t2 Resto_1; Wait (S); Sección_Crítica_1; Signal (S); end P1; Task body P2 is loop RC2 t3 SC2 t4 Resto_2; Wait (S); Sección_Crítica_2; Signal (S); end P2;
% <, 2 ', # 2 ( 1! + =
% <*=& S RC1 RC2 t1 t3 SC1 SC2 TEOREMA: LA E.M. SE PRESERVA A NIVEL DE SECCIONES t2 CRITICAS. NO HAY INTERBLOQUEOS t4 -Demostración: obtener matriz de incidencia, extraer sistemas de ecuaciones y resolver PA para E.M. e interbloqueo
( )C*H2H G C' S: semaphore := 0: Task Body P1 is Task Body P2 is RC1 t1 RC2, t2 loop Codigo Signal(S); Codigo end; loop Codigo Wait(S); Codigo end; RC3 t3 RC3, t4
% <*=& RC1 t1 RC3 RC2 S t3 t2 TEOREMA: P1 puede ciclar libremente, pero P2 debe esperar siempre la señal desde P1 RC4 -Demostración: obtener matriz de incidencia, extraer sistemas de ecuaciones y resolver PA para ambas situaciones t4
> ( 3 #2# 424 # I Barrera1 : semaphore := 0; Barrera2 : semaphore := 0; l1 t1,l2 t2 l3,t3 Task Body P1 is loop Signal(Barrera1); Wait(Barrera2); Código_Restante; end; l4 t4,l5 t5 l6,t6 Task Body P2 is loop Signal(Barrera2); Wait(Barrera1); Código_Restante; end;
Barrera1=1 Barrera2=1 t1 t4 t2 t5 t3 Barrera1=0 Barrera2=0 t6 TEOREMA: AMBOS PROCESOS SE SINCRONIZAN AL COMENZAR A EJECUTAR SUS CÓDIGOS RESTANTES -Demostración- Resolver PA correspondiente
)#+) &? 2 "?/!? "! ' & In_Ptr Out_Ptr
% " B: array (0..infinity) of integer; In_Ptr, Out_Ptr: integer:=0; Task body Productor is I:Integer; loop producir (I); B(In_Ptr):=I; In_Ptr:= In_Ptr+1; end Productor; Task body Consumidor is I:Integer; loop I:=B(Out_Ptr); Out_Ptr:= Out_Ptr+1; consumir (I); end Consumidor;
% % " J 7 J 7 = 2 *# ( 2 = + K!& ' ) & 2 *
% >((" ( B: array (0..infinity) of integer; In_Ptr, Out_Ptr: integer:=0; Elements: semaphore:=0; em: semaphore:=1; Task body Productor is I:Integer; loop producir (I); l1 t1 Wait(em); l2 B(In_Ptr):=I; In_Ptr:= In_Ptr+1; t2 Signal (em); Signal(Elements); end Productor; Task body Consumidor is I:Integer; loop Wait (Elements); Wait(em); I:=B(Out_Ptr); Out_Ptr:= Out_Ptr+1; Signal (em); consumir (I); end Consumidor; l5,t3 l6,t4 l7 t5
l1 em l5 t1 t2 l2 Elements t3 l6 t4 TEOREMA: El productor puede producir indiscriminadamente, pero el consumidor debe esperar a que haya al menos un dato en el buffer. l7 -Demostración: obtener matriz de incidencia, extraer sistemas de ecuaciones y resolver PA t5
% >((< B: array (0..N-1) of integer; In_Ptr, Out_Ptr: integer:=0; Elements: semaphore:=0; Spaces: semaphore:=n; em: semaphore:=1; Task body Productor is I:Integer; loop producir (I); Wait (Spaces); Wait(em); B(In_Ptr):=I; In_Ptr:=(In_Ptr+1)modN; Signal (em); Signal(Elements); end Productor; Task body Consumidor is I:Integer; loop Wait (Elements); Wait(em); I:=B(Out_Ptr); Out_Ptr:= (Out_Ptr+1)modN; Signal (em); Signal (Spaces); consumir (I); end Consumidor;
l1 em l5 t1 l2 Elements t3 t2 l6 N TEOREMA: El productor puede producir hasta llenar el buffer, el consumidor debe Spaces esperar a que haya al menos un dato en el buffer, y puede consumir mientras haya objetos en el mismo. l7 t4 -Demostración: obtener matriz de incidencia, extraer sistemas de ecuaciones y resolver PA t5
( ) C dispone de la biblioteca sem.h en el marco de las facilidades IPC. Define conjuntos de semáforos Semántica muy diferente a la estándar de Djikstra Son más potentes Funciones semget, semctl y semop
/*Antonio J. Tomeu-Dpto. LSI-Area CC. e I.A.*/ /*Ejemplo de Wait sobre un semaforo IPC */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <string.h> #define PERMISOS S_IRUSR S_IWUSR S_IRGRP S_IWGRP S_IROTH S_IWOTH #define TAM 3 #define CLAVE (key_t) 666 void ajustar(struct sembuf *s, int valor, int operacion, int flags); int main (void) { int semid; struct sembuf mioper[tam-1];
semid = semget(clave, TAM, IPC_CREAT PERMISOS); /*Creacion*/ if(semid==-1) printf("error"); semctl (semid, 0, SETVAL, 1); ajustar(&(mioper[0]), 0, -1, 0); semop(semid, mioper,1); /*Wait=>Decremento del semaforo*/ semop(semid, mioper,1); /*Wait=>Bloqueo del proceso*/ /*Eliminacion del conjunto de semaforos*/ semctl(semid, NULL, IPC_RMID);} void ajustar (struct sembuf *s, int valor, int operacion, int flags) { s->sem_num = (short) valor; s->sem_op = operacion; s->sem_flg = flags; return; }
( @* L!&! L!! '' 1E1F L! ) 1 #6''
( @* public class semaforo { private byte S; public void _inicial (byte valor) {S = valor; return;} synchronized public void Wait() { while (S == 0) try{ wait(); } catch (Exception e) {} S--; } } synchronized public void Signal() { S++; notifyall(); }
" * ( +1! ' + ' & # ' 1#2 44!&
& )=.6A> +6 /019B4 3#* 11 &#) &! 2 & "#E! F #EF? 3# *4*'
& )=# var V: shared T;...... region V do S; /*acceso en e.m. a V*/
& )=#,! # 32# #& ( 4 # 3 #* 32# # ( # 2!
& )=#" * 2 P: region x do region y do S1: Q: region y do region x do S2;!) 1#
& )=) # var V: shared T;...... region V when B do S; /*acceso en e.m. a V*/
& )=) # # 2 # ( 2 1 ##2 +,! + # +! M N ( #* ',2! 7+M N
& )=) #"
+) & )= var buffer: shared record B: array [0..n-1] of integer; In_Ptr, Out_Ptr, cont: integer; Productor region buffer when cont<n do producir(i); B[In_Ptr]:=I; In_Ptr:=In_Ptr+1 mod n; cont:=cont+1; end; Consumidor region buffer when cont>0 do end; I:=B[Out_Ptr]; Out_Ptr:=Out_Ptr+1 mod n; cont:=cont-1; consumir(i);
.6/019:4 3 & #1#2 #''1 2 #' * " ' ) G * 2 & &!
#" ;(! * C H
# type nombre-monitor=monitor declaraciones de variables procedure entry P1(...)... end;... procedure entry PN(...)... end; código de inicialización end;
#,! EG F! ) 32! ' ( '' * G )& ) G * 2G ) G *# 2G )#
#C) DEF ) 2 nombre_variable: condition; wait(variable_condición): 2 4..! 2 ' send(variable_condición):! non_empty(variable_condición):! &!' &c.wait, c.send! c.
#, E " < & G & G *# G * G G ( '4*2#' G )' G ' G )' G ' 7 O 3 G * G # G )' G *! G )' G *! #( '
+) monitor prod_con is B: array(0..n-1) of Integer; In_Ptr, Out_Ptr: Integer:=0; Count: Integer:=0; Not_Full, Not_Empty: Condition; Procedure Añadir(I:in Integer) is if Count=N then wait(not_full); end if; B(In_Ptr):=I; In_Ptr:=(In_Ptr+1) mod N; Send(Not_Empty); end; Procedure Coger(I:out Integer) is if Count=0 then wait(not_empty); end if; I:=B(Out_Ptr); Out_Ptr:=(Out_Ptr+1) mod N; Send(Not_Full); end; end prod_con;
( Wait Wait (S) Signal Signal (S) S 2 OEF # EF? J= 2 BA
( monitor Emula_Semaforo is S: Integer := S0; Not_Zero: Condition; procedure Emula_Wait is if S0=0 then Wait(Not_Zero); end if; S := S-1; end Emula_Wait; Procedure Emula_Signal is Begin S := S+1; Send(Not_Zero) end Emula_Signal; end monitor;
( & 1*,'' #&! C & Csemáforo* CCount 2 & ) 2
( B### ' & S Send(C) 2! if CCount > 0 then Signal(CSemáforo); end if; wait(c) 2! CCount := CCount+1; Signal(S); Wait(CSemáforo); Wait(S); CCount := CCount-1;
) No existen como tales Emulación mediante semáforos IPC Fases: Diseñar una solución con monitores Utilizar señalización SX Transformar a su equivalente con semáforos (Djikstra) Implementar con semáforos IPC
@* Todo objeto es un monitor potencial Clase Object: métodos wait, notify, notifyall Clases con métodos synchronized No soporta variables de condición Hay que simular la sincronización con los métodos de la clase Object. Equivalen a una única variable de condición.
@*# class Monitor { public Monitor(){ } //constructor public synchronized tipo1 metodo1() throws InterruptedException{ notifyall(); //señal explícita no desplazante while(!condicion1) wait(); //espera sobre v. de condición } public synchronized tipo2 metodo2() throws InterruptedException{ notifyall(); while(!condicion1) wait(); } }
# # ( 2 7 *! 24! *4 -+(! 4 2 * 2 & *
Monitor Lector_Escritor is Lector: integer:=0; Writing: boolean:=true; OK_to_Read, OK_to_Write: Condition; procedure Start_Read is if Writing or Awaited(OK_to_Write) then Wait(OK_to_Read); end if; Lector:= Lector+1; Send (OK_to_Read); end Start_Read; procedure End_Read is Lector:= Lector-1; if Lector=0 then Send(OK_to_Write); end if; end End_Read;
procedure Start_Write is if Lector<>0 or Writing then Wait(OK_to_Write); end if; Writing:=True; end Start_Write; procedure End_Write Writing:=False; if Awaited(OK_to_Read) then Send (OK_to_Read); else Send (OK_to_Write); end if; end End_Write; end Lector_Escritor Monitor;
Task Body Lector is loop Start_Read; Leer_Datos; End_Read; end Lector; Task Body Escritor is loop Start_Write; Escribir_Datos; End_Write; end Escritor;
#<( &!! Comer * Pensar #( 72 G 2 * 3 # 4* 2 4* 4*
(#% Tenedores: array(0..4) of Semaphore := (others=>1); Task body Filosofo is loop Pensar; Wait(Tenedores(i)); Wait(Tenedores(i+1) mod 5); Comer; Signal(Tenedores(i)); Signal(Tenedores(i+1) mod 5); end Filosofo;
T[0] T[1] T[2] T[3] T[4] a T[1] a T[2] a T[3] a T[4] a T[0]
(# % Mesa: Semaphore := 4; Tenedores: array(0..4) of Semaphore := (others=>1); Task body Filosofo is loop Pensar; Wait(Mesa); Wait(Tenedores(i)); Wait(Tenedores(i+1) mod 5); Comer; Signal(Tenedores(i)); Signal(Tenedores(i+1) mod 5); Signal(Mesa); end Filosofo;
# Monitor MTenedores Tenedores: array(0..4)of Integer range 0..2 (others)=>2; Listo: array (0..4) of Condition; Procedure Coger_Tenedor(I: Integer) is if Tenedores(I)<>2 then wait(listo(i)); end if; Tenedores((I+1) mod 5) := Tenedores((I+1) mod 5)-1; Tenedores((I-1) mod 5) := Tenedores((I-1) mod 5)-1; end Coger_Tenedor;
Procedure Dejar_Tenedor(I: Integer) is Tenedores((I+1) mod 5) := Tenedores((I+1) mod 5)+1; Tenedores((I-1) mod 5) := Tenedores((I-1) mod 5)+1; if Tenedores(I+1)=2 then send (Listo(I+1)); end if; if Tenedores(I-1)=2 then send (Listo(I-1)); end if; end Dejar_Tenedor; end MTenedores; Task body Filosofo is /*cinco entidades como esta*/ loop Pensar; Coger_Tenedor(I); Comer; Dejar_Tenedor(I); end Filosofo;
# Monitor MTenedores Estado: array(0..4)of (pensar, hambriento, comer); Listo: array (0..4) of Condition; Procedure Coger_Tenedor(I: Integer) is Begin Estado[I]:=hambriento; test(i); if Estado[i]<>comer then wait(listo[i]); end Coger_Tenedor; Procedure Dejar_Tenedor(I: Integer) is Estado[i]:=pensar; test(i-1 mod 5); test(i+1 mod 5); end Dejar_Tenedor;
Procedure test(k: Integer) is Begin if Estado[k-1 mod 5]<>comer and Estado[k]=hambriento and Estado[k+1 mod 5]<>comer then Estado[k]:=comer; send(listo[k]); end Coger_Tenedor; //codigo de inicialización For i:=1 to 5 Estado[i]:=pensar; end MTenedores;
,# 6( ( # ' #& 2 ) " )! 0" *)
,#) '' 3 7 2! * 1 */( // ( 0" *)
,#) task Body Pi is loop Resto_Código_i; send(coordinador, solicitud); receive(coordinador, permiso); Sección_Crítica_i; send(coordinador, terminación); end Pi; 0" *)
,#) A C H A C H ") "), " A C H H.'' ")
,#'- +& # A9 9!99DC 9 " # " #2! P69Q P Q 0" *)
,#'- +& 0" *)
,#%,-G El proceso que desea ejecutar su sección crítica debe ganar una votación entre todos los demás Conjunto de procesos ={P1, P2,,Pn} distribuidos en N nodos comunicados entre sí Se preserva el orden de los mensajes, y el retardo de los mismo es finito. Todos los nodos están comunicados entre sí Para cada proceso Pi existe un conjunto de procesos Si contenido en. Es su distrito de votantes Pi siempre pertenece a Si Todos los distritos tienen igual número de votantes. Para cada i,j se satisface que Si Sjconjunto vacío 0" *)
,#% -G i 1!! Si Bloqueado hasta recibir el voto de todos los procesos de Si Cuando un proceso de Si recibe una solicitud de voto contesta SÍ si aún no ha votado. Si ya ha votado (a otro proceso), retiene la respuesta El proceso Pi que ha ejecutado su sc informa a todos los procesos de Si que ya pueden votar a otros candidatos Exclusión mutua garantizada Pueden aparecer interbloqueos, pero se pueden prevenir 0" *)
,#% -G boolean voto_dado:= false; Task body Pi is Begin loop Resto_Código_i for(pj in Si) send(pj, solicitud); for(pj in Si) receive(pj, voto); Sección_Crítica_i; for(pj in Si) send(pj, finalizada); end; End; 0" *)
Task body Receptor_Solicitudes_i is Begin loop receive(pj, solicitud); if(voto_dado) encolar(pj); else voto_dado:=true; send(pj, voto); end; end; End; 0" *)
Task body Emisor_Permisos is Begin loop if(cola_vacía) voto_dado:=false; else Pj:=desencolar(); send(pj, voto); end; end; End; 0" *)
,#%,&+% G " #*"#% "! 3 ) #,! &2 7* & " * &'' &''*!(: &*!!1: ) 0" *)
,#% 1 3! 1& () 7 2! (!1, *& & 1 ( 21
,#" 1 EF '' 2 2 Task body Main_Process is loop Resto_De_Código; Choose_Sequence_Number;(*se pone a la cola*) Send_Request_to_Nodes; (*pide permiso a los demás*) Wait_for_reply; (*espera respuesta de todos*) Sección_Crítica; Reply_to_Deferred_Nodes;(*da permiso a otros*) end Main_Process; 0" *)
2 &(( (# Task body Request_Process is (*acepta solicitudes de otros*) loop accept Message; if Decide_to_Defer then Defer_reply; else Send_reply; end if; end Request_Process; 0" *)
2E*F ( 1'' ( # Task body Reply_Process is (*acepta respuesta de otros*) loop accept Message; Increment_Reply_count; if Last_Reply then Wake_Main_Process; end if; end Reply_Process; 0" *)
Los 3 procesos comparten las siguiente variables globales a nivel de nodo, las cuales informan sobre su estado. Number:Contiene el número de secuencia escogido por el nodo. High_Number:Mayor número de los recibidos. Para saltar la comparación si el nodo no desea competir por s.c. Requesting:flag indicador de si el nodo pide s.c. Reply_Count:Total de mensajes Reply recibidos. S:Semáforo para acceso en e.m. a variables globales. Wake_Up:Semáforo para suspender al proceso principal hasta que puede ejecutar su sección crítica. Deferred:Estructura de datos para indicar qué nodos tienen su respuesta diferida 0" *)
Number:Integer:=0; High_Number:Integer:=0; Requesting:Boolean:=False; Reply_Count:Integer:=0; S:Semaphore:=1; Wake_Up:Semaphore:=0; Deferred:array (1..N)of Boolean:=False; task type Main_Process is; task type Request_Process is entry Message (Num,ID:in Integer); end Request_Process; task type Reply_Process is entry Message; end Reply_Process; Main_Process: array (1..N) of Main_Process; Request_Process: array (1..N) of Request_Process; Reply_Process: array (1..N) of Reply_Process; 0" *)
, Procedure Choose_Number is; Wait(S); Requesting:=True; Number:=High_Number+1; Signal(S); end Choose_Number; Procedure Send_Request is; Reply_Count:=0; for J in 1..N loop if J<>I then Request_Process(J).Message(Number,I); end if; end Send_Request; Procedure Wait_for_Reply is; Wait(Wake_Up); end Wait_for_Reply; Procedure Reply_for_Deferred_Nodes is; Wait(S); Requesting:=False; Signal(S); for J in 1..N loop if Deferred (J) then Deferred:=False: Reply_Process(J).Message; end if; end Reply_for_Deferred_Nodes; 0" *)
,Request_Process Task body Request_Process is Received_Number:Integer; Received_ID:Integer; Decide_to_Defer:Boolean; loop accept Message(Num,ID:in Integer) do Received_Num:=Num; Received_ID:=ID; end Message; High_Number:=Max(High_Number, Received_Num); Wait(S); Decide_to_Defer:=Requesting and (Number<Received_Num or (Number=Received_Num) and I<Received_ID); if Decide_to_Defer then Deferred(Received_ID):=True; end if; Signal(S); end Request_Process; 0" *)
,Reply_Process "* # 3!)( '' Task body Reply_Process is loop accept Message; Reply_Count:=Reply_Count+1; if Reply_Count=N-1 then Signal (Wake_Up); end if; end Reply_Process; 0" *)
,#) Algoritmo Mensajes por E/S Retardo en entrada Problemas Centralizado 3 2 Caída del coordinador Token-Ring 1 a 0 a n-1 Pérdida token Distribuido Puro 2(n-1) 2(n-1) Caída de proceso 0" *)
Terminación Distribuida: Definición 4 1 7 4* ) ( 4*( &4* & 2 4*7(! 4*I # " )* 0",#1L!* #
Terminación Distribuida: Generalidades Soporte de los algoritmos La terminación se produce cuando? Características algoritmos de terminación entidades distribuidas estruturadas en grafo canales de comunicación inter-nodo dirigidos canales libres de error mensajes llegan a destino en orden de envío puede haber ciclos y bidireccionalidad existe un nodo fuente sin ejes de entrada
Terminación Distribuida: Ejemplo de Grafo C H S R C ( ' 1 0",#1L!* #