Concurrencia en JAVA JAVA es un lenguaje que tiene soporte de concurrencia, mediante Threads. Un thread es un proceso “liviano” (lightweight process) que.

Slides:



Advertisements
Presentaciones similares
2. Manejo de memoria Manejo de memoria estática
Advertisements

Computadores de alta velocidad (la lista top500).
Tabla de Contenido Concurrencia.
Ayudantía Pre-Actividad 5 Multimedios. Ayudantía Pre-Actividad 5 (1) creación de varias clases, y composición (2) manejo de threads (3) manejo de excepciones.
CJ02 – Técnicas avanzadas en java 1.4 y 5.0
LENGUAJES PARALELOS Chang y Smith (1990) clasificación:
Programando con OpenMP*
Lenguaje de programación Java
I.T.E.S.R.C. Romina Tamez Andrea Martínez Ma. De Lourdes Solís
T5-multithreading SO-Grado Q1.
Clases Extendidas La clase extendida hereda los campos y métodos de la clase de la cual extiende. La clase original se conoce como superclase y la clase.
TEMA 2 Técnicas básicas de construcción de aplicaciones distribuidas
Introducción a Programación Concurrente
Funciones. Programación, Algoritmos y Estructuras de Datos.
INFORMATICA I Funciones CLASE 13.
Conceptos de la clase anterior
Conceptos de la clase anterior
Aplicaciones Multihilo
Comunicación y sincronización entre procesos
PROGRAMACIÓN DE SISTEMAS DE MEMORIA COMPARTIDA (SMP):
Servidor de Batalla Naval.
Qué pasa cuando varios clientes tratan de conectarse al mismo teimpo a un servidor Una forma es ir atendiéndolos de a uno en un ciclo: como en el programa.
Tema 12: Programación multihilo
CI TEORIA semana 8 Subprogramas o funciones Definición de funciones.
Multiprogramación Procesos Cecilia Hernández
Unidad I Java y C++ : Similitudes y diferencias
Un hilo es un único flujo de ejecución dentro de un proceso. Un proceso es un programa ejecutándose dentro de su propio espacio de direcciones. Los.
PONNHI PONNHI Una Nueva Arquitectura Microkernel Pthreads en Espacio de Usuario José Manuel Rodríguez García Juan A. Rico Gallego Jesús M. Álvarez Llorente.
SCJP SUN CERTIFIED PROGRAMMER FOR JAVA 6. SCJP 6.0 SEMANA OCHO THREADS.
Tres Algoritmos Paralelos para Multiplicación Matriz Vector
Cobol C Pascal Fortran 5. UNIDADES DE PROGRAMAS SmallTalk Java C++
Comunicación y sincronización entre procesos Realizado por Kepa Bengoetxea Kortazar
Sincronización de Procesos Semáforos Emely Arráiz Ene-Mar 08.
Semáforos Cecilia Hernández
Ing Florencia Ferrigno Tecnicas Digitales 3
Unidad III Administración de procesos
Programación de Memoria Compartida
Comunicación entre Procesos por pase de mensajes Universidad Simón Bolívar Departamento de Computación y T.I Sistemas de operación III CI-4822 Prof. Yudith.
IET110 Sistemas Operativos P04: Exclusión Mutua Prof. Jonathan MakucSlide: 1.
Sistemas en tiempo real (STR)
Programación de Memoria Compartida
Microsoft© Visual Basic . Net.
Pablo Abrile1 Threads Lenguajes de Programación I.
Hebras Cecilia Hernández. Qué es un proceso? Consiste Espacio de direccionamiento Código a ejecutar Datos estáticos y dinámicos Pila o stack CPU: PC,
INFORMATICA III ESCUELA DE INGENIERIA ELECTRONICA DEPARTAMENTO DE SISTEMAS E INFORMATICA.
 El acceso concurrente a datos compartidos puede dar pie a inconsistencia de datos  Mantener la consistencia de los datos requiere mecanismos para asegurar.
Programming with POSIX* Threads Intel Software College.
Monitores Mecanismo sincronización de nivel más alto que semáforos Construcción a nivel de lenguaje de programación que controla el acceso a datos compartidos.
Sincronización de Procesos
Tema 9.6: Sincronización de Procesos
Universidad de Chile - Tupper 2007, Santiago - Fono/Fax: (56 2) cec.uchile.cl Módulo ECI - 11: Fundamentos de Redes de Computadores.
Programación secuencial vs programación concurrente
INFORMATICA III ESCUELA DE INGENIERIA ELECTRONICA DEPARTAMENTO DE SISTEMAS E INFORMATICA.
Materia: Técnicas Digitales 3
(agradecimiento: Ruben Weht
TEMA 2. Programación Concurrente
- 1 - Sistema Embebidos: Propiedades de los Lenguajes y SDL Agustín J. González 1s06 Se ha tomado como base el material generado por Peter Marwedel de.
CONCEPTOS FUNDAMENTALES DEL NIVEL DEL SISTEMA OPERATIVO
- 1 - Sistema Embebidos: Propiedades de los Lenguajes y SDL Agustín J. González 1s07 Se ha tomado como base el material generado por Peter Marwedel de.
Programando con Hilos POSIX* Intel Software College.
Informática III 2009 Ing. Estela D'Agostino 1 Programación secuencial vs programación concurrente Pascal, C, Fortran, Cobol Secuenciales único hilo de.
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
CARACTERÍSTICAS Es un lenguaje de programación estructurado de propósito general. Está estrechamente asociado al sistema operativo UNIX, ya que el propio.
Unidad 2 – Gestión de Procesos
Threads en Java  Threads: programas multitarea  Creación de threads  Ciclo de vida de un thread  Sincronización.
UTFSM - Sistemas Operativos
Hilos Java Profesor Elian Rojas Berrocal
Agenda  Historia  Características  Mecanismos de concurrencia  Ejemplos  Desventajas  Accesibilidad  Conclusiones  Bibliografía.
Desventajas Poco eficiente: lectura y escritura en disco es lenta Necesita otro mecanismo de sincronización para acceder a los datos Son los procesos.
Tema 1: Concurrencia con Java
Transcripción de la presentación:

Concurrencia en JAVA JAVA es un lenguaje que tiene soporte de concurrencia, mediante Threads. Un thread es un proceso “liviano” (lightweight process) que tiene un contexto privado mínimo. Cada Thread en JAVA tiene su propio contador de programa, su pila de ejecución (stack) y su conjunto de registros (working set), pero la zona de datos es compartida por todos los threads, exigiendo sincronización. A continuación se comenta una biblioteca de ejemplos en JAVA desarrollada en el 2002 por Andrés Barbieri. Todos los fuentes están disponibles en la página de la cátedra. 17-5-2004 Programación Concurrente 2004 - Clase 6

Threads en JAVA Para crear Threads existen 2 formas mostradas en los ejemplos: FoolThread.java FoolRunnable.java Estas son dos clases que muestran los pasos para la creación y ejecución de threads. La primera usa una subclase de la clase de la API llamada "Thread" y la segunda muestra una implementación de la interfaz "Runnable". Más detalles en los comentarios del código fuente. 17-5-2004 Programación Concurrente 2004 - Clase 6

Threads en JAVA Exclusión mútua implícita: El mecanismo de sincronización o exclusión mutua más básico es el provisto por la palabra clave "synchronized" declarada sobre un método sobre un conjunto de sentencias. Cada objeto tiene lo que se llama un "lock" y para ganar acceso a éste se lo hace mediante un bloque protegido por la palabra "synchronized", por lo tanto para obtenerlo deberá esperar hasta tener el acceso exclusivo el cual retendrá hasta salir del bloque. La clase ImplicitMutex muestra un ejemplo de uso. ImplicitMutex.java 17-5-2004 Programación Concurrente 2004 - Clase 6

Threads en JAVA Exclusión mútua explícita   JAVA permite la sincronización por condición con los métodos wait, notify y notifyAll que funcionan de un modo similar al “wait” y “signal” que vimos en monitores. Si bien no existen las variables "condition" los "lock" implícitos en cada objeto cumplen esta función. Los métodos son definidos en la superclase "Object" y siempre deben ser ejecutados en porciones de código "synchronized". La semántica que tienen es de SC (Signal and Continue). Ejemplos: ProtectedVar.java MonitoredVar.java 17-5-2004 Programación Concurrente 2004 - Clase 6

Threads en JAVA Lectores escritores en JAVA se puede ver en: UsefulThread.java   y la aplicación que arranca todo es: TestUseful.java Otros ejemplos que están en la biblioteca: Semaphore.java + ExplicitMutex.java (Implementación de semáforos) SyncMessageChannel.java + TestSync.java (Implementación de mensajes sincrónicos) AsyncMessageChannel.java + TestAsync.java (Implementación de mensajes asincrónicos) 17-5-2004 Programación Concurrente 2004 - Clase 6

Pasaje de mensajes en JAVA En una arquitectura distribuida tenemos pasaje de mensajes. EN particular la comunicación entre procesos proveída por TCP/IP es el protocolo más utilizado actualmente, tanto en LANs como WANs. La API de programación para TCP/IP más conocida son los sockets, introducidos por UNIX. JAVA ofrece también un conjunto de clases para implementar esta interfaz. En general se usan sockets TCP los cuales fueron concebidos para un arquitectura Cliente/Servidor, por eso los ejemplos que se mencionan. 17-5-2004 Programación Concurrente 2004 - Clase 6

Pasaje de mensajes en JAVA En la biblioteca se encuentra el código de: FindClient.java (Cliente) FIndServer.java (Servidor) Se trata de un ejemplo muy simple de interacción cliente-servidor por mensajes en JAVA. El Cliente envía una palabra y le pide al servidor que le cuente la cantidad de letras “A” de la misma, recibiendo el número como respuesta. 17-5-2004 Programación Concurrente 2004 - Clase 6

Ejemplo con Pthreads y memoria compartida Un número de threads (numWorkers) suman los elementos de una matriz compartida con size filas y columnas. Matrix ( [size], [size]) Se trata de un caso típico de paralelismo iterativo con memoria compartida. #include <pthread.h> #include <stdio.h> #define SHARED 1 #define MAXSIZE 2000 /* maximum matrix size */ #define MAXWORKERS 4 /* maximum number of workers */ pthread_mutex_t barrier; /* lock for the barrier */ pthread_cond_t go; /* condition variable */ int numWorkers; /* number of worker threads */ int numArrived = 0; /* number who have arrived */ 17-5-2004 Programación Concurrente 2004 - Clase 6

Suma paralela de los elementos de una matriz con Pthreads /* a reusable counter barrier */ void Barrier() { pthread_mutex_lock(&barrier); numArrived++; if (numArrived < numWorkers) pthread_cond_wait(&go, &barrier); else { numArrived = 0; /* last worker awakens others */ pthread_cond_broadcast(&go); } pthread_mutex_unlock(&barrier); 17-5-2004 Programación Concurrente 2004 - Clase 6

Suma paralela de los elementos de una matriz con Pthreads void *Worker(void *); int size, stripSize; /* size == stripSize*numWorkers */ int sums[MAXWORKERS]; /* sums computed by each worker */ int matrix[MAXSIZE][MAXSIZE]; /* read command line, initialize, and create threads */ int main(int argc, char *argv[ ]) { int i, j; pthread_attr_t attr; pthread_t workerid[MAXWORKERS]; /* set global thread attributes */ pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 17-5-2004 Programación Concurrente 2004 - Clase 6

Suma paralela de los elementos de una matriz con Pthreads /* initialize mutex and condition variable */ pthread_mutex_init(&barrier, NULL); pthread_cond_init(&go, NULL); /* read command line */ size = atoi(argv[1]); numWorkers = atoi(argv[2]); stripSize = size/numWorkers; /* initialize the matrix */ for (i = 0; i < size; i++) for (j = 0; j < size; j++) matrix[ i ] [ j ] = 1; 17-5-2004 Programación Concurrente 2004 - Clase 6

Suma paralela de los elementos de una matriz con Pthreads /* create the workers, then exit main thread */ for (i = 0; i < numWorkers; i++) pthread_create(&workerid[ i ], &attr, Worker, (void *) i); pthread_exit(NULL); } /* Each worker sums the values in one strip. After a barrier, worker(0) prints the total */ void *Worker(void *arg) { int myid = (int) arg; int total, i, j, first, last; /* determine first and last rows of my strip */ first = myid*stripSize; last = first + stripSize - 1; 17-5-2004 Programación Concurrente 2004 - Clase 6

Suma paralela de los elementos de una matriz con Pthreads /* sum values in my strip */ total = 0; for (i = first; i <= last; i++) for (j = 0; j < size; j++) total += matrix[ i ][ j ]; sums[myid] = total; Barrier(); if (myid == 0) { /* worker 0 computes the total */ for (i = 0; i < numWorkers; i++) total += sums[ i ]; printf("the total is %d\n", total); } 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador Un kernel o “núcleo” es un pequeño conjunto de estructuras de datos y procedimientos que forman el “core” de cualquier programa concurrente (en particular de un sistema operativo como administrador de recursos) Las estructuras de datos representan el estado de los procesos, semáforos y variables de condición. Las subrutinas o procedimientos representan operaciones primitivas sobre las estructuras de datos. La palabra primitiva se asocia con la ejecución atómica. So; CO P1 // P2 // .... Pn OC Sn+1; 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador Para implementar un código concurrente como el anterior se requieren tres mecanismos: CREAR procesos y arrancar su ejecución. STOP y eliminación de procesos. Saber cuando termina el alcance de un CO. Una primitiva es una rutina que es implementada por el Kernel, de tal modo que se ejecuta en forma atómica. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador FORK es la primitiva para crear otro proceso (hijo o child) que queda “elegible” para ejecución. El FORK tendrá como parámetro la dirección inicial de ejecución y datos de estado inicial. QUIT cuando un proceso lo ejecuta, se “elimina”. JOIN es la primitiva para esperar que todos los procesos involucrados en un CO lleguen al punto del OC (es decir terminen la parte concurrente de su ejecución). Normalmente un “padre” puede hacer JOIN de uno, varios o todos sus “hijos”. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador So; FOR [i=1 to n] # creamos los procesos hijos FORK (Pi); FOR [i=1 to n] # esperamos el fin de cada uno de ellos JOIN (Pi); Sn+1; Suponemos que el proceso principal está creado implícitamente e inicia la ejecución. A su vez el código de cada Pi ya está en memoria para ejecutarse. Al ejecutar el segundo FOR debe esperar que termine P1, luego P2 y así sucesivamente. Podría ser JOIN sin argumentos = espera sin orden que terminen todos. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador Un Kernel puede organizarse de un modo monolítico en el cual cada primitiva del kernel se ejecuta en forma atómica (y sólo una en un instante de tiempo)  lo usamos en el single processor kernel. Un Kernel puede organizarse como un programa concurrente donde los procesos usuario pueden ejecutar diferentes primitivas del Kernel en el mismo instante de tiempo (concepto de re-entrante).  monoprocesador / multiprocesador 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador Cada proceso está representado en el Kernel por un descriptor. En el descriptor está el estado del proceso y su contexto (registros propios y dirección de la próxima instrucción a ejecutar). El Kernel “arranca” cuando se produce una interrupción (externa, por ejemplo de un periférico o interna, trap o SVC ejecutada por un proceso para invocar un servicio del kernel). 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador El manejador de interrupciones analiza el pedido de interrupción y deriva la ejecución a la primitiva correspondiente. Cuando la primitiva se completa, un proceso dispatcher o scheduler decide que proceso continúa ejecutándose (context switching). En el kernel que sigue, el arreglo ProcessDescriptor[maxProcs] tendrá los descriptores de procesos, entre ellos la variable executing que nos dará el estado del proceso. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador Para asegurar que las primitivas se ejecutan atómicamente, la primer acción del manejador de interrupciones es inhibir otras interrupciones. El dispatcher rehabilitará las interrupciones, cuando la primitiva termine y le devuelva el control. En máquinas con múltiples niveles de interrupciones, podría no ser necesario bloquear todas. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador. Comentarios El arreglo ProcessDescriptor[maxprocs] tiene un tipo ProcessType que será una estructura de registro indicando los campos del descriptor. Un proceso “padre” le pide al kernel la creación de un proceso hijo, invocando la primitiva FORK que alocará e inicializará un descriptor “vacío”. Cuando el dispatcher busca un proceso para ejecutar, deberá buscar en la lista de procesos “ready” ya creados. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador. Comentarios Asumiremos dos listas FREE LIST de descriptores “vacíos” para responder a los FORK y READY LIST para indicar los procesos ya inicializados que están listos para que el dispatcher los elija. Una tercer lista “WAITING” indicará los procesos “padre” que están esperando procesos hijos que hagan Quit. La variable EXECUTING tendrá el valor del índice del descriptor del proceso que actualmente se está ejecutando. Al bootear se crea un proceso, se asigna su descriptor y su índice a EXECUTING y las listas Ready y Waiting están vacías. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador. Comentarios Con esta representación de los datos del Kernel, un Fork toma un descriptor de la lista Free, lo inicializa y lo inserta al final de la lista Ready. El Join chequea si el proceso hijo mencionado ha hecho Quit. Si no, deja el proceso padre en la lista Waiting. La ejecución de un Quit registra cual proceso terminó, pone el descriptor de ese proceso en la lista Free, despierta al proceso padre que esté esperando el Quit y setea Executing a 0, para indicarle al dispatcher que el proceso ha liberado el procesador. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel monoprocesador. Comentarios Cuando se invoca el dispatcher al final de una primitiva, chequea el valor de Executing. Si NO es 0, el proceso actual sigue reteniendo la ejecución. Si fuera 0, el dispatcher busca el primer descriptor de la lista Ready y setea con su índice a Executing. Luego carga el estado (conjunto de registros) de ese proceso. Si la lista Ready es FIFO y todos los procesos llegan al Quit en tiempo finito, el esquema asegura cierto fairness. Para evitar un deadlock, podemos usar un “interval timer” que es un dispositivo de hardware que dispara una interrupción luego de un tiempo fijo = el dispatcher lo puede usar para cambiar el Executing si es necesario... 17-5-2004 Programación Concurrente 2004 - Clase 6

Ejemplo de implementación: Kernel monoprocesador. processType processDescriptor[maxProcs]; int executing = 0; # index of the executing process declarations of variables for the free, ready, and waiting lists; SVC_Handler: { # entered with interrupts inhibited save state of executing; determine which primitive was invoked, then call it; } Timer_Handler: { # entered with interrupts inhibited insert descriptor of executing at end of ready list; executing = 0; dispatcher( ); Programación Concurrente 2004 - Clase 6 17-5-2004

Ejemplo de implementación: Kernel monoprocesador. procedure fork(initial process state) { remove a descriptor from the free list and initialize it; insert the descriptor on the end of the ready list; dispatcher( ); } procedure quit( ) { record that executing has quit; insert descriptor of executing at end of free list; executing = 0; if (parent process is waiting for this child) { remove parent from the waiting list; put parent on the ready list; } dispatcher(); Programación Concurrente 2004 - Clase 6 17-5-2004

Ejemplo de implementación: Kernel monoprocesador. procedure join(name of child process) { if (child has not yet quit) { put the descriptor of executing on the waiting list; executing = 0; } dispatcher(); procedure dispatcher() { if (executing == 0) { # current process blocked or quit remove descriptor from front of ready list; set executing to point to it; start the interval timer; load state of executing; # with interrupts enabled Programación Concurrente 2004 - Clase 6 17-5-2004

Kernel multiprocesador Para extender el kernel monoprocesador a multiprocesador, debemos considerar que tenemos memoria compartida accesible por cualquier procesador, lo cuál obliga a algunas modificaciones simples en el kernel monoprocesador: 1- Los procedimientos y datos del kernel estarán en memoria compartida, por lo cual su acceso será con mecanismos de exclusión mútua. 2- El dispatcher debe ser diferente para poder explotar los múltiples procesadores. 3- Cada procesador debe tener su timer y las interrupciones internas de un proceso deben ser atendidas por el procesador donde reside. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador Cuando un procesador es interrumpido, entra al kernel e inhibe las interrupciones sobre ese procesador. Esto significa que el kernel es indivisible para ese procesador, pero podría recibir pedidos de otro procesador en el mismo tiempo. Debemos elegir entre hacer todo el kernel una sección crítica (lo cual simplifica pero hacer perder totalmente la eficiencia del multiprocesamiento) y tener múltiples secciones críticas, asociadas con los datos compartidos. En el código que sigue los datos críticos son las listas free, ready y waiting. La variable executing ahora será un arreglo con una entrada por procesador. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador El mayor cambio es el dispatcher: antes teníamos UN procesador y se suponía que siempre tenía algún proceso para ejecutar... Ahora podríamos tener momentos con procesadores “desocupados” (idle). Cuando un proceso es “despertado” o creado por un FORK debe buscar si existe un procesador idle donde ejecutarse. Esta funcionalidad puede proveerse de varios modos,nosotros elegiremos: Que cada procesador cuando esté desocupado ejecute un proceso especial que periódicamente examine la lista de “READY” hasta encontrar un proceso en espera. Cuando este “auto-dispatcher” encuentra la lista READY vacía, debe esperar hasta que aparezca un proceso en la lista y darle el control. 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador process Idle { while (executing[i] == the Idle process) { while (ready list empty) Delay; lock ready list; if (ready list not empty) { remove descriptor from front of ready list; set executing[i] to point to it; } unlock ready list; start the interval timer on processor i; load state of executing[i]; # with interrupts enabled 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador processType processDescriptor[maxProcs]; int executing[maxProcs]; # one entry per processor declarations of free, ready, and waiting lists and their locks; SVC_Handler: { # entered with interrupts inhibited on processor i save state of executing[i]; determine which primitive was invoked, then call it; } Timer_Handler: { lock ready list; insert executing[i] at end; unlock ready list; executing[ i ] = 0; dispatcher( ); 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador procedure fork(initial process state) { lock free list; remove a descriptor; unlock free list; initialize the descriptor; lock ready list; insert descriptor at end; unlock ready list; dispatcher(); } procedure quit() { lock free list; insert executing[i] at end; unlock free list; record that executing[i] has quit; executing[i] = 0; if (parent process is waiting) { lock waiting list; remove parent from that list; unlock waiting list; lock ready list; put parent on ready list; unlock ready list; 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador procedure join(name of child process) { if (child has already quit) return; lock waiting list; put executing[i] on that list; unlock waiting list; dispatcher(); } 17-5-2004 Programación Concurrente 2004 - Clase 6

Kernel multiprocesador procedure dispatcher() { if (executing[ i ] == 0) { lock ready list; if (ready list not empty) { remove descriptor from ready list; set executing[i] to point to it; } else # ready list is empty set executing[ i ] to point to Idle process; unlock ready list; if (executing[ i ] is not the Idle process) start timer on processor i; load state of executing[i]; # with interrupts enabled 17-5-2004 Programación Concurrente 2004 - Clase 6

Comentarios En la página está la evaluación del 2003, a modo de referencia. Las clases teóricas se reinician el lunes 31-5, con comunicación y sincronización por mensajes. El archivo de la biblioteca JAVA está disponible en la página de la cátedra. Programación Concurrente 2004 - Clase 6 17-5-2004