La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Qué vimos la clase pasada?

Presentaciones similares


Presentación del tema: "Qué vimos la clase pasada?"— Transcripción de la presentación:

1 Qué vimos la clase pasada?
Hoare introdujo CSP como lenguaje formal que sigue el modelo de pasaje de mensajes sincrónicos, como un modelo de especificación, sin una implementación real. OCCAM es un lenguaje real, que implementa lo esencial de CSP sobre una arquitectura “modelo” que físicamente se ha desarrollado y que son los trasputers. Trasputers + OCCAM constituyen una combinación que permite hablar de “sistema multiprocesador para procesamiento concurrente”, donde aparecen los conceptos de CSP (comunicación guardada half duplex, no determinismo, especificación del paralelismo, timers, canales estáticos). Programación Concurrente Clase 9

2 Qué vimos la clase pasada?
Una técnica muy utilizada es el desarrollo de bibliotecas de funciones que permiten comunicar/sincronizar procesos. Las soluciones basadas en bibliotecas (tales como LINDA, MPI, PVM) tienden a ser menos eficientes que los lenguajes “reales”de programación concurrente, aunque tienen la facilidad de “agregarse”al código secuencial con bajo costo de desarrollo. LINDA explota el paradigma de “bag of tasks” y en nuestros días las redes han potenciado las soluciones basadas en PVM o MPI (que son básicamente bibliotecas de comunicaciones). Programación Concurrente Clase 9

3 Comentarios sobre las preguntas para la promoción
Ud. tiene una red (por ejemplo móvil) conectada sin cables. Debe hacer un análisis para que todos sepan quienes están conectados en la red. Usaría mensajes sincrónicos o asincrónicos? Por qué? Si no existe un nodo distinguido y todos deben aprender la topología, es conveniente trabajar con mensajes asincrónicos y un timer general. Si intentamos con mensajes sincrónicos, es muy complicado por la naturaleza bloqueante del SEND. Si se tratara de hacer un broadcast en una red conectada en anillo, qué diferencias ve entre SMP y AMP? Los tiempos que se pierden en los SEND bloqueantes si el siguiente nodo en el anillo no está haciendo RECEIVE. Programación Concurrente Clase 9

4 Servidor / Servidores replicados y el caso de los Filósofos.
Programación Concurrente Clase 11

5 Paradigma de servidores replicados. Modelos de solución de filósofos.
El primer modelo de solución que hemos visto, es el centralizado. En este caso los procesos Filósofo se comunican con un proceso Waiter (SERVIDOR) que decide el acceso o no a los recursos. La segunda solución que llamaremos distribuida supone cinco procesos Waiter cada uno de los cuales maneja un tenedor. Para este problema un Filósofo puede comunicarse con dos Waiters (SERVIDOR izquierdo y derecho), solicitando y devolviendo el recurso. Los Waiters NO se comunican entre ellos. En la tercer solución que llamaremos descentralizada, cada Filósofo ve un único Waiter. En cambio los Waiters (SERVIDORES) se comunican entre ellos (de hecho cada uno con sus dos vecinos) para decidir el manejo del recurso asociado a “su” Filósofo. Programación Concurrente Clase 11

6 Recordemos Filósofos centralizados.
Waiter:: var eating[1:5] := ([5] false) { EAT: (  i: 1  i  5: eating[i]   (eating[i1]  eating[i1]) } DO (i: 1..5) not (eating [i1] or eating[i1]); Phil[i]?getforks( )  eating[i] := true  (i: 1..5) Phil[i]?relforks( )  eating[i] := false OD Phil[i: 1..5]:: DO true  Waiter ! getforks( ) come Waiter ! relforks( ) piensa Programación Concurrente Clase 11

7 Paradigma de servidores replicados: Filósofos distribuidos.
Process Philosopher[i=0 to 4] { INT first=i, second= i+1; IF (i == 4) { first=0; second=4;} WHILE (true) { Call Waiter[first]. Getfork ( ); Call Waiter[second]. Getfork ( ); COMER; Send Waiter[first]. Relfork ( ); Send Waiter[second].Relfork ( ); PENSAR; } Programación Concurrente Clase 11

8 Paradigma de servidores replicados: Filósofos distribuidos.
Module Waiter[5] op Getforks( ), Relfork( ); BODY Process The_Waiter { WHILE (true) receive getfork ( ); receive relfork ( ); } End Waiter; Programación Concurrente Clase 11

9 Paradigma de servidores replicados: Filósofos descentralizados.
Module Waiter[ t=0 to 4] OP Getforks(int), Relforks(int); #usadas por los filósofos OP NeedL( ), NeedR( ), PassL ( ), PassR( ); # para los Waiters OP Forks (bool, bool, bool, bool); #para inicializar BODY OP Hungry( ), Eat ( ) ; #operaciones locales BOOL haveL, dirtyL, haveR, dirtyR; #status de los tenedores INT left = (t-1) MOD 5; #vecino a izquierda INT right = (t +1) MOD 5; # vecino a derecha PROC Getforks ( ) { send Hungry ( ); receive Eat( ); # espera el permiso para comer } Programación Concurrente Clase 11

10 Filósofos descentralizados. Proceso Waiter
Process the_Waiter { receive forks (haveL, dirtyL, haveR, dirtyR); WHILE (true) { IN hungry ( ) ---> # preguntar por los tenedores que no se tienen IF (Not HaveR) send Waiter[right].needL( ); IF (Not HaveL) send Waiter[left].needR( ); # esperar hasta tener ambos tenedores WHILE ( Not haveL OR Not haveR) IN passR( ) ----> haveR=true; dirtyR=false; [ ] passL( ) -----> haveL=true; dirtyL=false; [ ] needR( ) st dirtyR ---> haveR=false; dirtyR=false; send waiter[rigth].passL( ); send waiter[rigth].needL( ); [ ] needL( ) st dirtyL ---> haveL=false; dirtyL=false; send waiter[left].passR( ); send waiter[left].needR( ); NI Programación Concurrente Clase 11

11 Filósofos descentralizados. Proceso Waiter
# Al salir del lazo WHILE el Waiter tiene los dos tenedores para # su filosofo. Debe dejarlo comer y esperar que los libere send Eat ( ); dirtyL=true; dirtyR=true; receive Relforks( ); [ ] needR ( ) ----> # Waiter vecino requiere mi tenedor derecho (su izquierdo) haveR=false; dirtyR=false; send waiter[rigth].passL( ); [ ] needL ( ) ----> # Waiter vecino requiere mi tenedor izquierdo (su derecho) haveL=false; dirtyL=false; send waiter[left].passR( ); NI } End Waiter Programación Concurrente Clase 11

12 Filósofos descentralizados. Procesos Filósofo y Main
Process Philosopher [i=0 to 4] { WHILE (true) Call Waiter[i].Getforks ( ); COMER; Call Waiter[i].Relforks( ); PENSAR; } Process Main { send Waiter[0].forks(true, true, true, true); send Waiter[1].forks(false,false, true, true); send Waiter[2].forks(false, false, true, true); send Waiter[3].forks(false, false, true, true); send Waiter[4].forks(false, false, false, false); Programación Concurrente Clase 11

13 Conceptos de RPC y Rendezvous.
El pasaje de mensajes (sincrónico o asincrónico) se ajusta muy bien a los problemas de filtros y pares que interactúan. Siempre se plantea la comunicación unidireccional. Cuando resolvemos C/S la comunicación bi-direccional obliga a especificar 2 tipos de canales (requerimientos y respuestas). RPC (Remote Procedure Call) y Rendezvous son técnicas de comunicación y sincronización entre procesos que suponen un canal bidireccional. Por esto son ideales para programar aplicaciones Cliente-Servidor. Programación Concurrente Clase 9

14 Conceptos de RPC y Rendezvous.
Supongamos una arquitectura multiprocesador con tareas o procesos que serán “servidores” de otras tareas o procesos que funcionan como clientes. RPC y Rendezvous combinan una interfaz “tipo monitor” con operaciones que se exportan a través de llamadas externas (CALL) con mensajes sincrónicos (demoran al llamador). Programación Concurrente Clase 9

15 Conceptos de RPC y Rendezvous. Diferencias
En RPC la idea es que existe alguna forma de “sistema operativo” o administrador de procesos que “controla” los procesos servidores. Ante un pedido de un servicio activa (“crea”) el servidor y entrega el servicio al cliente. Para el cliente, durante la ejecución del servicio, es como si tuviera en su sitio el proceso remoto que lo sirve.(Ejemplo: JAVA) Programación Concurrente Clase 9

16 Conceptos de RPC y Rendezvous. Diferencias
EL Rendezvous supone un modelo de tareas (procesos) concurrentes que existen y pueden jugar el rol de clientes o servidores. Es el modelo de CSP extendido para soportar procesos dinámicos y canales bidireccionales. (Ejemplo típico: ADA). Un proceso servidor reside siempre en un dado procesador físico. Programación Concurrente Clase 9

17 Conceptos de Rendezvous.
El concepto básico es que un programa concurrente se compone de procesos independientes que se pueden sincronizar. La sincronización “acopla” las tareas concurrentes, estableciendo un link bidireccional donde el proceso que llama se demora hasta recibir la respuesta del proceso llamado. El rol de servidor o cliente puede alternarse entre los procesos (tareas) e incluso una misma tarea puede ser servidor para algunos procesos y cliente para otros. Programación Concurrente Clase 9

18 Lenguaje ADA y Rendezvous.
Desde el punto de vista de la concurrencia, un programa Ada tiene “tasks” (procesos) que se pueden ejecutar independientemente (sobre distintos procesadores) y que contienen primitivas de sincronización. Los puntos de invocación (es decir de "entrada") a un proceso concurrente o task se denominan ENTRYs y están especificados en la parte visible del TASK. Un TASK puede decidir si "acepta" la comunicación con otro proceso,mediante la primitiva ACCEPT. Un aspecto muy importante de ADA es que podemos declarar un TIPO TASK, y luego crear instancias del proceso identificado con dicho tipo que se necesiten en la ejecuciòn. Programación Concurrente Clase 9

19 TASKs en lenguaje ADA. La forma más común de una especificación de task es: TASK identifier IS declaraciones de ENTRYs end; La forma más común de un cuerpo de task es: TASK body identifier IS declaraciones locales BEGIN sentencias END identifier; Programación Concurrente Clase 9

20 TASKs en lenguaje ADA. Una especificación de TASK define una única tarea. Una instancia del correspondiente task body se crea en el bloque en el cual se declara el TASK. Ada también soporta arreglos de tareas, pero de manera distinta a la de la mayoría de otros lenguajes. En particular, el programador primero declara un task type y luego declara un arreglo de instancias de ese tipo. Programación Concurrente Clase 9

21 TASKs en lenguaje ADA. También se puede usar task types en conjunción con punteros (access types) para crear tasks dinámicamente. Ada no provee ningún mecanismo para asignar tasks a procesadores y por lo tanto para controlar el layout de un programa distribuido. Si fuera necesario, tiene que ser expresado en un lenguaje de configuración específico de la implementación. Programación Concurrente Clase 9

22 Constructores del lenguaje ADA para sincronización.
El rendezvous es el único mecanismo de sincronización en Ada y también es el mecanismo de comunicación primario. Las declaraciones de entry son muy similares a las declaraciones op. entry identifier(formales) Los parámetros del entry en Ada pueden ser IN, OUT o IN OUT. Ada también soporta arreglos de entries, llamados familias de entry. Si el task T declara el entry E, otras tasks en el alcance de la especificación de T pueden invocar a E por una sentencia call: call T.E(reales) Como es usual, la ejecución de call demora al llamador hasta que la operación E terminó (o abortó o alcanzó una excepción). Programación Concurrente Clase 9

23 TASKs en lenguaje ADA. Por ejemplo un mailbox único para mensajes de un tipo mensaje puede ser implementado por una task. La parte visible exporta dos entries: depositar y retirar: TASK TYPE Mailbox IS ENTRY Depositar(msg: IN mensaje); ENTRY Retirar(msg: OUT mensaje); END Mailbox; A, B, C : Mailbox; -- Se declaran 3 instancias del tipo Mailbox. TASK BODY Mailbox IS -- Declaraciones BEGIN -- Implementación de los entries Depositar y Retirar Podemos utilizar estos mailbox para manejar mensajes del siguiente modo: call A.Depositar(x1); call B.Depositar(x2); call C.Retirar(x3); Programación Concurrente Clase 9

24 Sincronización en ADA. La task que declara un entry sirve llamados de ese entry por medio de la sentencia accept. accept E(formales) do lista de sentencias end; La ejecución de accept demora la tarea hasta que haya una invocación de E, copia los argumentos de entrada en los formales de entrada, luego ejecuta la lista de sentencias. Cuando la lista de sentencias termina, los formales de salida son copiados a los argumentos de salida. En ese punto, tanto el llamador como el proceso ejecutante continúan. Una sentencia accept es como una input statement con una guarda. Programación Concurrente Clase 9

25 Sentencia ACCEPT en ADA.
Si ponemos: ACCEPT E1(parámetros formales) DO cuerpo de E1 END E1; ACCEPT E2(parámetros formales) DO cuerpo de E2 END E2; ACCEPT E3(parámetros formales) DO cuerpo de E3 END E3; Se especifica que se espera un pedido por el entry E1, luego de atendido se espera un pedido por el entry E2 y luego de atendido un pedido por el entry E3 que será atendido. NOTAR que el orden es fundamental para no tener un deadlock. Programación Concurrente Clase 9

26 La sentencia ACCEPT en ADA.
Podemos ejecutar repetidamente una secuencia de atención de pedidos como la anterior, mientras se dé una condición lógica: WHILE (condicion booleana) LOOP ACCEPT E1(parámetros ) DO cuerpo de E1 END E1; ACCEPT E2(parámetros ) DO cuerpo de E2 END E2; ACCEPT E3(parámetros ) DO cuerpo de E3 END E3; END LOOP Aplicado a nuestro ejemplo anterior, supondría un lazo como éste: LOOP ACCEPT Depositar (msg: IN mensaje) DO ... END Depositar; ACCEPT Retirar (msg: OUT mensaje) DO ... END Depositar; END LOOP; Notar que esta manera de escribir el código supone una secuencia exacta: a cada Depositar le seguirá un Retirar. Programación Concurrente Clase 9

27 Waiting selectivo en ADA (Select).
La sentencia wait selectiva soporta comunicación guardada. select when B1  sentencia accept; sentencias or ... or when Bn  sentencia accept; sentencias end select Cada línea (salvo la última) se llama alternativa. Las Bi son expresiones booleanas, y las cláusulas when son opcionales. Una alternativa se dice que está abierta si Bi es true o se omite la cláusula when. Esta forma de wait selectivo demora al proceso ejecutante hasta que la sentencia accept en alguna alternativa abierta pueda ser ejecutada, es decir, haya una invocación pendiente del entry nombrado en la sentencia accept. Programación Concurrente Clase 9

28 Un ejemplo de waiting selectivo en ADA.
LOOP SELECT WHEN numero < capacidad => ACCEPT Depositar (msg: IN mensaje) DO -- Acciones -- Incrementar numero END Depositar; OR WHEN numero > 0 => ACCEPT Retirar (msg: OUT mensaje) DO -- Decrementar numero END Retirar; END SELECT; END LOOP; Programación Concurrente Clase 9

29 Lectores-Escritores en ADA.
Implementación de Lectores-Escritores TASK TYPE Scheduler IS ENTRY InicioLeer; ENTRY FinLeer; ENTRY InicioEscribir; ENTRY FinEscribir; END Scheduler; TASK BODY Scheduler IS NumLectores: INTEGER:=0; Programación Concurrente Clase 9

30 Lectores-Escritores en ADA.
BEGIN LOOP SELECT WHEN InicioEscribir'COUNT = 0 => ACCEPT InicioLeer DO NumLectores:= NumLectores+1; END InicioLeer; OR ACCEPT FinLeer DO NumLectores:= NumLectores -1 ; END FinLeer; Programación Concurrente Clase 9

31 Lectores-Escritores en ADA.
WHEN NumLectores=0 => ACCEPT InicioEscribir; ACCEPT FinEscribir; FOR i IN 1..InicioLeer'COUNT LOOP ACCEPT InicioLeer DO NumLectores:= NumLectores +1; END InicioLeer; END LOOP; END SELECT; END Scheduler; Programación Concurrente Clase 9

32 Remote Procedure Call En RPC los programas se descomponen en módulos que contienen procesos y procedimientos. Los módulos pueden residir en espacios de direcciones distintos. Los procesos de un módulo pueden compartir variables y llamar a procedures declarados en ese módulo. Un proceso en un módulo puede comunicarse con procesos de otro módulo invocando procedimientos de éste. Los módulos tienen especificación e implementación de procedimientos. Programación Concurrente Clase 9

33 Remote Procedure Call module Mname headers de procedures visibles body
declaraciones de variables código de inicialización cuerpos de procedures visibles procedures y procesos locales end Programación Concurrente Clase 9

34 Remote Procedure Call El header de un procedure visible tiene la forma: op opname (formales) returns result El cuerpo de un procedure visible es contenido en una declaración proc: proc opname(identif. formales) returns identificador resultado variables locales instrucciones end Un proceso (o procedure) en un módulo llama a un procedure en otro ejecutando: call Mname.opname (argumentos) Para un llamado local, el nombre del módulo se puede omitir. Programación Concurrente Clase 9

35 Sincronización en RPC La implementación de un llamado intermódulo es distinta que para un llamado local: un nuevo proceso sirve el llamado. El proceso llamador se demora mientras el proceso servidor ejecuta el cuerpo del procedure que implementa opname. Si el proceso llamador y el procedure están en el mismo espacio de direcciones, es posible evitar crear un nuevo proceso. En general, un llamado será remoto se debe crear un proceso server o alocarlo de un pool preexistente de servers. Programación Concurrente Clase 9

36 Sincronización en RPC Por sí mismo, RPC es solo un mecanismo de comunicación. Aunque un proceso llamador y su server sincronizan, el único rol del server es actuar por invocación del llamador (es como si el llamador mismo estuviera ejecutando el llamado, y así la sincronización entre el llamador y el server es implícita). Necesitamos que los procesos en un módulo sincronicen (procesos server ejecutando llamados remotos y procesos del módulo). Esto comprende exclusión mutua y sincronización por condición. Programación Concurrente Clase 9

37 Sincronización en RPC Existen dos enfoques para proveer sincronización, dependiendo de si los procesos en un módulo ejecutan con exclusión mútua (un solo proceso por vez) o concurrentemente. Si ejecutan con exclusión mútua las variables compartidas son protegidas automáticamente contra acceso concurrente, pero los procesos necesitan programar sincronización por condición. Si pueden ejecutar concurrentemente necesitamos mecanismos para programar exclusión mutua y sincronización por condición (cada módulo es en sí mismo un programa concurrente  podemos usar cualquier método ya descripto (semáforos, monitores, o incluso rendezvous). Programación Concurrente Clase 9

38 Sincronización en RPC Es más general asumir que los procesos pueden ejecutar concurrentemente (puede ser mucho más eficiente en un multiprocesador de memoria compartida). Asumiremos que los procesos dentro de un módulo ejecutan concurrentemente, utilizando por ejemplo time slicing. Por ahora, usamos semáforos para programar exclusión mutua y sincronización por condición; Se verá luego el agregado de rendezvous y comunicación guardada. Programación Concurrente Clase 9

39 Ejemplo con RPC: Time Server
Módulo que provee servicios de timing a módulos cliente. Dos operaciones visibles: get_time y delay( interval ) Un proceso interno que continuamente inicia un timer por hardware, luego incrementa el tiempo al ocurrir la interrupción de timer. module TimeServer op get_time( ) returns INT; #recupera la hora del día op delay(INT interval ); #intervalo entre ticks body INT tod = 0; #hora del día SEM m= 1; # semáforo para exclusión mútua SEM d[n] = ([n] 0); # semáforos de demora privados QUEUE of (INT waketime, INT proces_id) napQ; proc get_time ( ) returns time { time := tod; } Programación Concurrente Clase 9

40 Ejemplo en RPC: Timer Server
proc delay(interval) { # asumimos interval > 0 INT waketime = tod + interval; P(m) insert (waketime, myid) en el lugar apropiado de napQ; V(m); P(d[myid]); # espera a ser despertado } Process Clock { Inicia timer por hardware; WHILE (true) { Esperar interrupción, luego rearrancar timer; tod := tod + 1; P(m); WHILE tod  menor waketime en napQ { remove (waketime, id) de napQ; V(d[id]); #despierta el proceso Id end TimeServer; Programación Concurrente Clase 9

41 Ejemplo en RPC: Timer Server
Múltiples clientes pueden llamar a get_time y a delay a la vez  múltiples procesos “servidores” estarían atendiendo los llamados concurrentemente. Los pedidos de get_time se pueden atender concurrentemente porque sólo significan leer la variable tod. delay y clock necesitan ejecutarse con exclusión mutua porque ambos manipulan napQ, la cola de procesos cliente "durmiendo”. El valor de myid en delay se supone que es un entero único entre 0 y n-1. Se usa para indicar el semáforo privado sobre el cual está esperando un cliente. Programación Concurrente Clase 9

42 Manejo de caches en un sistema de archivos distribuidos con RPC.
Supongamos un sistema distribuido con n workstations ejecutando procesos, y una base de datos con archivos en un file server. Los programas de aplicación que quieren acceder a datos del file server, llaman procedimientos read y write de un módulo local que llamaremos FileCache. Se supone que se leen o escriben arreglos de caracteres. Los archivos están almacenados en el FileServer en bloques de 1024 bytes, fijos. El módulo FileServer provee el servicio de lectura y escritura de bloques con los procedimientos ReadBlk y WriteBlk. El módulo FileCache mantiene en memoria los bloques recientemente leídos. Un read puede ser atendido “localmente” o no. Idem con las operaciones de Write. Cuando no se pueden atender localmente se produce la comunicación con FileServer. Programación Concurrente Clase 9

43 File Cache con RPC. Module FileCache # ubicado en cada workstation
op read (INT count ; result CHAR buffer[ *] ); op write (INT count; CHAR buffer[*] ); body declaración del cache de N bloques de archivo; variables para la descripción de los registros de cada file; declaración de los semáforos para sincronización de acceso al cache; proc read (count, buffer) { IF (los datos pedidos no están en el cache) { seleccionar los bloques del cache a usar; IF (se necesita vaciar parte del cache); FileServer.writeblk(....); FileServer.readblk(....); } buffer= número de bytes requeridos del cache; Programación Concurrente Clase 9

44 File Cache con RPC. proc write(count, buffer) {
IF (los datos apropiados no están en el cache) { seleccionar los bloques del cache a usar; IF (se necesita vaciar parte del cache); FileServer.writeblk(....); } bloquedeCache= número de bytes desde buffer; end FileCache; Notar que los llamados de los programas de aplicación de las Workstations son locales a su FileCache, pero desde estos módulos se invocan los procesos remotos de FileServer. FileServer tiene UN cliente por workstation. Programación Concurrente Clase 9

45 Manejo de caches en un sistema de archivos distribuidos con RPC.
Si existe un FileCache por programa de aplicación, no se requiere sincronización interna entre los read y write, porque sólo uno puede estar activo. Si múltiples programas de aplicación usaran el mismo FileCache, tendríamos que usar semáforos para implementar la exclusión mútua en el acceso a FileCache. En cambio en el FileServer (atiende múltiples FileCache) requeriremos sincronización interna. También con el proceso DiskDriver. A continuación se ve el código (simplificado) del FileServer con RPC. Programación Concurrente Clase 9

46 File Server con RPC. Module FileServer # ubicado en el servidor
op readblk (INT fileid, offset; result CHAR blk[1024] ); op writeblk (INT fileid, offset; CHAR blk[1024] ); body declaración del cache de bloques del disco; cola de pedidos pendientes de acceso al disco; declaración de semáforos para acceso al cache y a la cola; # a continuación no se ve el código de sincronización. proc readblk (fileid, offset, blk) { IF (los datos pedidos no están en el cache) { almacenar el pedido de lectura en la cola del disco; esperar que la operación de lectura sea procesada; } blk= bloques pedidos del disco; Programación Concurrente Clase 9

47 File Server con RPC. proc writeblk (fileid, offset, blk) {
Ubicar el bloque en el cache; IF (es necesario grabar físicamente en el disco) { almacenar el pedido de escritura en la cola del disco; esperar que la operación de escritura sea procesada; } bloque cache = blk; process DiskDriver { WHILE (true) { wait por un pedido de acceso físico al disco; arrancar una operación física; esperar interrupción; despertar el proceso que está esperando completar el request; end FileServer; Programación Concurrente Clase 9

48 RPC programando filtros o interacción entre pares
El problema de construir una red de filtros (por ejemplo para el sorting by merging) es algo más complicado con RPC que con mensajes. Esto se debe a que no es un problema “tipo Cliente-Servidor”. Pueden analizar la solución en el texto de Andrews. El intercambio de valores entre pares, por ejemplo el problema que resolvimos en clases anteriores con mensajes asincrónicos resulta algo más “pesado” con RPC. Queda para el alumno pasar la solución con AMP a RPC. Programación Concurrente Clase 9


Descargar ppt "Qué vimos la clase pasada?"

Presentaciones similares


Anuncios Google