aic2tema5

Parallel Virtual Machine
Índice
5.1. Características de PVM 5.2 Arquitectura de PVM 5.2.1 Modelo de computación 5.2.2 Modelo de implementación 5.2.3 Arranque y configuración de PVM 5.2.4 Construcción de la máquina virtual (interioridades). 5.3 Modelo de comunicación. 5.3.1 Mensajes. 5.3.2 Tarea – demonio. 5.3.3 Demonio – demonio. 5.3.4 Etapas de un mensaje. 5.4 Programación de aplicaciones en PVM 5.4.1 Interfaz de usuario de PVM 5.4.2 Funciones para el control de procesos 5.4.3 Funciones de información 5.4.4 Funciones de configuración dinámica de la máquina virtual 5.4.5 Funciones de señalización 5.4.6 Funciones de control de buffers 5.4.7 Funciones de empaquetado/desempaquetado de datos. 5.4.8Funciones para envío y recepción de mensajes. 5.4.9 Funciones para operaciones colectivas 5.5 Ejemplos 5.5.1 Padre-Hijo 5.5.2 Envío de mensajes 5.5.3 Uso de grupos 5.5.4 Información de la PVM 5.5.5 Producto escalar de dos vectores 5.5.6 Producto de dos matrices cuadradas

1

5.1 Características de PVM
● ● ● ●

SW de dominio público desarrollado por el Oak Ridge National Laboratory. Computación basada en procesos. Modelo basado en paso de mensajes. Heterogeneidad a nivel de computadores, redes y aplicaciones.

● ● ●

● ●

Existe la posibilidad de asignar explícitamente tareas a computadores concretos. Los computadores de la máquina virtual pueden ser multiprocesadores de memoria distribuida o compartida. Escalabilidad. ○ Inclusión/ eliminación de forma dinámica. ○ Se puede configurar en una aplicación una submáquina virtual dentro de la máquina virtual. Tolerancia a fallos. ○ No proporciona tolerancia a fallos de forma implícita en una aplicación. ○ El programador es el responsable de diseñarla en el programa. Dominio público. ○ Versión actual: 3.4.4 Bajo coste. ○ SW gratuito. ○ HW: cualquier computador con versiones Linux/PVM. Portabilidad.

Entornos donde se ha instalado PVM MODELO DE COMPUTADOR ORDENADORES PERSONALES SISTEMA OPERATIVO -------------------------------------------------------------------------------WinNT, Linux, Solaris, SCO, NetSBD, BSDI, FreeBSD, NetBSD -------------------------------------------------------------------------------OSF, NT-Alpha, HP-UX, AIX 3.x, AIX 4.x, IRIS 5.x, IRIS 6.x, SunOS, Solaris 2.x -------------------------------------------------------------------------------2

Pentium II, Pentium PRO, Pentium Duals y Quads, AMD, Apple Macintosh ESTACIONES DE TRABAJO Y SISTEMAS DE MEMORIA COMPARTIDA DEC Alpha, Pmax, Microvax, HP 9000, IBM RS6000, J30, SGI, SUN3, SUN4, SPARC, Ultra SPARC COMPUTADORES PARALELOS

Cray YMP T3D T3E, Cray2, Convex Exemplar, IBM SP2, 3090, NEC SX-3, Fujitsu, Amdahl, TMC CM5, Intel Paragon, Sequent, Symmetry, Balance

5.2 Arquitectura de PVM
● Cada tarea puede enviar un mensaje a cualquier otra tarea PVM ○ No existen límites en el número y tamaño de los mensajes. ○ Factor condicionador ==> memoria disponible en cada computador. Envío asíncrono sin bloqueo ○ Devuelve el control a la tarea tan pronto como el buffer de envío esté libre para ser utilizado de nuevo con independencia de que el destinatario haya realizado una llamada a la función de recepción. Recepción asíncrona con/sin bloqueo. ○ Una recepción no-bloqueante devuelve el control a la tarea con independencia de la llegada de los datos. ○ Existe un flag que permite determinar qué ha ocurrido en la recepción. ○ La recepción bloqueante no devuelve el control a la tarea en tanto no se produzca la llegada de los datos al buffer de recepción. Se garantiza el orden de los mensajes. ○ Modificación del orden mediante las funciones de filtrado. Difusión de mensajes en modo broadcast. ○ Mismo mensaje a un grupo de tareas. Grupos dinámicos de tareas. ○ Identificador de grupo. ○ Formar parte de diferente grupos. ○ Entrada y salida dinámica. ○ Sincronización de barrera y envío de mensajes en modo broadcast. Envío de señales y eventos asíncronos. ○ Ej.: despertar a una tarea para recibir un mensaje, notificar situaciones anómalas. ○ La recepción de eventos sólo se puede dar en: conclusión de una tarea, y eliminación/inclusión de un computador en la máquina virtual.

● ● ●

5.2.1 Modelo de computación
a. Paralelización de una aplicación según la similaridad de sus tareas: a. MPMD o paralelismo a nivel funcional: i. Cada tarea realiza una función diferente (entrada de datos, resolución del problema, presentación de resultados...) ii. ¿Cómo se obtiene el paralelismo? 1. Ejecutando diferentes tareas de forma concurrente. 2. Estableciendo entre alguna de ellas una segmentación o pipeline a nivel de datos. b. SPMD: i. Cada tarea ejecuta el mismo código pero sobre un subconjunto diferente de datos. b. Paradigmas algorítmicos de paralelización desde el punto de vista de la estructuración de las tareas: a. Fases paralelas: i. Sucesión de un número indeterminado de fases para alcanzar la solución. ii. Cada fase tiene dos etapas: cálculo e interacción.

3

4 . Las tareas de la aplicación se comportan como etapas de una segmentación virtual a través de la cual los datos circulan de forman continua.Suma de números (Segmentación) Código básico para el procesador PI recv(&accumulation. accumulation=accumulation+number. Y el último proceso Pn-1. Segmentación (pipeline) i. EJEMPLO . que es: recv(&number.b. Pn-2). send(&accumulation. Excepto para el primer proceso P0: send(&number. Pi+1). Pi-1). P1). accumulation=accumulation+number.

2. Generación totalmente arbitraria de la estructura de las tareas en función de la carga de trabajo a procesar 5. Tarea maestra 1. e.a. conversión de datos y oculta la estructura de red al programador. Parte secuencial del algoritmo 2. administra los mecanismo de sincronización. transmitir mensajes entre ellas y alterar las propiedades o configuración de la máquina virtual. recoge los resultados y realiza (si hay) funciones de sincronización Variantes ii. ○ Estos ficheros son tres: libpvm3. 2.) ii.. ○ Acepta como parámetro opcional un fichero con la configuración. Biblioteca de desarrollo (API): ○ Contiene funciones para operar con las tareas. Maestro-esclavo (host-node) i.2 Modelo de implementación ● Demonio (pvmd3): ○ Instalado en todos los computadores de la máquina virtual. 5 ● ● . Difícil balancear adecuadamente la carga d. El padre puede tener que procesar la parte que le corresponda de la carga de trabajo. libfpvm3.a. Arborescente i. Un hijo cuando concluye puede recibir más carga del padre y continuar trabajando. Adecuado para problemas en los que la carga de trabajo se desconoce a priori (algoritmos recursivos o de clasificación.a. Lanza e inicializa las tareas esclavas. libgpvm3. ○ Gestiona y ejecuta las aplicaciones PVM en la máquina virtual. Híbrido i..c. comunicación. ○ Toda aplicación se debe enlazar con los ficheros de la biblioteca. 1. Consola de PVM.

Muestra en pantalla argumento. mstat tarzan 6 . Muestra la configuración de la máquina virtual alias h help conf delete host_1. Sin argumento lista todos los comandos que se pueden utilizar en la consola. No se puede eliminar la máquina desde la que se está utilizando la consola. o host_file fichero de configuración. Es la forma recomendada para detener el sistema ya que asegura una salida ordenada.pvmrc SINTAXIS SIGNIFICADO EJEMPLO add host_1.3 Arranque y configuración de PVM Hay cuatro formas de arrancar PVM en Linux: . Imprime el identificador (TID) de la tarea consola.Ejecutando de forma directa el demonio (pvmd3) pvm [-n host_name] [host_file] xpvm [-n host_name] [host_file] pvmd3 [-n host_name] [host_file]& o –n host_name permite especificar un nombre alternativo para la máquina en la que se arranca el demonio en caso de que estén instaladas varias tarjetas o interfaces de red.. delete tarzan echo argumento echo hola mundo halt Mata (elimina) a todos los procesos y demonios PVM incluyendo la consola y detiene la máquina virtual. Los procesos que se encuentren funcionando en esos computadores son eliminados. 5.host_n Incorpora los computadores host_1 a host_n a la máquina virtual.. Sin parámetros. add tarzan alias atajo comando Define un atajo o alias para escribir un comando. kill 40003 mstat host Muestra el estado del computador host.. help comando Muestra todas las opciones disponibles para comando.. Permite modificar de forma interactiva la máquina virtual que previamente ha sido definida por el demonio mediante el fichero de configuración. Versión gráfica de la consola: xpvm. Visualiza un listado de los trabajos en ejecución.Desde la consola gráfica (xpvm) . help halt id jobs kill tid Se utiliza para matar una tarea PVM mediante su identificador. lista los existentes.Desde un programa (función pvm_start_pvmd Antes de visualizar la consola se produce la lectura del fichero $HOME/.2.○ ○ ○ Proporciona una interfaz simple entre el usuario y el demonio.host_n Elimina los computadores host_1 a host_n de la máquina virtual. .Desde la consola (pvm) .

limpia los buffers de envío y recepción de mensajes. 7 . Cierra la consola dejando la máquina virtual funcionando. se utiliza el login empleado en la máquina en que se inició la ejecución de PVM. ps ps ps ps -a -h40003 -nlinda. inicializa las tablas internas de PVM y deja a los demonios en estado de espera.ps opciones Lista todos los procesos que se ejecutan en la máquina virtual. ○ Contiene los computadores que en el futuro pueden añadirse desde consola. ○ Sintaxis: ■ nombre_computador opcion_i=valor_i ● Manualmente desde Consola (add) ○ No permite incluir opciones ○ Salvo que se hayan especificado antes en el fichero de configuración (&) OPCIONES lo=nombre_usuario SIGNIFICADO Permite indicar un nombre de usuario (login) alternativo para realizar la conexión remota al computador.es -x pstat tid Imprime por pantalla el estado de la tarea cuyo identificador es tid. -hhost_tid: Información de los procesos del nodo que tenga como TID host_tid. setenv sig n_señal tid Envía la señal n_señal a la tarea cuyo identificador es tid.uned.pvmrc Hay dos formas de configurar PVM: ● Fichero de configuración ○ Contiene la lista de los computadores que forman la máquina virtual. -nhost_name: Información de los procesos que del nodo con el nombre host_name -x: Información de todos los procesos. Por defecto. ○ Cada usuario puede tener su propio fichero de configuración. pstat 40003 quit reset Mata todas las tareas PVM salvo las consolas que se encuentren en ejecución. Muestra su localización. sig 15 40003 alias ? help alias ayuda help alias stop halt alias exit quit alias depurar trace echo Configuración actual máquina virtual conf echo Versión de PVM version echo TID de la consola id add blancanieves add sabio Ejemplo de fichero . Las opciones que posee son: -a: Información de todos los procesos. Visualiza las variables de entorno del sistema. incluida la consola. su identificador y el de la tarea padre.

Por defecto. Se puede indicar una ruta absoluta o relativa con respecto al directorio home del usuario en la máquina remota seguido del nombre del demonio (por defecto. Si no se especifica esta opción. las RPC (Remote Procedure Calls) están activadas.es. Por defecto se ejecutan en el directorio $HOME.so=pw Provoca que el demonio de la máquina en la que se inició la ejecución de PVM solicite una contraseña para poder acceder a la máquina remota. Hay que utilizar un nombre y no una dirección IP ya que el valor se pasa al comando rsh y a la función rexec(). la máquina virtual buscará las aplicaciones en la ruta $HOME/pvm3/bin/PVM_ARCH siendo PVM_ARCH el nombre de la arquitectura de la máquina considerada. pvmd3). además. Es la opción adecuada para poder utilizar la instalación personal de un usuario. Esta opción es la adecuada si no se pueden utilizar rsh y rexec() pero existe comunicación IP entre el maestro y el esclavo. ip=nombre_de_ordenador Cuando existen varios interfaces o tarjetas de red. Sin embargo. # Ejemplo de fichero de configuración blancanieves sabio so=pw mudito dx=/url/local/bin/pvmd3 lo=lengua lloron ep=/home/ejecutables:~/bin cascarrabias lo=tozudo # Computadores que pueden añadirse #posteriormente con el comando add 8 .dia.es:msanchez): teniendo que introducir la contraseña del usuario msanchez en el computador tarzan. sp=valor_numerico Permite especificar la potencia del computador en relación con las demás máquinas que constituyen la máquina virtual. Esto sólo funcionará si en la máquina remota aparece el nombre del computador local en el fichero . so=ms Implica que en esta máquina el demonio debe ser arrancado de forma manual. esta opción permite seleccionar un nombre de entre los que maneja la máquina. Al procesar el demonio esta opción se obtendrá por pantalla el mensaje: Password (tarzan. PVM utiliza el comando rsh para iniciar los demonios pvmd3 remotos. dx=ubicacion_del_demonio Permite establecer al demonio en la máquina remota en una ubicación diferente a la que se utiliza por defecto.equiv del sistema y. el arranque de la máquina continuará normalmente.uned. El empleo de esta opción provoca el establecimiento de un diálogo a través de la consola con el maestro. Tras esto. wd=directorio_de_trabajo Permite indicar el directorio de trabajo en el que se van a ejecutar todas las tareas que sean lanzadas. Cuando se recurre a esta opción no se puede arrancar la PVM desde la consola o como tarea de fondo ya que el demonio solicita la entrada de datos a través del teclado. El uso de esta opción no es muy habitual. El valor numérico debe ser entero y estar en el rango [1 – 1000000]. cuando se especifica esta opción el demonio maestro recurre a la función rexec() para la creación de la tarea remota. el cual irá proporcionando por consola las instrucciones necesarias para arrancar de forma manual el demonio.uned.rhosts del usuario o en el fichero /etc/host. El valor por defecto es 1000. ep=ubicaciones_de_ejecutables Conjunto de rutas separadas por el carácter : en las que se encuentran los ficheros que se van a utilizar.dia.

. 9 ● ● ● ● .. ○ Cada demonio tiene una copia de la host table. Mediante la función rexec(): ○ Se encuentra compilada como parte del código de pvmd3.uid (registro de errores).dia. ■ Este proceso de arranque se realiza por el proceso shadow pvmd o pvmd’ (proceso hijo del maestro realizada mediante la llamada al sistema fork()).uned. ○ Entrada host descriptor: ■ hay una por cada uno de los computadores que foman la máquina virtual.es so=pw &penelope. ■ pvmd.2.ucm. ■ $HOME/.rhosts: contiene todos los nombres de los computadores que componen la máquina virtual. ○ Sin necesidad de contraseñas: ■ /etc/hosts.&ulises. ■ No se puede usar para la inclusión dinámica. ○ Reclama al usuario el empleo de una contraseña en tiempo de ejecución. Creación de los demonios esclavos: ○ Manualmente (opción so=ms del host_file). El esclavo mata a todas las tareas que dependan de él mediante el envío de la señal SIGTERM y remite un mensaje a los restantes demonios para que lo eliminen de sus copias de la host table. La tabla del host. ○ Arranca a los demonios esclavos según el host_file. ○ ¿Por qué se puede producir la actualización? ■ Al añadir un nuevo esclavo a la máquina virtual. El maestro se encarga de actualizar la host table y enviar la taba actualizada mediante broadcasting a todos los esclavos.es wd=/home/pruebas/ Ejemplo de fichero de configuración # Ejemplo de fichero de configuración con #opciones por defecto * lo=aqueo dx=/url/local/bin/pvmd3 patroclo aquiles # Redefinición de una de las opciones por #defecto * lo=troyano hector paris Ejemplo de fichero de configuración con opciones por defecto 5. ■ Eliminación de un esclavo desde el maestro.mat. Mediante el comando rsh(): ○ Tienen que estar activos los servicios RPC (demonio rshd). ● uid: identificador numérico del usuario que ejecuta el demonio. ■ Eliminación autónoma por parte de un esclavo de una entrada cuando observe que una máquina es inalcanzable (tiempo de confirmación). sea abortado.es lo=laertes &telemaco. sea cancelado por el envío de una señal UNIX. ■ Permite acceder a la información de configuración del computador y de los buffers de mensajes.equiv: contiene todos los nombres de los computadores que componen la máquina virtual. ■ Un demonio sea dado de baja de forma local. El maestro envía un mensaje a todos los esclavos indicando la máquina que ha causado la baja. ○ Contiene información de los computadores que forman la PVM. ■ Suele usarse si los servicios RPC están deshabilitados pero existe conectividad entre las máquinas mediante TCP/IP.uned. ○ Cada demonio arranca en el directorio /tmp dos ficheros: ■ pvm1.uid (nº ip y puerto de escucha).4 Construcción de la máquina virtual ● Arranque del demonio maestro: ○ Es el que arranca en primer lugar (4 formas descritas).

0 1 1.. virtual...262143 Identificador de una tarea.. 1 0 0 0 Identificador del demonio local a la tarea.262143 Dirección multicast. L (Local field). ○ L: identifica a una tarea dentro de cada uno de los computadores de la máq. Es posible disponer de hasta (212 −1)= 4095 computadores en una máquina virtual..● Identificador de una tarea (TID) ○ Cada tarea. 1 0 1. G H L S 31 30 29 18 17 0 S G H L SIGNIFICADO 0 0 1.4095 1. 1 1 Número negativo Número negativo Condición de error.. H (Host field). grupo de tareas y demonios poseen un TID único..4095 1.. 10 .. ○ Campos: S (Server bit).. Pueden coexistir hasta (218 −1)= 262143 en cada computador. 1 0 0 0 Identificador del shadow daemon en la máquina maestra.4095 0 Identificador de un demonio. ○ H: almacena el host descriptor. G (Group bit).

5. ○ Servicio seguro (mensajes de confirmación).2 Tarea-demonio: ● Se realiza a través de sockets TCP. Formato de las cabeceras de los paquetes: ○ SOM (Start Of Message). 5. SOM=1: primer mensaje. EOM=1: último mensaje. 5. Este número se envía al demonio destino y se devuelve con la respuesta. El waitc sirve para que el demonio local cuando reciba la conformidad del demonio destino pueda recuperar el contexto en que se encontraba y saber qué tarea fue la originaria. ■ Checksum: para control de errores. ■ Código: nº entero que define el tipo de mensaje (filtrado). Se puede selecionar en la compilación que los sockets sean Unix en lugar de TCP (más rápido).3 Modelo de comunicación ● Tipos de comunicación que coexisten en la PVM: ○ Indirecta entre dos tareas (opción por defecto): ■ Entre un demonio y una tarea (TCP) ■ Entre demonios (UDP) ○ Directa entre dos tareas (TCP) Hay que compilar PVM con la opción.3. ○ EOM (End Of Message). ■ Wait context ID (waitc): lo genera el demonio cuando recibe una petición de servicio por parte de una tarea local. No se usa. ● 11 . ○ Cabecera: información de control. ○ SOM=EOM=0 ==> fragmento intermedio.3. ○ Comunicación a nivel local ==> coste de creación y cierre relativamente bajo.1 Mensajes ● Partes del mensaje: ○ Cuerpo: información útil (datos del problema) que se intercambian las tareas. ■ Codificación: indica la clase de empaquetamiento.

Ambos bits activos: piggybacking. CT: cabecera tarea. 12 . ○ Bajo número de conexiones. DAT=0 . ○ Empleo de timers del nivel UDP para detectar problemas en las comunicaciones o los demonios. CDD: cabecera demonio-demonio.3. PVM envía un paquete de ACK (ACK=1.5. ACK: cabeceras con ACK=1.3. ○ DAT: indica que el paquete contiene datos válidos y debe ser entregado a la tarea. ○ ACK: indica que el número del paquete del que se confirma su recepción es válido. DAT=0) por cada fragmento de datos recibido (ACK=0.4 Etapas de un mensaje ● ● ● ● ● ● M: mensaje Mn: partes en que se descompone M. CTD: cabecera tarea – demonio. ● 5. ○ Coste de creación de sockets UDP más bajo que los de TCP.3 Demonio-demonio: ● Protocolo UDP. ○ FIN: provoca el cierre ordenado del proceso de comunicación entre los demonios. Cabecera del paquete: ○ SOM y EOM: determinan los paquetes que delimitan el comienzo y final de un mensaje. DAT=1).

Control de buffers: limpiar buffer de envío. ● ● ● 5.uid del demonio maestro. ■ Se generan varias copias con el comando spawn.4. crear un buffer. 13 . ○ API de PVM. Señalización: permiten dotar a la máquina virtual de la funcionalidad necesaria para poder construir aplicaciones paralelas tolerantes a fallos. C++ y FORTRAN.1 Interfaz de usuario de PVM ● ● ● ● ● ● ● ● ● http://www.5. ○ Aplicación lanzada desde la consola: la salida irá al fichero /tmp/pmd1. ○ Programa maestro y esclavo: ■ El programa maestro crea tareas que ejecutan el código de los esclavos. Envío y recepción de mensajes. Operaciones colectivas. Composición de la aplicación paralela: ○ Un único programa: ■ Lanzado desde la consola. Configuración dinámica de la máquina virtual: permiten la adaptación del sistema ante determinadas situaciones.. ○ Un único programa: ■ Se desdobla en varias tareas. Salida estándar: ○ Aplicación invocada desde la línea de comandos: los resultados se escriben en pantalla. un fallo de computadores o un aumento de la carga computacional.4 Programación de aplicaciones en PVM ● Aplicación paralela basada en PVM: ○ Lenguaje de programación: C.html Control de procesos: creación y destrucción de tareas. Información: permiten obtener información sobre el estado de la máquina virtual..org/pvm2/book/pvm-book.netlib. como por ejemplo. Restricción al lanzamiento de una tarea desde la consola: la tarea no debe contener una entrada interactiva. Empaquetamiento /desempaquetamiento de datos. ■ Cada tarea ejecuta un código según la lógica del programa. establecer un buffer activo.

”ulises. (char**)0. PvmTaskDefault. tids). tids). argumentos. char **argv. es una cadena de caracteres que indica dónde crear el proceso.uned.es”. int *tids) ● task: nombre del programa PVM que va a ejecutarse. 0. ○ numt=pvm_spawn(“esclavo”. 0. char **argv. int block). 1.dia. int flag. n . ● ● ● where: cuando procede. ○ char argumentos[] = {“12”. 1. int ntask.``´´. n. ntask: nº de copias del proceso que hay que crear. tids: array con los TIDs de las tareas creadas con éxito. 0. PvmTaskArch. tids).5. Elimina hosts de la máquina virtual PVM. siendo el elemento 0 el nombre y ubicación del proceso y el último null. Arranca nuevos procesos bajo PVM.“SUN4”. Si hay errores. ○ No debe usarse para la terminación de la tarea que la invoca (pvm_exit() y exit()). 16. tids). int int numt=pvm_spawn(char *task. 14 ● ● . &tids[0]). int info=pvm_kill (int tid). int nhost. ● flag: valor entero que se emplea para especificar las opciones de creación del proceso. **hosts.2 Funciones para el control de procesos OPCIONES int info=pvm_start_pvmd(int arg. char *where. Termina tarea PVM int info=pvm_kill(int tid) ● Ejemplos de uso de la función pvm_spawn. “60”. tids) ○ numt=pvm_spawn(“esclavo”. “linda”.PvmTaskHost. char **argv. int block) int info=pvm_addhosts(char *infos) int info=pvm_delhosts(char *infos) **hosts. La ruta por defecto en que se buscan los programas es $HOME/pvm3/bin/$PVM_ARCH. 256. int SIGNIFICADO Arranca el demonio PVMD.0. (char*)0} numt=pvm_spawn(“esclavo”. ○ numt=pvm_spawn(“esclavo. 0. ○ numt=pvm_spawn(argv[0]. ○ numt=pvm_spawn(argv[0]. (char**)0. PvmTaskDefault. int nhost.4. Añade hosts a la máquina virtual PVM. PvmTaskHost. ○ Solicita la terminación del proceso que la recibe. ○ info<0==> error int info=pvm_start_pvmd (int argc. (char*)0. ● argv: puntero a un vector de argumentos que se pasa a la tarea que va a ser creada. los códigos de error se sitúan en las últimas (ntask-numt) posiciones.

15 . block: ■ block<>0: la rutina ha de esperar hasta que todos los comutadores indicados en el host_file se incorporen. int i. for (i = 0. ○ hostp: puntero a un array de estructuras del tipo pvm hostinfo que proporciona la siguiente información sobre cada computador: ■ int hi_tid: DTID del demonio. ■ int hi_speed: velocidad relativa del computador. ■ char *hi_name: array de caracteres con el nombre del computador. &taskp ). &ntask. printf("Arquitectura: %s\n". ● int tid = pvm_parent(). info = pvm_config( &nhost. &computadores ). &narch. ○ nhost: nº de computadores que forman la máquina virtual. i++) { printf("Nombre: %s\n". argv: array de parámetros que se pasan al demonio. ○ narch: nº de diferentes formatos de datos que se están utilizando. ■ DTID: solicita información de las tareas asociadas a ese demonio. ○ which ■ 0: solicita información de todas las tareas. ○ Devuelve el TID del padre o el valor PvmNoParent si el proceso no fue creado con la función pvm_spawn(). ■ int ti_tid: TID de la tarea. } Ejemplo ● int info = pvm_tasks (int which. ■ char *hi_arch: array de caracteres con el nombre de la arquitectura. ■ block=0: permite continuar la ejecución del programa.○ ○ ○ argc: nº de argumentos en argv. computadores[i].hi_arch). info = pvm_tasks( 0. narch).hi_name).4. ■ info: devuelve 0 si la rutina se ejecuta con éxito. Nombre de un host_file. ■ TID genérico para una tarea concreta. ntask. printf ("Tipos de arquitecturas que componen la PVM: %d\n". ■ char *ti_a_out: cadena de caracteres con el nombre de la tarea. ■ int ti_ptid: TID de la tarea padre.3 Funciones de información ● int tid = pvm_mytid(). printf ("Número de nodos que componen la PVM: %d\n". printf("DTID: %x\n". struct pvmhostinfo **hostp). struct pvmhostinfo *computadores. int *ntask. int i. 5. narch. ○ taskp: puntero a un array de tamaño ntask de estructuras del tipo pvmtaskinfo. i < nhost. nhost). struct pvmtaskinfo *taskp. computadores[i]. nhost. struct pvmtaskinfo **taskp). ○ Proporciona información sobre las tareas PVM que se están ejecutando en la máquina virtual. ■ int ti_host: TID del demonio bajo el que se ejecuta la tarea. ○ ntask: nº de tareas de las que se devuelve información. computadores[i]. ● int info = pvm_config( int *nhost. ■ int ti_flag: indicador del estado de la tarea. int *narch.hi_tid).

enrutamiento de los mensajes. ○ info: ■ info=nhost: todos los computadores se han añadido. taskp[i]. taskp[i]. ○ Imprime información sobre el error producido en la última llamada a una función de PVM. ==> análisis de infos. ○ Algunas opciones: impresión automática de errores. i < ntask. printf("Nombre de la tarea: %s\n". int val) ○ Rutina de propósito general para el cambio de ciertas opciones que determinan el funcionamiento de la máquina virtual.ti_ptid).. ■ 1<=info<nhost: se ha producido algún fallo.4 Funciones de configuración dinámica de la máquina virtual ● int info = pvm_addhosts (char **hosts. ○ nhost: nº de computadores a añadir. ● ● int mstat = pvm_mstat (char *host) ○ Proporciona infromación sobre el estado del computador host. int nhost. printf("TID demonio: %x\n". ○ msg: mensaje adicional que se concatena a la información generada por la rutina.ti_host). ■ info<1: no se ha añadido ningún computador. ○ infos: array con los códigos de estado de cada uno de los computadores indicados en el array hosts. i++) { printf("TID tarea: %x\n".4. taskp[i]. int status = pvm_pstat (in tid) ○ Proporciona información sobre el estado de la tarea de identificador tid. int val = pvm_getopt (int what) ○ Rutina de propósito general que permite obtener información sobre la configuración de la máquina virtual. printf("TID tarea padre: %x\n". } Ejemplo ● int info = pvm_perror (char *msg).ti_tid).printf("Total tareas en PVM: %d\n". taskp[i]. nivel de depuración. ○ hosts: array de cadenas de caracteres con el nombre de los computadores a incluir en la máquina virtual. 16 . ntask).ti_a_out). ● int oldval = pvm_setopt (int what. int *infos) ○ Rutina para la inclusión de nhost nuevos computadores en la máquina virtual.. for (i = 0. ● 5.

. int signum). int bufid = pvm_initsend (int encoding). arraytids ).6 Funciones de control de buffer ● Pasos para el envío de un mensaje de una tarea PVM: ○ Inicialización de un buffer de envío ○ Empaquetamiento del mensaje en el buffer ○ Envío del mensaje Pasos para la recepción de un mensaje por una tarea: ○ Recepción mensaje (modo bloqueante o no bloqueante). contador. se indica las veces que hay que avisar. ○ bufid: identificador del buffer activo. ○ Función que envía un mensaje a la tarea que lo invoca cuando suceden determinados eventos en un conjunto específico de tareas. % Cancelación de la notificación. tids: lista de los TIDs de las tareas y demonios que hay que observar.4. El programador puede crear más buffer pero sólo puede haber uno activo en cada instante. del array cuando se usan las opciones PvmTaskExit y PvmHostDelete. contador. int *infos) ○ Rutina para la eliminación de nhost computadores de la máquina virtual. 100. . .● int info = pvm_delhosts (char **hosts. arraytids ). . cnt: especifica la long. int *tids).4. ○ Desempaquetamiento de los datos. . . pvm_notify( PvmTaskExit | PvmNotifyCancel. Ejemplo 5. 9999. . % Establecimiento de la notificación.5 Funciones de señalización ● int info = pvm_sendsig (int tid. ● ■ ■ ■ msgtag: etiqueta del mensaje que se envía a la tarea que ha invocado la rutina. int msgtag. Inicialmente para cada tarea PVM se crea un buffer activo de envío y otro de recepción. . Cuando se usa la opción PvmHostAdd. pvm_notify( PvmTaskExit. 5. 17 ● ● ● ● . ○ Rutina para el envío de una señal signum a la tarea PVM asociada al tid. . . contador. . 9999. int cnt. . ○ Limpia el buffer de envío activo. Si se envía con éxito la seál info=0. El array está vacío si se usa la opción PvmHostAdd info = pvm_notify( PvmTaskExit. inf info = pvm_notify (int what. array_tids ). int nhost. ■ what: establece el evento al que hay que prestar atención.

int stride) ○ int info = pvm_upkXXX (YYY *datos. ■ YYY: tipo de datos C del array a empaquetar.○ encoding: indica el método de codificación. ■ stride = 2 de cada dos elementos se empaqueta 1. Formato genérico de las funciones más importantes: ○ int info = pvm_pkXXX (YYY *datos. ■ PvmDataDefault: formato XDR (adecuado para entornos heterogéneos). ■ PvmDataInPlace: en el buffer se almacenan únicamente punteros a los datos y sus tamaños. int bufid = pvm_getrbuf () ○ Devuelve en bufid el identificador del buffer activo de recepción. ○ oldbuf: valor del buffer de recepción activo antes de invocar la rutina. ● ● ● ● ● 5. Los datos han de estar en posiciones contiguas de memoria y no deben ser modificados entre el empaquetado y envío. int nitem. ○ int info = pvm_pkstr (char *cadena) ○ int info = pvm_upkstr (char *cadena) ● 18 . ○ nitem: total de elementos a empaquetar. ● int bufid = pvm_mkbuf (int encoding) ○ Crea un buffer de envío vacío. ○ stride: establece la distancia entre dos elementos consecutivos a empaquetar. int info = pvm_freebuf (int bufid) ○ Se emplea para liberar la memoria asignada al buffer bufid cuando no vaya a ser utilizado más. int oldbuf = pvm_setsbuf (int bufid) ○ Establece como buffer activo de envío el identificado por bufid. manteniendo los datos almacenados en el espacio de datos del usuario.7 Funciones de empaquetado y desempaquetado de datos ● Argumentos de las rutinas de empaquetado: ○ Puntero al primer elemento del arreglo a empaquetar. ○ Establece como buffer activo de recepción el identificado por bufid. ■ PvmDataRaw: sin codificación (sólo posible si los computadores tienen formatos de datos compatibles si no dará error en el desempaquetado). int bufid = pvm_getsbuf () ○ Devuelve en bufid el identificador del buffer activo de envío. int oldbuf = pvm_strbuf (int bufid). int nitem. int stride) ■ XXX: tipo de datos de PVM que se va a enviar. ○ oldbuf: valor del buffer de envío activo antes de invocar la rutina.4.

■ Crea un nuevo buffer de recepción activo para el mensaje que llega. 19 . ○ pvm_nrecv (): recepción no bloqueante.4. Estas rutinas conllevan el empaquetamiento/envío o desempaquetamiento/recepción. ● b) Datos a enviar son del mismo tipo: ○ Se emplea pvm_psend() y pvm_precv(). ○ pvm_send (): envío no bloqueante.8 Funciones para el envío y recepción de mensajes ● a) Datos a enviar son de distinto tipo: ○ Necesariamente tienen que ser empaquetados antes de ser colocados en un buffer de envío de PVM. ○ pvm_recv (): recepción bloqueante.5.

○ info = pvm_send( tid. ○ Valores del argumento type: ● 20 . 10. void *buf. 1). int msgtag. -1) int info = pvm_psend (int tid. int type).● c) Modos de empaquetamiento de datos de PVM: ● ● d) Descripción de las rutinas: int info = pvm_send (int tid. int len. int msgtag) ○ info = pvm_initsend (PvmDataDefault). ○ info = pvm_pkint( array.

etiqueta = 4.● int info = pmv_mcast (int *tids. bufid = pvm_nrecv( tid. ? ● int bufid = pvm_recv (int tid. info = pvm_upkfloat (array. ntask. -1). 1). if (recibido) bufid = pvm_recv(tid. -1). info = pvm_mcast( tids. ○ Rutina no-bloqueante que sólo devuelve un identificador del buffer en el bufid como notificación de que el mensaje ha llegado. 1. if (bufid){ info = pvm_upkint (tids. etiqueta = 5. int msgtag). int bufid = pvm_nrecv( int tid. else 21 ● ● ● . tid = pvm_parent (). info = pvm_upkint( tids. 100. 10. int bufid = pvm_probe (int tid. bufid = pvm_recv( tid. 1. struct timeval *timeout) ○ Permite fijar un tiempo máximo de espera para la recepción del mensaje. int ntask. int msgtag. 10. } else /*Realizar otras operaciones */ ? int bufid = pvm_trecv (int tid. ○ Si el mensaje no ha llegado a la tarea receptora la rutina devuelve 0. etiqueta). recibido = pvm_probe( tid. info = upkfloat( array_entrada. 100. tid = pvm_parent(). etiqueta). 1). Si se ha producido un error en la recepción devuelve un valor inferior a 0. 1). 1). tid = pvm_parent (). 1). 10. info = pvm_upkint (tam_prob. info = pvm_pkint( array. int msgtag). 1). 1). int mstag) ○ Rutina no-bloqueante que envía el mensaje previamente empaquetado en el buffer activo a un grupo de ntask tareas identificado por el array tids). info = pvm_initsend( PvmDataRaw). etiqueta). ○ msgtag ha de ser mayor o igual que 0. ○ bufid: identificador del buffer de recepción activo que ha sido creado y que contiene el mensaje recibido. int msgtag). info = pvm_upkint( tamanio_problema.

○ tid: identificador de la tarea origen del mensaje. int msgtag. int *rtag.4. o rlen: long. Biblioteca de grupos: libgpvm3. &tipo. ○ bytes: long. ○ len: tamaño del array (múltiplo del tamaño del tipo de datos). int type. Si n es el nº de tareas dentro del grupo.9 Funciones para operaciones colectivas ● ● ● ● ● PVM Group Server (pvmgs): se activa al invocarse la primera función colectiva. int *rlen) ○ tid: identificador tarea origen (comodín –1) ○ msgtag: etiqueta ○ buf: puntero al array en que almacenamos el mensaje recibido. PVM intenta rellenar huecos con los nº de instancia de los miembros del grupo que lo han abandonado. o info: éxito info=0.● /*Realizar otras operacione*/ ? int info = pvm_bufinfo (int bufid. void *buf. bufid= pvm_recv (-1. &long. fracaso info<0 5. ○ Códigos de error que pueden ser devueltos en inum: 22 . &tid) ● int info = pvm_precv (int tid. o rtag: etiqueta del mensaje recibido. int *tid) ○ Permite obtener información del mensaje almacenado en el buffer bufid. int inum = pvm_joingroup (char *group) ○ inum: instancia (nº de orden de la tarea en el grupo. int *bytes. int *rtid.a Agrupamiento dinámico: permite que existan varios grupos de tareas simultáneamente y que una tarea forme parte de varios grupos a la vez. int *mstag. ○ type: tipo de los datos del array. ○ msgtag: etiqueta del mensaje. del cuerpo del mensaje en bytes. int len. ○ Las tareas que se desunen del grupo y se vuelven a unir pueden que no obtengan el nº de instancia que tenían. info = pvm_bufinfo( bufid. Las llamadas a funciones colectivas pueden producir resultados imprevistos dependiendo de si una tarea abandona o entra en el grupo. -1). 0<=inum<=n-1. o rtid: identificador de la tarea que ha enviado el mensaje. del mensaje recibido.

info = pvm_pkint( array. int count) ○ La tarea se bloquea hasta que count miembros de group han invocado esta función. ■ count=-1 PVM usa el valor obtenido con pvm_ ■ info = 0 éxito. ○ Se puede invocar la función sin pertenecer al grupo. 10. ● int info = pvm_bcast (char *group. int inst = pvm_getinst(char *group. etiqueta). ○ Envía el mensaje almacenado en el buffer activo a todos los procesos que forman parte de group excepto a la tarea que invoca la función. Al terminar el proceso root tendrá el resultado final de la operación. ● Número de órden de la tarea Contenido del vector de datos 23 . ○ Se produce un error si las tareas que llaman a la función usan un valor de count distinto. int count. etiqueta = 5. PvmSum y PvmProduct. int *count. int rootginst) ○ No-bloqueante. ○ rootginst: instancia de la tarea root. void *y. void *data. int inum) int size = pvm_getsize (char *group) int info = pvm_barrier (char *group. PvmMax.● int info = pvm_lvgroup (char *group) ○ Códigos de error que pueden ser devueltos por info: ● ● ● ● int tid = pvm_gettid (char *group. int msgtag) ○ No-bloqueante. ○ func: función que define la operación a realizar sobre los datos. void func (int *datatype. ○ data: puntero a la dirección del array que contiene los valores locales. ○ Puede ser necesario llamar a pvm_barrier para sincronizar las tareas implicadas. info<0 errores. ○ Debe ser invocada por todas las tareas que forman el grupo. int datatype. int inum) ○ Obtiene el tid de la tarea que tiene asignado el nº inum en el grupo group. info = pvm_initsend( PvmDataRaw). int msgtag. Se pueden usar funciones definidas por el usuario. char *group. void *data. int * info) ○ y: valores recibidos de las otras tareas implicadas en la función pvm_reduce. 1). info = pvm_bcast (“grupo”. PvmMin. ○ Normalmente se usa count=(nº miembros del grupo). ○ count: nº de elemntos del array. ● int info = pvm_reduce(void (*func) ().

i< num. char *group. PVM_INT. int msgtag. una sección del array. double *x.400.3. int rootginst) ○ La tarea root envía a cada una de las tareas del grupo.222. int rootginst) ○ Rutina para que la tarea root reciba un mensaje de cada uno de los integrantes del grupo. PVM_INT. 24 . int datatype. 10.: Número de órden de la tarea 0 1 2 tarea_root = 1. int *num. incluida la que inicia el envío.4. ○ pvm_gather es no bloqueante.300.27000.50 100. int datatype.555 No definido ● int info = pvm_scatter (void *result. int count.200. for (i = 0.333. PVM_INT. 5. incluido ella. info = pvm_reduce( multiplicar. int *info){ int i.40. &datos. info = pvm_scatter(&getmyrow. Si una tarea llama a pvm_gather y abandona posteriormente el grupo antes de que la raíz haya llamado a pvm_gather puede ocurrir un error. &matriz. 5. void *data. char *group. i++) x[i]*=y[i]. } Resultado después de la op. double y.0 1 2 tarea_root = 1. Resultado después de la op. &datos.8000. etiqueta.75000 No definido Ejemplo Contenido del vector de datos No definido 111. void multiplicar( int *datataype. 1. “grupo”. msgtad. “calculador”. y recopile toda la información enviada en un único array.2. raiz) ● int pvm_gather( void *result.: Número de órden de la tarea 0 1 2 Contenido del vector de datos No definido 1000.20. tarea_root).444. int msgtag. tarea_root).500 info = pvm_reduce( PvmSum.30. msgtag. “calculador. void *data.64000.5 10. int count.

Hijos) != 2) { printf("ERROR lanzando la ejecucion de los procesos hijo\n"). } printf("Soy el proceso padre con ID: %d. parent_tid.h> int main() { int tid. int Hijos[2]. NULL. if (tid < 0) { printf("No puedo conectarme con PVM\n"). Terminamos\n"). tid).5 Ejemplos PVM 5. return 0. return 0. parent_tid=pvm_parent().h> #include <pvm3. PvmTaskDefault. if (tid < 0) { printf("No puedo conectarme con PVM\n"). parent_tid). pvm_exit(). tid=pvm_mytid().5.5.h> #include <pvm3. return -1. return -1. 0. Todo fue bien.h> #include <stdlib.h> int main() { int tid. tid). } printf("Soy el proceso padre. pvm_exit(). if (pvm_spawn("plantilla-hijo". } Fichero PADRE #include <stdio. Ahora voy a lanzar 2 hijos\n".h> #include <stdlib. return -1. tid=pvm_mytid(). de identificador %d\n". printf("El identidicador del padre es %d\n". 2. } Fichero HIJO 25 . } printf("Soy un proceso hijo. pvm_exit().1 Padre-Hijo #include <stdio. pvm_exit().

} /* Envio la informacion a un hijo */ if (pvm_send(Hijos[1]. 1. if (pvm_pkint(&temporal. NULL. int temporal. return -1. Si la comenta prueba a que */ el hijo 2 realice dos operaciones pvm_recv y vera como */ el primer dato es 1 y el segundo 2 */ (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"). return -1.h> #include <stdlib. 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"). pvm_exit(). pvm_exit().5.h> #include <pvm3. pvm_exit(). Hijos) != 2) { printf("ERROR lanzando la ejecucion de los procesos hijo\n"). pvm_exit().h> int main() { int tid. Voy a enviar un entero a cada hijo\n"). 1. tid=pvm_mytid(). pvm_exit(). } /* Colocando la informacion en el buffer */ temporal=1. 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"). Necesario porque no se borra */ Prueba a comentar esta seccion y vera como el hijo 2 */ Recibe un 1 en vez de un 2. 2. PvmTaskDefault. 26 . /* Inicializando el buffer */ if (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"). return -1. 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 2\n"). if (tid < 0) { printf("No puedo conectarme con PVM\n"). int Hijos[2]. } /* Colocando la informacion en el buffer */ temporal=2. return -1. } if (pvm_spawn("comunica-hijo". 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 1\n"). return -1. } /* Envio la informacion a un hijo */ if (pvm_send(Hijos[0]. } /* /* /* /* /* if Inicializando el buffer. } printf("Soy el proceso padre. if (pvm_pkint(&temporal. return -1.2 Envío de mensajes #include <stdio. pvm_exit(). pvm_exit(). return -1. 0. return -1.5.

1) < 0) { printf("Error al leer el primer dato de buffer y fin\n"). Terminamos\n"). return -1. 1. } printf("Soy el hijo %d y he recibido de %d lo siguiente: %d\n". pvm_exit(). int temporal. return 0. return -1. pvm_exit(). 2) < 0) { printf("Error al recibir datos. return -1. parent_tid. fin"). pvm_exit(). pvm_exit(). parent_tid. } if(pvm_recv(parent_tid. tid. parent_tid=pvm_parent().h> int main() { int tid. temporal). Todo fue bien. } Envío de mensajes MAESTRO #include <stdio. pvm_exit(). tid=pvm_mytid(). if (tid < 0) { printf("No puedo conectarme con PVM\n"). return 0.} printf("Soy el proceso padre.h> #include <pvm3.h> #include <stdlib. } if(pvm_upkint(&temporal. } Envío de mensajes HIJO 27 .

return -1. } /* Colocando la informacion en el buffer */ temporal=1.h> int main() { int tid. 2. 1. tid). tid_grupo. if (pvm_spawn("grupos-hijo". return -1. } /* Inicializando el buffer */ if (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"). pvm_lvgroup("CyP"). pvm_lvgroup("CyP"). 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 1\n"). } printf("Soy el proceso padre. pvm_lvgroup("CyP"). Soy el padre luego se que es 0 */ tid_grupo= pvm_getinst("CyP". int Hijos[2]. Hijos) != 2) { printf("ERROR lanzando la ejecucion de los procesos hijo\n"). int temporal. Creo el Grupo de nombre CyP */ if (pvm_joingroup("CyP") < 0) { printf("ERROR al crear el padre el grupo de nombre CyP\n"). return -1.h> #include <stdlib. pvm_exit(). /* Sincronismo de entrada con el grupo. } /* Soy el padre. PvmTaskDefault. Voy a enviar un entero a cada hijo\n"). 1). pvm_exit(). pvm_lvgroup("CyP"). 3) < 0) { printf("Problemas en el Padre en sincronismo de entrada al grupo\n"). pvm_exit(). pvm_lvgroup("CyP"). return -1. pvm_exit(). return -1. } /* Envio la informacion a un hijo */ if (pvm_send(pvm_gettid("CyP".5. /* Conectando con PVM */ tid=pvm_mytid().3 Uso de grupos #include <stdio. pvm_exit(). En nuestro caso somos */ /* 3: el padre y dos hijos */ if ( pvm_barrier("CyP". return -1. if (pvm_pkint(&temporal. if (tid < 0) { printf("No puedo conectarme con PVM\n"). 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"). NULL. 28 . 0. Andes de cualquier operacion con el grupo conviene estar seguros de que todos los procesos del grupo han conseguido unirse correctamente. } /* guardo mi tid en el grupo. pvm_exit().5.h> #include <pvm3. return -1.

return -1. pvm_lvgroup("CyP"). 3) < 0) { printf("Problemas en el Padre en sincronismo de salida de grupo\n"). return 0. Andes de cualquier operacion */ con el grupo conviene estar seguros de que todos los procesos del */ grupo han conseguido unirse correctamente. pvm_exit(). printf("Soy un hijo. return -1. tid). 29 . /* /* /* /* if Sincronismo de entrada con el grupo. pvm_exit(). pvm_lvgroup("CyP"). Todo fue bien. } /* Soy un hijo. /* Sincronismo de salida con el grupo. int temporal. fin"). Me uno al grupo de nombre CyP */ if (pvm_joingroup("CyP") < 0) { printf("ERROR al unise al grupo CyP un hijo\n"). En nuestro caso somos */ 3: el padre y dos hijos */ (pvm_barrier("CyP". } /* Notifico a PVM que abandono el grupo */ pvm_lvgroup("CyP"). Mi ID en PVM es %d y mi ID en el grupo %d\n". Terminamos\n"). 0). 2). return -1. 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 2\n"). return -1. } Uso de grupos MAESTRO #include <stdio. pvm_exit(). pvm_exit().} if (pvm_send(pvm_gettid("CyP".h> int main() { int tid. parent_tid=pvm_parent(). } /* guardo mi tid en el grupo */ tid_grupo= pvm_getinst("CyP". return -1.h> #include <stdlib. Andes de abandonar el grupo conviene estar seguros de que todos las operaciones entre procesos del grupo han concluido correctamente. tid_grupo). pvm_exit(). 3) < 0) { printf("Problemas en un hijo en sincronismo de entrada al grupo\n"). parent_tid. /* Notifico a PVM que abandono la maquina virtual */ pvm_exit().h> #include <pvm3. 2) < 0) { printf("Error al recibir datos. if (tid < 0) { printf("No puedo conectarme con PVM\n"). */ if (pvm_barrier("CyP". tid_grupo. return -1. tid. } if(pvm_recv(pvm_gettid("CyP". tid=pvm_mytid(). } printf("Soy el proceso padre. pvm_lvgroup("CyP"). pvm_exit().

pvm_lvgroup("CyP"). return 0. parent_tid. pvm_exit(). tid. Andes de abandonar el grupo conviene estar seguros de que todos las operaciones entre procesos del grupo han concluido correctamente. /* Sincronismo de salida con el grupo.} if(pvm_upkint(&temporal. 1) < 0) { printf("Error al leer el primer dato de buffer y fin\n"). temporal). return -1. 3) < 0) { printf("Problemas en un hijo en sincronismo de salida de grupo\n"). } Envío de mensajes ESCLAVO 30 . 1. } /* Notifico a PVM que abandono el grupo */ pvm_lvgroup("CyP"). } printf("Soy el hijo %d y he recibido de %d lo siguiente: %d\n". */ if (pvm_barrier("CyP". pvm_exit(). pvm_exit(). return -1.

struct pvmtaskinfo *taskp. pvm_initsend(PvmDataDefault).4 Información de la PVM #include <stdio. printf("\t\tTID tarea padre: %x\n". exit (0). } for (i = 0. struct pvmhostinfo *PVM.taskp[j]. tareas. info = pvm_mcast (array_tids.hi_tid). pvm_exit(). int tareas = 3. tareas_lanzadas = pvm_spawn (argv[0]. i < nhost.ti_ptid). datos.PVM[i]. printf ("\n\tARQ: %s\n". PVM[i]. narch). &ntask. printf("\t\tNombre tarea: %s\n". ntask. buffer. if (info < 0) { printf ("\nError al hacer pvm_mcast a las %d tareas. tareas_lanzadas. printf("\tTareas PVM: %d\n\n". narch. printf ("\nNúmero de nodos que componen la PVM: %d\n". exit (-1).hi_arch).ti_tid). i++) { buffer = pvm_recv (-1.hi_tid. &narch. printf ("\nError: Número de tareas debe ser mayor de 1 y menor de %d\n". i++) { printf("\nNodo %d: DTID:%x". if ((tareas < 1) || (tareas > MAX_TAREAS)) { pvm_exit (). int array_tids[MAX_TAREAS]. i++) printf ("\tTID %d: %x. (i+1). char* argv[]) { int mytid. mytid = pvm_mytid(). i. printf ("\n\tNombre: %s". printf("\t\tTID demonio: %x\n". 0. &PVM). if (tareas_lanzadas == 0) { pvm_exit (). } for (i = 0. nhost). PVM[i].5. array_tids). i < tareas_lanzadas. 0). j. int info.taskp[j].ti_a_out). PvmTaskDefault.\n". j < ntask. printf ("Tipos de arquitecturas que componen la PVM: %d\n". for (j = 0. MUERTO). array_tids[i]).5. myparent. for (i = 0. tareas. i+1.hi_name).taskp[j]. tareas_lanzadas). myparent = pvm_parent(). } info = pvm_config( &nhost. if (myparent == PvmNoParent) { /* Soy el padre */ if (argc == 2) tareas = atoi (argv[1]). } } printf ("\nIniciando el asesinato de las tareas:\n").taskp[j]. j++) { printf("\t\tTID tarea: %x\n". (char**)0. i < tareas_lanzadas. 31 . nhost. MAX_TAREAS).&taskp). info = pvm_tasks(PVM[i].ti_host). ntask). tareas). printf ("Tareas PVM lanzadas con éxito: %d\n". exit(-1).h" #define USO "infor n" #define MAX_TAREAS 10 #define MUERTO 10 int main (int argc.\n".h> #include "pvm3.

exit (0). datos). exit (0). } pvm_exit(). 1). 1. pvm_send (myparent. 1). pvm_exit (). pvm_initsend (PvmDataDefault). -1). } /* Soy el hijo */ buffer = pvm_recv (myparent. pvm_pkint (&mytid.\n".pvm_upkint (&datos. MUERTO). } Información de la PVM 32 . printf ("\tTarea %x muerta. 1.

for (i = 0. i < N. 2000). Nlocal. producto_escalar.1) / N_NODOS. (char **)0. 1). 1.h> #include "pvm3. i++) { double suma_parcial = 0. N = Nlocal * N_NODOS. array_tids = (int *)malloc(N_NODOS * sizeof(*array_tids)). pvm_exit(). int N = atoi(argv[1]). } printf("Longitud vectores= %d\n".5 Producto escalar de dos vectores #include <stdio. for (i=0. struct pvmhostinfo *hostp. 1). 0. pvm_pkdouble (&vector_a[i * Nlocal]. for (i=0. exit (0). info. vector_b[i]).5. i++) printf (" %f".N).h" #define USO "padre_pe longitud_de_los_vectores" #define ESCLAVO "hijo_pe" int main(int argc. 1). } info = pvm_spawn (ESCLAVO. vector_b[i] = rand() / (float)RAND_MAX. i < N.5. printf ("Vector A: "). /* Envío de la información a los esclavos */ for (i = 0. &hostp). array_tids). N_NODOS). pvm_pkdouble (&vector_b[i * Nlocal]. narch. 1. i < N_NODOS. pvm_pkint (&Nlocal. } Producto escalar de dos vectores PADRE #include "pvm3. i++) { pvm_initsend (PvmDataDefault). for (i = 0. vector_a[i]). vector_b= (double *)malloc (N * sizeof (*vector_b)). Nlocal. N_NODOS. PvmTaskDefault. free (vector_a). 1). i++) printf (" %f". Nlocal = (float)(N + N_NODOS . free (vector_b). i < N_NODOS. double *vector_a. *vector_b. vector_a= (double *)malloc (N * sizeof (*vector_a)). char *argv[]) { int i. pvm_send (array_tids[i]. pvm_upkdouble (&suma_parcial. printf("La máquina PVM está compuesta por %d computadores\n". producto_escalar += suma_parcial. Nlocal. pvm_recv (-1.h" 33 . producto_escalar. int *array_tids. pvm_config(&N_NODOS. } /* Recepción de resultados parciales y suma total */ producto_escalar = 0. 1000). N_NODOS. N_NODOS). i++) { vector_a[i] = rand() / (float)RAND_MAX. printf("\nProducto escalar= %f con N_NODOS= %d\n". int mytid = pvm_mytid().h> #include <stdlib. printf ("\nVector B: "). &narch. i < N. free (array_tids).

Nlocal. 1). pvm_exit(). i++) suma_parcial += vector_a[i] * vector_b[i]. for ( i = 0. free(vector_b). pvm_upkdouble (vector_b. 1). *vector_b. /* Cálculo de la suma parcial */ suma_parcial = 0. 1). 1000). padre. Nlocal. 2000). double *vector_a. i < Nlocal. 1). pvm_pkdouble (&suma_parcial. pvm_upkdouble (vector_a. return 0 } Producto escalar de dos vectores HIJO 34 . suma_parcial.int main(void) { int I. free(vector_a). 1. 1. pvm_recv (padre. pvm_upkint (&Nlocal. /* Recepción de los datos del padre */ padre = pvm_parent (). vector_b = (double *)malloc( Nlocal * sizeof(*vector_b)). vector_a = (double *)malloc( Nlocal * sizeof(*vector_a)). /* Envío de resultado al maestro */ pvm_initsend (PvmDataDefault). Nlocal. pvm_send (padre.

i++) { for (j=0. PvmTaskDefault. for (m=0. k++. printf ("\n"). if (argc > 1) N = atoi(argv[1]). for (i=0. } mezcla[k] = j+1. i++) { for (j=0. k++. *mezcla. int elemento[3]. array_tids). *matriz_b. 35 .6 Producto de dos matrices cuadradas #include <stdio.\n". = 2 * (N*N*N + N*N). printf ("\n"). j<N. m. = (int *)malloc(N * N * sizeof(int)). for (i=0. j<N. m<N. for (i=0. m<N. i<N.h> #include "pvm3. j<N. mezcla_resultados = (int *)malloc(3 * N * N * sizeof(int)). *mezcla_resultados. j++) { mezcla[k] = i+1. } info = pvm_spawn (argv[0]. N_TAREAS. *matriz_c. N_TAREAS. i++) { for (j=0. char *argv[]) { int i. = (int *)malloc(N * N * sizeof(int)). j++) printf ("\t%d". k++. i<N. i<N. i++) { matriz_a[i] = (rand()/(float) RAND_MAX) * 10. Total: %d. *fila_columna. (int *)malloc(N_MEZCLA * sizeof(int)).5. j. 0. printf ("\nEjecutándose %d tareas más el padre. *array_tids. (char **)0. matriz_a[i*N+j]). k++. } printf ("Matriz B:\n").h> #include <stdlib. m++) { mezcla[k] = matriz_b[m*N+j]. info.5. m++) { mezcla[k] = matriz_a[i*N+m]. } k = 0. N_TAREAS N_MEZCLA matriz_a matriz_b matriz_c mezcla = = N*N-1.h" #define #define #define #define #define USO "mul_mat M" GRUPO "MUL" ETI_DATOS 1000 ETI_REPARTO 2000 ETI_RECOGIDA 3000 int main(int argc. matriz_b[i] = (rand()/(float) RAND_MAX) * 10. N = 3. array_tids = (int *)malloc(N_TAREAS * sizeof(int)). k. for (m=0. j++) printf ("\t%d". instancia.matriz_b[i*N+j]). N_MEZCLA. = (int *)malloc(N * N * sizeof(int)). if (pvm_parent () == PvmNoParent) { instancia = pvm_joingroup (GRUPO). } } } printf ("Matriz A:\n"). int *matriz_a. info. i<N*N. for (i=0. info+1).

N_TAREAS. i<N. i++) elemento[2] += fila_columna[i+1] * fila_columna [i+2+N]. i<3*N*N. i<N. pvm_mcast (array_tids. GRUPO. N_TAREAS). matriz_c[i*N+j]). N_TAREAS+1). PVM_INT. pvm_getinst(GRUPO. ETI_REPARTO. ETI_REPARTO. } Producto de dos matrices cuadradas 36 . } else { /* Soy el hijo */ pvm_joingroup (GRUPO). j++) printf ("\t%d". elemento[0] = fila_columna[0]. elemento[1] = fila_columna[N+1]. i++) { for (j=0. mezcla. instancia). pvm_parent())). } pvm_initsend (PvmDataDefault). j<N. elemento[1] = fila_columna[N+1]. ETI_RECOGIDA. info = pvm_gather (mezcla_resultados. 3.\n"). pvm_recv (pvm_parent(). PVM_INT. } pvm_barrier (GRUPO. GRUPO. elemento[2] = 0. elemento[2] = 0. 2*(1+N). GRUPO. info = pvm_scatter(fila_columna. i<N. pvm_parent())). 0. return -1. fila_columna = (int *)malloc ( 2*(1+N) * sizeof(int)). 1). printf ("\n"). 1). ETI_RECOGIDA. pvm_exit(). pvm_pkint (&N. matriz_c[j] = mezcla_resultados [i+2]. pvm_halt (). for (i=0 . ETI_DATOS). pvm_barrier (GRUPO. 1. info = pvm_gather (0. ETI_DATOS). elemento. 2*(N+1). for (i=0. N_TAREAS). instancia). i=i+3) { j = N * (mezcla_resultados[i]-1) + (mezcla_resultados[i+1]-1). 1. for (i=0 . } pvm_lvgroup (GRUPO). GRUPO.if (info != N_TAREAS) { pvm_perror ("No se han creado todas las tareas. N_TAREAS+1). exit(0). } printf ("Matriz C:\n"). pvm_getinst(GRUPO. pvm_barrier (GRUPO. N_TAREAS = N * N. pvm_upkint (&N. pvm_barrier (GRUPO. PVM_INT. info = pvm_scatter(fila_columna. elemento. 3. elemento[0] = fila_columna[0]. N_MEZCLA = 2 * (N * N * N + N * N). PVM_INT. for (i=0. i++) elemento[2] += fila_columna[i+1] * fila_columna [i+2+N]. pvm_lvgroup (GRUPO).

Sign up to vote on this title
UsefulNot useful