Escolar Documentos
Profissional Documentos
Cultura Documentos
Alberto Garcia-Robledo
Laboratorio de Tecnologas de Informacin, CINVESTAV-Tamaulipas, Carretera Nacional Cd. Victoria-Monterrey Km 6, Cd. Victoria Tamaulipas, Mxico, CP. 87276, Tel. (52 834) 316 6600 algarcia@tamps.cinvestav.mx
1.
Introduccin
El presente documento muestra la ejecucin de un sistema distribuido mnimo que ejemplifica el funcionamiento bsico del algoritmo de los filsofos comensales. Tanto los programas de los componentes del sistema como del algoritmo fueron tomados de [1]. El cdigo fuente puede ser descargado de [2], aunque se incluye distribuido junto con este documento.
procesamiento que tarda dos segundos durmiendo el hilo durante este tiempo. Finalmente, se libera el acceso a la seccin crtica a travs de la instancia del algoritmo seleccionado antes de iniciar otra iteracin. En resumen, el programa 1.1 instancia un algoritmo de exclusin mutua determinado, lanza un hilo que representa el proceso actual y entra a un bucle infinito. En cada iteracin el hilo solicita acceso a la seccin crtica utilizando la instancia del algoritmo elegido, se bloquea hasta obtener el acceso y simula un procesamiento que dura dos segundos antes de liberar la seccin crtica y empezar una nueva iteracin. Listing 1.1. LockTester.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
p u b l i c c l a s s Lock Tester { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) throws E xc e pti o n { Li n ke r comm = n u l l ; tr y { S t r i n g baseName = a r g s [ 0 ] ; i n t myId = I n t e g e r . p a r s e I n t ( a r g s [ 1 ] ) ; int numProc = I n t e g e r . p a r s e I n t ( a r g s [ 2 ] ) ; comm = new Li n ke r ( baseName , myId , numProc ) ; Lock l o c k = n u l l ; i f ( a r g s [ 3 ] . e q u a l s ( Lamport ) ) l o c k = new LamportMutex (comm) ; i f ( a r g s [ 3 ] . e q u a l s ( Ricart Agrawala ) ) l o c k = new RAMutex(comm) ; i f ( a r g s [ 3 ] . e q u a l s ( Di ni ng Phil ) ) l o c k = new DinMutex (comm) ; i f ( a r g s [ 3 ] . e q u a l s ( CircToken ) ) l o c k = new CircToken (comm, 0 ) ; f o r ( i n t i = 0 ; i < numProc ; i ++) i f ( i != myId ) ( new L i s te ne r Thre ad ( i , ( MsgHandler ) l o c k ) ) . start () ; while ( t r u e ) { System . out . p r i n t l n ( myId + i s not i n CS ) ; U t i l . mySleep ( 2000 ) ; l o c k . re q ue s t C S ( ) ; U t i l . mySleep ( 2000 ) ; System . out . p r i n t l n ( myId + i s i n CS ) ; lock . releaseCS () ; } } c atc h ( I n t e r r u p t e d E x c e p t i o n e ) { i f (comm != n u l l ) comm . c l o s e ( ) ; } catch ( Exception e ) { System . out . p r i n t l n ( e ) ; e . pri nt S tac k Trace ( ) ;
36 37 38
} }
11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27
28 29 30 31 32 33 34 35 36 37 38 39 40 41
import java . u t i l . ; import java . i o . ; p u b l i c c l a s s Linker { Print Writer [ ] dataOut ; Buf f ered Re ader [ ] data In ; Buf f ered Re ader dIn ; int myId , N; Connector c o nne c to r ; p u b l i c I n t L i n k e d L i s t n e i g h b o r s = new I n t L i n k e d L i s t ( ) ; p u b l i c Linker ( S t r i n g basename , int id , int numProc ) throws Exception { myId = i d ; N = numProc ; data In = new Buf f ered Reade r [ numProc ] ; dataOut = new Print Write r [ numProc ] ; Topology . read Ne i ghbo rs ( myId , N, n e i g h b o r s ) ; c o nne c to r = new Connector ( ) ; c o nne c to r . Connect ( basename , myId , numProc , data In , dataOut ) ; } p u b l i c void sendMsg ( int dest Id , S t r i n g tag , S t r i n g msg ) { dataOut [ d e s t I d ] . p r i n t l n ( myId + + d e s t I d + + tag + + msg + # ) ; dataOut [ d e s t I d ] . f l u s h ( ) ; } p u b l i c void sendMsg ( int dest Id , S t r i n g tag ) { sendMsg ( dest Id , tag , 0 ) ; } p u b l i c void m u l t i c a s t ( I n t L i n k e d L i s t d e s t I d s , S t r i n g tag , S t r i n g msg ) { for ( int i =0; i < d e s t I d s . s i z e ( ) ; i ++) { sendMsg ( d e s t I d s . get Entry ( i ) , tag , msg ) ; } } p u b l i c Msg re cei ve Msg ( int from Id ) throws IOException { S t r i n g g e t l i n e = data In [ from Id ] . read Line ( ) ; U t i l . p r i n t l n ( r e c e i v e d message + g e t l i n e ) ; S t r i n g T o k e n i z e r s t = new S t r i n g T o k e n i z e r ( g e t l i n e ) ; int s r c I d = I n t e g e r . p a r s e I n t ( s t . nextToken ( ) ) ; i n t d e s t I d = I n t e g e r . p a r s e I n t ( s t . nextToken ( ) ) ; S t r i n g tag = s t . nextToken ( ) ; S t r i n g msg = s t . nextToken ( # ) ; return new Msg( s r c I d , dest Id , tag , msg ) ; }
42 43 44 45
El programa 1.1 es ejecutado de manera concurrente tantas veces como nmero de proceso queremos que tenga nuestro sistema distribuido. Al ejecutar cada instancia del programa, se le es asignado un identificador numrico y cero-basado dentro del sistema distribuido. Para cada proceso existe un archivo que contiene los identificadores de ese proceso. El nombre del archivo sigue el formato topology#, en donde # es reemplazado por el identificador del proceso al cual el archivo pertenece. Gracias a estos archivos, es posible determinar la topologa que define la manera en la que los procesos se comunican unos con otros. Esto es particularmente til para nuestro ejemplo, en el que los filsofos se sientan en una mesa redonda, por lo cual los procesos deben estar organizados en un anillo, como se muestra en la figura 1.
Figura 1. Topologa del sistema distribuido que representa el a los filsofos comensales
El listado 1.4 muestra un script que muestra la manera en que se ejecutan cinco procesos de manera concurrente sincronizados entre s mediante el algo- ritmo de los filsofos comensales. Como puede observarse, el primer paso es la ejecucin en segundo plano de un programa NameServer, el cual se muestra en el listado 1.3. NameServer es un servidor de nombres sencillo, que permite a cada proceso saber sobre los dems. El servidor de nombres mantiene una tabla con los campos name, hostName, portNumber a travs de un objeto NameTable que proporciona un
mapeo entre el nombre de un proceso al host y puerto en el que se ejecuta. Las operaciones bsicas que proporciona son insert (agregar proceso a la tabla) y search (buscar proceso en la tabla). Detalles sobre la implementacin del servidor de nombres pueden ser encontrados en el captulo en [1]. Listing 1.3. NameServer.java
1 2 3 4 5 6 7 8 9 10 11 12
import java . net . ; import java . i o . ; import java . u t i l . ; p u b l i c c l a s s NameServer { NameTable t a b l e ; p u b l i c NameServer ( ) { t a b l e = new NameTable ( ) ; } void h a n d l e c l i e n t ( S oc ke t t h e C l i e n t ) { tr y { Buf f ered Reader din = new Buf f ered Reader ( new Input Stream Reader ( t h e C l i e n t . get Input Stre am ( ) ) ); Pri nt Wri te r pout = new Pri nt W ri te r ( t h e C l i e n t . getOutputStream ( ) ) ; S t r i n g g e t l i n e = din . read Line ( ) ; S t r i n g T o k e n i z e r s t = new S t r i n g T o k e n i z e r ( g e t l i n e ) ; S t r i n g tag = s t . nextToken ( ) ; i f ( tag . e q u a l s ( s e a r c h ) ) { int i nde x = t a b l e . s e a r c h ( s t . nextToken ( ) ) ; i f ( index == 1) // not found pout . p r i n t l n ( 1 + + n u l l h o s t ) ; else pout . p r i n t l n ( t a b l e . get Po rt ( inde x ) + + t a b l e . getHostName ( i nde x ) ) ; } else i f ( tag . e q u a l s ( i n s e r t ) ) { S t r i n g name = s t . nextToken ( ) ; S t r i n g hostName = s t . nextToken ( ) ; int po rt = I n t e g e r . p a r s e I n t ( s t . nextToken ( ) ) ; int ret Val ue = t a b l e . i n s e r t ( name , hostName , po rt ) ; pout . p r i n t l n ( ret V al ue ) ; } pout . f l u s h ( ) ; } catch ( IOException e ) { System . e r r . p r i n t l n ( e ) ; } } p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) {
13
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
29 30 31 32 33 34 35 36
37 38 39 40
41 42 43 44 45 46 47 48 49 50
NameServer ns = new NameServer ( ) ; System . out . p r i n t l n ( NameServer s t a r t e d : ) ; tr y { S e r v e r S o c k e t l i s t e n e r = new S e r v e r S o c k e t ( Symbols . S e r v e r Po rt ) ; while ( t r u e ) { Soc ke t a C l i e n t = l i s t e n e r . a c c e p t ( ) ; ns . h a n d l e c l i e n t ( a C l i e n t ) ; aClient . close () ; } } catch ( IOException e ) { System . e r r . p r i n t l n ( S e rv e r a bo rte d : + e ) ; } } }
A cada proceso se le indica mediante los argumentos del programa el identificador del proceso, el nmero de procesos total (5 en nuestro caso) y el nombre del algoritmo de exclusin mutua que deseamos que utilice. Las claves de los posibles algoritmos son: Lamport RicartAgrawala DiningPhil (el que estamos probando) CircToken Listing 1.4. init-DiningPhil.bat Start java NameServer Start "Filosofo 0" java LockTester "Filosofos" 0 5 DiningPhil Start "Filosofo 1" java LockTester "Filosofos" 1 5 DiningPhil Start "Filosofo 2" java LockTester "Filosofos" 2 5 DiningPhil Start "Filosofo 3" java LockTester "Filosofos" 3 5 DiningPhil Start "Filosofo 4" java LockTester "Filosofos" 4 5 DiningPhil Cada proceso se ejecuta en una termina cmd diferente, de modo que podamos visualizar el estado de cada proceso de manera individual. Por ejemplo, la figura 2 muestra la salida que expone el proceso 0 (filosofo 0) en un momento determinado. La figura siguiente se muestra la ejecucin de los 5 procesos filsofos corriendo de manera concurrente y sincronizada por el algoritmo de los filsofos comensales.
En otras palabras, es posible ver a los cinco filsofos sentados en la mesa comiendo y pensando de manera sincronizada (aunque solo sea de manera textual). En la consola de cada filsofo es posible observar de manera secuencial cada uno de los mensajes de sincronizacin que llegan y salen de cada uno de ellos. Cuando un filsofo tiene hambre, pide sus cubiertos solo a aquellos filsofos que los comparten con el (sus dos vecinos en nuestro caso), por lo que les enva el mensaje request. El filsofo se bloque en espera de la respuesta de ambos filsofos, es decir, hasta que recibe un mensaje Fork de cada uno de sus vecinos. Es entonces cuando entra a la seccin crtica durante dos segundos antes de soltar los cubiertos. Mientras come, el filsofo registra qu vecinos le han pedido un cubierto, para que cuando salga de la seccin crtica tenga conocimiento de a qu vecinos y en qu orden prestara sus cubiertos. Estos pasos se repiten indefinidamente en tanto estn corriendo los procesos de todos los filsofos que iniciaron el sistema distribuido.
Listing 1.5. init-CircToken.bat Start java NameServer Start "Filosofo 0" java LockTester "Filosofos" 0 5 CircToken Start "Filosofo 1" java LockTester "Filosofos" 1 5 CircToken Start "Filosofo 2" java LockTester "Filosofos" 2 5 CircToken Start "Filosofo 3" java LockTester "Filosofos" 3 5 CircToken Start "Filosofo 4" java LockTester "Filosofos" 4 5 CircTokenStart "Filosofo 4" java LockTester "Filosofos" 4 5 DiningPhil
Listing 1.6. init-lamport.bat Start java NameServer Start "Filosofo 0" java LockTester "Filosofos" 0 5 Lamport Start "Filosofo 1" java LockTester "Filosofos" 1 5 Lamport Start "Filosofo 2" java LockTester "Filosofos" 2 5 Lamport Start "Filosofo 3" java LockTester "Filosofos" 3 5 Lamport Start "Filosofo 4" java LockTester "Filosofos" 4 5 Lamport
Listing 1.7. init-RicartAgrawala.bat Start java NameServer Start "Filosofo 0" java LockTester "Filosofos" 0 5 RicartAgrawala Start "Filosofo 1" java LockTester "Filosofos" 1 5 RicartAgrawala Start "Filosofo 2" java LockTester "Filosofos" 2 5 RicartAgrawala Start "Filosofo 3" java LockTester "Filosofos" 3 5 RicartAgrawala Start "Filosofo 4" java LockTester "Filosofos" 4 5 RicartAgrawala
Referencias
1. Garg, Vijay. Concurrent and Distributed Computing in Java. Hoboken: IEEE Press/WileyInterscience, 2004. 2. Garg, Vijay. Distributed Computing: Java Code. http://users.ece.utexas.edu/garg/dist/jbkCode.html. Revisado el 25 de mayo de 2009.