Diseño de Algoritmos Distribuidos en Java

Documentos relacionados
DISEÑO DE UNA ARQUITECTURA CLIENTE/SERVIDOR MEDIANTE OBJETOS DISTRIBUIDOS EN JAVA

Modelo de Objetos Distribuidos

Java RMI Remote Method Invocation. Invocación Remota de Métodos en Java

Llamada a métodos remotos (RMI). Curso 04/05. Tema 9. Departament d Informàtica. Universitat de València. 1. Introducción 2

Invocación de métodos remotos en Java: JAVA - RMI

RMI. Aplicaciones Distribuidas

Java RMI. Sistemas Distribuidos Rodrigo Santamaría

Java RMI. las RPC de Java. Parte I. Luis Fernando Llana Díaz. Departamento de Sistemas Informáticos y ProgramaciónUniversidad Complutense de Madrid

en otra máquina exactamente de la misma manera que si se encontrará en la misma máquina

JAVA RMI (REMOTE METHOD INVOCATION)

RMI [Remote Method Invocation]

Sistemas Distribuidos Java RMI (Remote Method Invocation) Alberto Lafuente Mikel Larrea Dpto. ATC, UPV/EHU

El servicio de echo en Java-RMI

Práctica 2: Java Remote Method Invocation (RMI)

Objetos Distribuidos

1. Visión general de RMI

5.1 Introducción a las tecnologías de objetos distribuidos con Java RMI

Arquitectura Cliente/Servidor. Invocación de Métodos Remotos RMI: Remote Method Invocation. Llamadas a Métodos Remotos

JAVA - Serializacíon / RMI. (C) Philippe Roose , 2005

Sistemas Distribuidos (Capítulo 8 de Distributed Computing de M. L. Liu)

PROGRAMACION DISTRIBUIDA

PROGRAMACION DISTRIBUIDA MobileTracker: Ejemplo de implementación con RMI

Práctica 4: Java Remote Method Invocation (RMI)

Carlos Montenegro. Programación Orientada a Objetos Proyecto Curricular de Ingeniería de Sistemas

CAPITULO 3 ARQUITECTURA DE COMPONENTES GIS EN INTERNET

Remote Method Invocation (RMI) Basado en: Fundamentals of RMI. Short Course. JGuru.

CONTENIDO. Serialización. Carga dinamica de stubs RMI AVANZADO. Callbacks. Carga dinámica de Stubs

El servicio de echo con sockets

PROGRAMACION DISTRIBUIDA

Centro Asociado Palma de Mallorca. Antonio Rivero Cuesta

PROGRAMACIÓN ORIENTADA A OBJETOS 10/02/2009. Examen de Java. Nombre: DNI: Titulación:

RMI Remote Method Invocation

FSD Práctica Invocación Remota: JavaRMI. Estudio Previo. Información

Interacción entre Aplicaciones: objetos distribuidos e invocación remota

SISTEMAS DISTRIBUIDOS

Identificadores, palabras reservadas, tipos de datos, operadores aritméticos y el sistema estándar de salida en Java

Práctica sobre compartición de instancias remotas.

Una introducción a Java RMI

Cliente/Servidor en Java

Unidad Didáctica 3. Tipos genéricos. Fundamentos de Programación Departamento de Lenguajes y Sistemas Informáticos

Unidad Didáctica 2. Elementos básicos del lenguaje Java Tipos, declaraciones, expresiones y asignaciones

Tema 4: INVOCACIÓN REMOTA

Tema 3. Objetos distribuidos

Componentes Distribuidos EJBs. Ing. Cesar Julio Bustacara Medina

Estructuras de control selectivas

Ingeniería del Software Arquitectura Física en 3 niveles

HOJA DE EJERCICIOS 5 PROGRAMACIÓN CON EXCEPCIONES EN JAVA

Elementos léxicos del lenguaje de programación Java

Introducción a Java LSUB. 30 de enero de 2013 GSYC

Examen Teórico Convocatoria de Junio de 2012

PROGRAMACION DISTRIBUIDA

Servicios Web. Andrés Pastorini. TRIA Tecnólogo Informático

Definición. Mónica E. García García Feb 07

Remote Method Invocation (RMI) de Java

1. Introducción. 1.1 Construcción de una aplicación CORBA

PROGRAMACIÓN GENÉRICA

Sockets en Java. Prof. Wílmer Pereira Universidad Simón Bolívar

JAVA 1. Introducción

Parte I: Programación en un lenguaje orientado a objetos

Interfaces. Amparo López Gaona. Septiembre de Amparo López Gaona () Interfaces Septiembre de / 1

Ejercicio 4. EJB Sesión - Sistema SGA. Java EE. Ejercicio 4. EJB Sesión Sistema SGA. Curso de Java EE

Variables. Una variable no es más que un nombre simbólico que identifica una dirección de memoria: vs.

Agenda..NET C# Laboratorio #1

Ingeniería del Software Separación entre Presentación y Lógica del Negocio

Tema 1: Principios de Java

CORBA desde Java. Diego Sevilla Ruiz Sistemas Distribuidos. 1. Introducción

Práctica 5: Servidor web concurrente en Java

Construcciones del Lenguaje Java

Una aplicación sencilla con CORBA y Java

Introducción a Java. Dr. (c) Noé Alejandro Castro Sánchez

'HVDUUROORGH$SOLFDFLRQHV FRQ-DYD50,

Examen escrito de Programación 1

TEMA 7: Paso de Mensajes con RMI

Qué es Java? Un lenguaje de programación Un entorno de desarrollo Un entorno de aplicación Un entorno de despliegue Es similar en sintaxis de C + +.

FUNDAMENTOS DE PROGRAMACIÓN. SEPTIEMBRE 2005

LABORATORIO DE RC PRÁCTICA 2: IMPLEMENTACIÓN DE UN CLIENTE Y SERVIDOR DE

CURSO : ESTRUCTURA DE DATOS DOCENTE : ING. JUAN ZEVALLOS VALLE

Sistemas de Información

Métodos CON valor de retorno

VII.1: RMI: Remote Method Invocation

Comunicación entre procesos: sockets udp. Jorge Iván Meza Martínez

Ejecución de hebras. En realidad, todas las aplicaciones escritas en Java son aplicaciones multihebra (recuerde el recolector de basura).

Manual del Protocolo XML-RPC de Mensajería Negocios

INTERFACE COMPARATOR. DIFERENCIAS ENTRE COMPARATOR Y COMPARABLE. CLASE COLLECTIONS. EJERCICIOS RESUELTOS. (CU00918C)

Programación concurrente en Java

Arquitecturas cliente/servidor

Transcripción:

Diseño de Algoritmos Distribuidos en Java José Luis Pastrana Brincones (pastrana@lcc.uma.es) Departamento de Lenguajes y Ciencias de la Computación de la Universidad de Málaga Resumen El diseño de algoritmos es una parte fundamental en las tecnologías de la información, como se ha visto reflejado por el gran número de libros y artículos relacionados con el tema. La gran mayoría de los mismos, tratan los algoritmos en el contexto de una programación secuencial, donde el flujo de control va siempre en una misma dirección y en cada paso del algoritmo se realiza una única acción. El gran auge del concepto de redes de comunicación, junto con los avances en la metodología de programación han conseguido que el concepto de comunicación y de diseño de algoritmos distribuidos surjan como un nuevo aspecto en las técnicas de desarrollo del software. Los algoritmos distribuidos, clásicamente, han sido desarrollados mediante el uso de lenguajes imperativos a los que se les ha añadido determinadas primitivas de comunicación, pero si nos fijamos en la filosofía de los lenguajes orientados a objetos, podemos ver la similitud existente entre procesos y objetos, comunicación y métodos, y aún más, incluso podríamos ver nuestra red de comunicaciones como un objeto más en nuestro sistema. En este trabajo, consideraremos dos clases de algoritmos distribuidos: la primera en la que trataremos los algoritmos basados en una arquitectura Cliente/Servidor y para la que usaremos una técnica de invocación de métodos remotos. Y una segunda,más genérica, en la que consideraremos un sistema distribuido como un conjunto de objetos o procesos conectados a través de una red y que cooperan para la obtención de un objetivo común. Para la resolución de este tipo de problemas, consideraremos la red como un objeto más del sistema que tiene métodos para el envío y recepción de mensajes a través de la misma. A lo largo del trabajo, se describirán ambas técnicas y se implementarán varios algoritmos como ejemplo para su mejor comprensión. Como lenguaje de soporte hemos usado Java debido al gran auge que está teniendo en nuestros días, así como por adaptarse a los requerimientos de orientación a objetos e incluir un paquete para la

invocación de métodos remotos, y la clase jpvm (David A. Thurman) que embebe PVM en Java y que nos ha servido para modelar la red como un objeto del sistema. Arquitectura Cliente/Servidor. En una arquitectura Cliente/Servidor, el servidor es un proceso que repetidamente maneja peticiones de los clientes (recibe una petición de un cliente, realiza el servicio y retorna el resultado), y el cliente es el proceso que realiza dichas peticiones de servicios a otra aplicación llamada cliente. El desarrollo de aplicaciones Cliente/Servidor mediante sockets conlleva el diseño de un protocolo que consiste en un lenguaje común entre el Cliente y el Servidor. El diseño de dicho protocolo es una de las mayores fuentes de errores tales como el deadlock. En lugar de trabajar directamente con sockets, una aplicación Cliente/Servidor puede ser desarrollada usando una filosofía de orientación a objetos. Desde el punto de vista del Cliente, consideramos el Servidor como un objeto remoto que nos ofrece una serie de servicios que pueden ser llamados mediante la invocación remota de sus métodos. La invocación de métodos remotos (Remote Methods Invocation, RMI) es muy similar (pero más general y fácil de usar) que la llamada a procedimientos remotos (Remote Procedure Call, RPC). Básicamente, el usuario trabaja con los objetos remotos como si estos fueran locales, gracias a que los paquetes RMI incluyen un recolector de basura distribuido y una invocación transparente de los métodos remotos (con la misma sintaxis que los locales). Veamos a continuación cómo podríamos realizar esto mediante un sencillo ejemplo realizado en Java. Vamos a desarrollar un Servidor que nos realiza operaciones sobre vectores y matrices, así como un cliente que las utiliza. El desarrollo de aplicaciones Cliente/Servidor en Java conlleva 6 etapas: 1. Definición de la Interfaz Remota. Permite al cliente conocer los servicios que puede utilizar, por lo tanto debe ser pública. 2. Implementación de la interfaz remota. Esta será el cuerpo del servidor. 3. Escribir la aplicación cliente que use el servidor. 4. Generar los stubs y skeletons. Un stub es un cliente proxy y un skeleton es una entidad servidor que realiza las llamadas a la implementación actual del objeto remoto 5. Ejecutar el registry. Es un Servidor de nombres.

1. Ejecutar el Servidor y el/los Cliente. Remote interface. Implementation public import interface java.rmi.*; MatrixInterface extends java.rmi.remote import { java.rmi.server.unicastremoteobject; public int[] add(int a[], int b[] ) throws java.rmi.remoteexception; public class public MatrixServer int[] sub(int extends a[], int UnicastRemoteObject b[] ) throws java.rmi.remoteexception; implements MatrixInterface { private... String ServerName; public public MatrixServer int[][] add(int ( String a[][], s ) throws int b[][] RemoteException ) throws java.rmi.remoteexception; { ServerName public int[][] = s; sub(int a[][], int b[][] ) throws java.rmi.remoteexception; public... int[] add(int a[], int b[] ) throws RemoteException {... public int[] sub(int a[], int b[] ) throws java.rmi.remoteexception {...... public int[][] add(int a[][], int b[][] ) throws java.rmi.remoteexception {... public int[][] sub(int a[][], int b[][] ) throws java.rmi.remoteexception {...... public static void main(string argv[]) { MatrixServer server; System.setSecurityManager( new RMISecurityManager() ); try { server = new MatrixServer ( " MatrixServer " ); Naming.rebind("//host/ MatrixServer ",server); System.out.println("MatrixServer running "); catch (Exception e) { System.out.println("Sorry, error succeeded:" + e.getmessage()); e.printstacktrace(); Cliente Application import java.rmi.*; import java.net.*; public class Cliente { public static void main(string argv[]) { int a[] = { 1, 2, 3, 4, 5 ; int b[] = { 6, 7, 8, 9, 0 ; int result [] = new int[5]; MatrixInterface RemoteServer; int i; try { String url = "//host/matrixserver"; RemoteServer = (MatrixInterface)Naming.lookup(url); result = RemoteServer.add(a,b); System.out.print( ( ); for(i=0;i<4;++i) System.out.print(a[i] +, ); System.out.print(a[4] + ) + ( ); for(i=0;i<4;++i) System.out.print(b[i] +, ); System.out.print(b[4] + ) = ( ); for(i=0;i<4;++i) System.out.print(c[i] +, ); System.out.println(c[4] + ) ); catch (Exception e) { System.out.println("Sorry, error succeeded:" + e.getmessage()); e.printstacktrace();

Conjunto e Procesos que Cooperan para lograr un Objetivo Común. Un algoritmo distribuido ha sido definido clásicamente como un conjunto de procesos, conectados a través de una red, que cooperan para lograr un objetivo común. Nuestra aproximación consiste en considerar cada proceso como un objeto, e incluso la red de conexión es considerada como un objeto más de nuestro sistema. Cada objeto-proceso tiene sus propios métodos y objetos locales para la resolución de su parte de la tarea y la red es un objeto especial que tiene métodos para el envío y recepción de mensajes entre objetos. Veamos cómo podemos utilizar esta aproximación para la resolución de un problema clásico para sistemas distribuidos: El Problema de la Exclusión Mutua Distribuida. Hemos utilizado Java como soporte junto con la clase jpvm (desarrollada por David A. Thurman, Center for Human-Machine Systems Research, School of Industrial and Systems Engineering, Georgia Institute of Technology) para el modelado de la red como objeto. Esta clase implementa todas las primitivas de las librerías de PVM mediante la incorporación de métodos en código nativo. El Problema de la Exclusión Mutua Distribuida. Este es uno de los primeros problemas que se plantean en programación distribuida. Una serie de procesos, que trabajan en paralelo, compiten por recursos que no pueden ser accedidos al mismo tiempo. El problema de la exclusión mutua fue debido a Dekker y usaba únicamente operaciones primitivas para la lectura y escritura de una palabra en memoria. En un sistema distribuido, la especificación de un algoritmo de exclusión mutua no puede ser realizada en términos de dependencia de un acceso a memoria central, debe ser realizada en términos de intercambio de mensajes, y el algoritmo debe tener las características de equitabilidad y ausencia de bloqueo, es decir, que cualquier proceso que desee entrar en su sección crítica debe ser capaz de hacerlo en un intervalo finito de tiempo. Circulación de un Token en un Anillo Lógico. Este es un algoritmo simple para el problema de la exclusión mutua distribuida, aplicable cuando la topología de nuestra red es un anillo. Cada proceso solamente podrá entrar en su sección crítica cuando posea el Token, que siempre recibirá de su vecino de la izquierda, y dará al de su derecha al salir de la sección crítica.

public class TokenRing { public static void main(string argv[]) { Net net; int max; int me; int left; int right; boolean token_present; try { Net = new Net((Integer.valueOf (argv[0])).intvalue()); catch (ArrayIndexOutOfBoundsException e) { Net = new Net(1); me = net.mi_id(); max = net.numprocs(); right = (me+1)%max; left = me -1; if (left<0) left = max -1; if (me==0) else /* Algorithm Body */ token_present=true; token_present = false; while(true) { if (!token_present) {net.wait_token(left); token_present=true; /* Critical Section */ System.out.println("Process "+me+ " in Critical Section"); /* Critical Section */ net.send_token(right); token_present=false; public class Net extends jpvm { private int my_id; private int my_father; private int maxproc; private int processes[]; private Net pvm; public final static int Initialise = 0; public final static int Token = 1; public Net() { super(); public Net(int max) { String javaexe ="/jdk/bin/java"; String args[]; int max_array[]; int i; args = new String [3]; args[0]= "-classpath"; args[1]= " /jdk/lib/classes.zip + :/jpvm-v1.1.4:/tokenring_pvm"; args[2]="tokenring"; max_array = new int[1]; pvm = new Net(); my_id = pvm.mytid(); my_father = pvm.parent(); if (my_father==pvmnoparent) { maxproc = max; processes[0]=my_id; { pvm.spawn(javaexe,args, PvmTaskDefault,"",max_array); processes[i]=max_array[0]; max_array[0] = maxproc; pvm.initsend(pvmdatadefault); pvm.pkint(max_array, 1, 1); pvm.pkint(processes, maxproc, 1); pvm.send(processes[i], Initialise); else { pvm.recv(my_father, Initialise); pvm.upkint(max_array, 1, 1); maxproc = max_array[0]; pvm.upkint(processes, maxproc, 1); public int mi_id() { int i; for (i=0;i<maxproc;++i) if (processes[i]==my_id) return i; return -1; public int numprocs() { return maxproc; public void wait_token(int left) { pvm.recv(processes[left],token); public void send_token(int right) { pvm.initsend(pvmdatadefault); pvm.send(processes[right],token);

El Algoritmo de Ricart and Agrawala/Suzuki Kasami. En este algoritmo, el privilegio que permite a un proceso entrar en su sección crítica esta representado por un Token; cualquier proceso que posea el Token podrá entrar en su sección crítica sin pedir permiso a los demás. Inicialmente el Token es asignado a uno de los procesos (el proceso número cero en nuestro caso). Un proceso que desea entrar en su sección crítica no sabrá qué otro proceso tiene el Token en dicho instante y lo pedirá mediante la difusión todos los demás de un mensaje que estará etiquetado en el tiempo. Cuando el proceso que tiene el Token (Pj) deja su sección crítica, busca en el vector de peticiones en orden j+1,j+2,...,n,1,2,...j-1 el primer valor de k tal que su etiqueta de tiempo de su última petición del Token sea mayor que el valor almacenado en el Token para dicho proceso, y entonces transfiere el Token de Pj a Pk. public class Ricart { public static void main(string argv[]) { Net net; int max,me,i,j clock,token[],requests[]; boolean token_present, token_held; try { net = new Red( (Integer.valueOf (argv[0])).intvalue()); catch (ArrayIndexOutOfBoundsException e ) { net = new Red(1); me = net.mi_id(); max = net.numprocs(); if (me==0) token_present=true; else token_present = false; token_held=false; clock=0; token = new int[max]; requests = new int[max]; for(i=0;i<max;++i) { token[i]=0; requests[i]=0; /* Algorithm Body */ while(true) { if (!token_present) { ++clock; net.broadcast(requests,clock); token = net.wait_access(); token_present=true; token_held=true; /* Critical Section */ System.out.println("Process "+me+ " in Critical Section"); /* Critical Section */ token[me] = clock; token_held=false; requests = net.wait_request(); if (requests!=null) /* any request */ for(i=0;i<max;++i) { j = (i+me+1)%max; if ( (requests[j] > token[j]) && (token_present) ) { token_present=false; net.send_access(token,j); break;

public class Net extends jpvm { private int my_id,my_father,maxproc, processes[]; private Net pvm; public final static int Initialise = 0; public final static int Request = 1; public final static int Access = 2; public final static int Any = -1; public Net() { super(); public Net(int max) { String javaexe = "/jdk/bin/java"; String args[]; int max_array[],i; args = new String [3]; args[0]= "-classpath"; args[1]= "/jdk/lib/classes.zip: + /jpvm-v1.1.4: /Ricart_pvm"; args[2]="ricart"; max_array = new int[1]; pvm = new Net(); my_id = pvm.mytid(); my_father = pvm.parent(); if (my_father==pvmnoparent) { maxproc = max; processes[0]=my_id; { pvm.spawn(javaexe,args, PvmTaskDefault,"",max_array); processes[i]=max_array[0]; max_array[0] = maxproc; pvm.initsend(pvmdatadefault); pvm.pkint(max_array, 1, 1); pvm.pkint(processes, maxproc, 1); pvm.send(processes[i],initialise); else { pvm.recv(my_father,initialise); pvm.upkint(max_array, 1, 1); maxproc = max_array[0]; pvm.upkint(processes, maxproc, 1); public int mi_id() { int i; for (i=0;i<maxproc;++i) if (processes[i]==my_id) return i; return -1; public int numprocs() { return maxproc; public void broadcast(int requests[],int clock) { int i,ck[],me[]; me = new int[1]; me[0] = mi_id(); ck = new int[1]; ck[0]=clock; pvm.initsend(pvmdatadefault); pvm.pkint(me, 1, 1); pvm.pkint(ck, 1, 1); pvm.pkint(requests, maxproc, 1); for (i=0;i<maxproc;++i) if (processes[i]!=my_id) pvm.send(processes[i],request); public int[] wait_request() { int rq[],info,ck[],me[]; info = pvm.nrecv(any,request); if (info<=0) return null; /* No requests */ rq = new int[maxproc]; me = new int[1]; ck = new int[1]; pvm.upkint(me, 1, 1); pvm.upkint(ck, 1, 1); pvm.upkint(rq, maxproc, 1); if (rq[me[0]] < ck[0]) rq[me[0]] = ck[0]; return rq; public int[] wait_access() { int token[]; token = new int[maxproc]; pvm.recv(any,access); pvm.pkint(token, maxproc, 1); return token; public void send_access(int token[],int j)

{ pvm.initsend(pvmdatadefault); pvm.pkint(token, maxproc, 1); pvm.send(processes[j],access); Pérdida del Token: Algoritmo de Misra. El principal problema de la solución de un Token circulando por un anillo es que la pérdida de dicho Token implica un bloqueo del sistema. El Algoritmo de Misra fue desarrollado para la detección y regeneración del Token en el caso de que éste se pierda. Usaremos dos tokens, llamados ping y pong, y asociados con ellos dos números enteros llamados nbping y nbpong respectivamente, iguales en valor absoluto pero de signo opuesto, que almacenan el número de veces que ambos tokens se han encontrado en un mismo proceso. Dichos números estarán entonces relacionados por la restricción nbping + nbpong = 0. Inicialmente, ambos tokens están en un mismo proceso y por tanto, nbping = 1, nbpong = -1. Cada proceso Pi almacena en una variable local, inicializadas a cero, el valor de nbping o nbpong, asociado con el Token. Esencialmente, el algoritmo conserva la relación nbping + nbpong = 0 y cuando esta relación se rompe, significa que el Token ping (o pong) se ha perdido y hay que regenerarlo. public class Misra { public final static int ping = 0; public final static int pong = 1; public static void main(string argv[]) { Net net; int max,me,left,right, nbping=1,nbpong=-1,m=0; boolean token_ping,token_pong; try { net = new net( (Integer.valueOf (argv[0])).intvalue()); catch (ArrayIndexOutOfBoundsException e) { net = new net(1); me = net.mi_id(); max = net.numprocs(); right = (me+1)%max; left = me -1; if (left<0) left = max -1; if (me==0) { token_ping=true; token_pong=true; else { token_ping = false; token_pong = false; /* Algorithm Body */ while(true) { if (!token_ping) token_ping = net.wait_token(left,ping,nbping); if (!token_pong) token_pong = net.wait_token(left,pong,nbpong); if (token_ping) /* Critical Section */ { System.out.println("Process "+me +" in Critical Section "); if ((token_ping) && (token_pong) ) { ++ nbping; -- nbpong; net.send_token(right,ping,nbping); net.send_token(right,pong,nbpong); else { if (token_ping) { if (m == nbping) /* Token Lost */ { ++nbping; nbpong = -nbping; net.send_token(right,pong, nbpong); /* Regenerate it */ else { m = nbping; net.send_token(right,ping,nbping); if (token_pong)

{ if (m == nbpong) /* Token Lost */ { ++nbpong; nbping = -nbpong; net.send_token(right,ping, nbping); /* Regenerate it */ else { m = nbpong; net.send_token(right,pong,nbpong); public class Net extends jpvm { private int my_id,my_father, maxproc,processes[]; private Net pvm; public final static int Initialise = 0; public Net() { super(); public Net(int max) { String args[],javaexe = "/jdk/bin/java"; int i,max_array[]; args = new String [3]; args[0]= "-classpath"; args[1]= "/jdk/lib/classes.zip + :/jpvm-v1.1.4:/misra_pvm"; args[2]="misra"; max_array = new int[1]; pvm = new Net(); my_id = pvm.mytid(); my_father = pvm.parent(); if (my_father==pvmnoparent) { maxproc = max; processes[0]=my_id; { pvm.spawn(javaexe,args, PvmTaskDefault,"",max_array); processes[i]=max_array[0]; max_array[0] = maxproc; pvm.initsend(pvmdatadefault); pvm.pkint(max_array, 1, 1); pvm.pkint(processes, maxproc, 1); pvm.send(processes[i],initialise); else { pvm.recv(my_father,initialise); pvm.upkint(max_array, 1, 1); maxproc = max_array[0]; pvm.upkint(processes, maxproc, 1); public int mi_id() { int i; for (i=0;i<maxproc;++i) if (processes[i]==my_id) return i; return -1; public int numprocs() { return maxproc; public boolean wait_token(int i,int tag, int nb) { int info,numb[]; info = pvm.nrecv(processes[i],tag); if (info<=0) return false; numb = new int[1]; pvm.upkint(numb,1,1); nb = numb[0]; return true; public void send_token(int i,int tag, int nb) { int numb[]; numb = new int[1]; numb[0] = nb; pvm.initsend(pvmdatadefault); pvm.pkint(numb,1,1); pvm.send(processes[i],tag); Referencias [1] M. Raynal, Distributed Algorithms and Protocols: John Wiley & Sons Ltd., 1988. [2] R. Andrews, Concurrent Programming. Gregory: Benjamin/Cummings, 1991.

[3] Remote Method Invocation System. Sun Microsystems Inc.,1996-1997. [4] Getting Started using RMI. Sun Microsystems Inc.,1996-1997. [5] RMI and Object Serialisation. Sun Microsystems Inc.,1996-1997. [6] Q. H. Mahmond, Distributed Object Programming Using Java:Java Resource Center,1997.