Contenido Contenido.............................................................................................................................................. ................................................................................................................................................. ... i Lista de figuras f iguras ...................................................................................................................................... ........................................................................................................................................ .. ii Objetivo...................................................................................................................................... .................................................................................................................................................. ............ iii Introducción............................................................................................................................................ ............................................................................................................................................ 1 Historia.................................................................................................................................................... .................................................................................................................................................... 2 Paradigmas de programación concurrente .................................................................... ............................................................................................ ........................ 3 Espacio de direcciones global particionado (PGAS) ............................................................................ ............................................................................ 3 Modelo actor.................................................... actor....................................................................................................................... ................................................................................... ................ 4 Comunicación de procesos secuenciales (CSP)...................................................................... (CSP) ................................................................................... ............. 4 Concurrente orientado a objetos ................................................................. ....................................................................................................... ...................................... 5 Programación de flujo f lujo de datos ............................................................................... .......................................................................................................... ........................... 6 Multihilo.............................................................................................................................................. .............................................................................................................................................. 6 Estudios de comparación en modelos de programación concurrentes ................................................. 8 Programación concurrente en idiomas específicos ................................................................................ ................................................................................ 9 Ada ................................................................... ......................................................................................................................................... ................................................................................... ............. 9 Especificaciones de task y cuerpos de task. ......................................................... .................................................................................... ........................... 9 Fases de un task. ............................................................................................................. ........................................................................................................................... .............. 10 Erlang ............................................................... ..................................................................................................................................... ................................................................................. ........... 11 Procesos. .................................................................. ....................................................................................................................................... ..................................................................... 11 Procesos concurrentes y paso de mensajes. ................................................................................ 12 Actores en Erlang. ......................................................................................................................... ......................................................................................................................... 13 Go (Golang) ....................................................................................................................................... ....................................................................................................................................... 14 CSP: goroutines. ............................................................................................................................ ............................................................................................................................ 14 CSP: channels. ............................................................................................................................... ............................................................................................................................... 15 Java.................................................................................................................................................... .................................................................................................................................................... 16 Estados de un hilo ................................................................................................... ......................................................................................................................... ...................... 17 Conclusión............................................................................................................................................. ............................................................................................................................................. 19 Bibliografía ........................................................... .............................................................................................................................. ................................................................................. .............. 20
ii
Lista de figuras Figura 1 Partes de un task ......................................................... .................................................................................................................... ........................................................... 10 Figura 2 Estados de tarea..................................................................................................................... tarea..................................................................................................................... 10 Figura 3 Ejemplo de módulo Erlang Erl ang ................................................................. ..................................................................................................... .................................... 12 Figura 4 Comunicación entre procesos ............................................................................................... ............................................................................................... 13 Figura 5 actores en Erlang ................................................................................................................... ................................................................................................................... 13 Figura 6 creacion de un goroutine ................................................................... ....................................................................................................... .................................... 14 Figura 7 modelo fork-join de Go ........................................................................................................... ........................................................................................................... 15
..................................................................................................... 16 Figura 8 ejemplo de channel en Go ..................................................................................................... Figura 9 Modelo de hilos en Java......................................................... ......................................................................................................... ................................................ 17 Figura 10 Estados de un hilo ................................................................. ................................................................................................................ ............................................... 17
iii
Objetivo
Proporcionar una comparación de los diferentes enfoques de los Lenguajes concurrentes, discutir sus fortalezas y debilidades e identificar las áreas de aplicación para las que son más adecuadas. Esto requirió resolver problemas relevantes (desde el punto de vista de concurrencia) utilizando cada enfoque. También fue necesario decidir sobre la metodología de la comparación.
1
Introducción
La reciente transición de la computación de propósito general a arquitecturas multinúcleo ha cambiado drásticamente el campo de la computación. Esta transición fue causada por las restricciones físicas que impiden la escala de frecuencia. Ya no es el caso que la próxima generación de hardware hará que los programas sean mucho más rápidos, a menos que se creen con la concurrencia en mente, una tarea que desde hace tiempo se reconoce como difícil y propensa a errores. Aunque se han propuesto muchos lenguajes de programación para hacer que la escritura de programas concurrentes sea más simple que el multihilo tradicional, en gran medida se desconoce si alguno de los lenguajes recién creados realmente mejora algún aspecto de la productividad del programador. Este informe se enfoca en el subconjunto de aquellos lenguajes que están orientados hacia arquitecturas multi-core. Esos lenguajes intentan facilitar la vida del programador introduciendo abstracción de alto nivel y ocultando la mayoría de los detalles de bajo nivel utilizados para implementarlos. El problema con esas abstracciones es que podrían eliminar la flexibilidad que sería necesaria para resolver de manera eficiente algunos problemas relacionados a la concurrencia.
2
Historia
En la última década, el campo de la programación concurrente se ha ampliado desde aplicaciones de sistema operativo "puro" a una multitud de programas distribuidos y en tiempo real. Desde finales de la década de 1960, la programación concurrente se ha considerado necesaria para la implementación de objetos relacionados con la computadora en los sistemas operativos, como los procesos de usuario y los controladores de dispositivos. Los primeros desarrollos de la programación simultánea surgieron en un esfuerzo por dar a la comunidad relativamente pequeña de programadores de núcleo de sistema un conjunto de operaciones para fomentar el desarrollo de sistemas operativos más confiables. En ina vision más reciente, la programación concurrente se considera como un enfoque para lograr una representación más fiel de los objetos en el mundo modelados por un programa. Muchos programas son, de hecho, simulaciones de algún sistema en el mundo físico: un avión que se mueve en el espacio, un banco con cajeros y clientes. El mundo físico se compone de muchos objetos que operan independientemente el uno del otro, necesitando ocasionalmente sincronizar, comunicarse o referirse a información compartida. En esta vista, la programación simultánea es útil porque proporciona un mapeo más natural de estos objetos del mundo real a los segmentos del programa. Se dice que una representación más natural es más fácil de codificar, depurar y mantener. Dado que un número cada vez mayor de programas se codifica mejor como concurrentes, un número cada vez mayor de programadores necesita aprender a hacer una programación concurrente de manera confiable y correcta. A medida que la concurrencia ha pasado de los sistemas operativos a las aplicaciones, la necesidad de hacer una programación concurrente ha pasado de un pequeño círculo de programadores de sistemas a una comunidad mucho más amplia de programadores de aplicaciones.
3
Paradigmas de programación concurrente
Los lenguajes de programación concurrente, son lenguajes de programación que usan construcciones de lenguaje para concurrencia. Estas construcciones pueden implicar multithreading (Multihilo), soporte para computación distribuida, paso de mensajes, recursos compartidos (incluyendo memoria compartida) o futuros y promesas. Dichos lenguajes a veces se describen como lenguajes orientados a la concurrencia o lenguajes de programación orientados a la concurrencia (COPL). Muchos lenguajes de programación concurrentes se han desarrollado más como lenguajes de investigación (por ejemplo, Pict) que como lenguajes para uso de producción. Sin embargo, lenguajes como Erlang, Limbo y occam, han visto el uso industrial en varios momentos en los últi mos 20 años. Los paradigmas de programación en los que la concurrencia juega un papel importante son: Espacio de direcciones global particionado (PGAS)
Espacio de direcciones global particionado o Partitioned Global Address Space (PGAS), es un espacio global de direcciones con parte de la memoria local para cada procesador (YELICK, 2007, pág. 24). Es un modelo de programación paralelo. Asume un espacio de direcciones de memoria global que está particionado lógicamente y una parte de él es local para cada proceso, subproceso o elemento de procesamiento. La novedad de PGAS es que las porciones del espacio de memoria compartida pueden tener una afinidad por un proceso particular, explotando así la localidad de referencia.
El modelo PGAS es la base de los siguientes lenguajes: 1) Chapel 2) Coarray Fortran 3) Fortress 4) High Performance Fortran 5) Titanium 6) Unified Parallel C 7) X10 8) ZPL
4
Modelo actor
Modelo actor o Actor Model, los actores envían mensajes asincrónicos a otros actores (AGHA, 1986, pág. 8). El modelo actor en ciencias de la computación es un modelo matemático de computación concurrente que trata a los "actores" como primitivas universales de la computación concurrente. En respuesta a un mensaje que recibe, un actor puede: tomar decisiones locales, crear más actores, enviar más mensajes y determinar cómo responder al siguiente mensaje recibido. Los actores pueden modificar su propio estado privado, pero solo pueden afectarse mutuamente a través de mensajes (evitando la necesidad de bloqueos). El modelo actor se originó en 1973. Se ha utilizado tanto como un marco para una comprensión teórica de la computación y como la base teórica para varias implementaciones prácticas de sistemas concurrentes. Varios lenguajes de programación diferentes emplean el modelo actor o alguna variación del mismo. Estos lenguajes incluyen a:
1) Axum - un lenguaje de dominio específico desarrollado por Microsoft. 2) Elixir (runs on the Erlang VM) 3) Erlang 4) Janus 5) Red 6) SALSA 7) Scala/Akka (toolkit) 8) Smalltalk 9) Akka.NET
Comunicación de procesos secuenciales (CSP)
Comunicación de procesos secuenciales o communicating sequential processes (CSP), composición paralela de un número fijo de procesos secuenciales que se comunican de forma síncrona utilizando mensajes en un patrón fijo (HOARE, 1978, pág. 677). Es un lenguaje formal para describir patrones de interacción en sistemas concurrentes. Es un miembro de la familia de teorías matemáticas de concurrencia conocidas como álgebras de procesos, o cálculos de procesos, que se basan en mensajes que pasan por canales. CSP fue
5
muy influyente en el diseño del lenguaje de programación occam, además a influido en el diseño de lenguajes de programación tales como:
1) Limbo 2) RaftLib 3) Go 4) Crystal 5) Clojure's core.async
Concurrente orientado a objetos
Concurrente orientado a objetos o Concurrent Object-Oriented, lenguaje orientado a objetos extendido con concurrencia (MORANDI, 2010, pág. 23). es un paradigma de programación basado en el concepto de "objetos", que puede contener datos, en forma de campos, a menudo conocidos como atributos; y código, en forma de procedimientos, a menudo conocidos como métodos y que también puede implementar concurrencia.
Los lenguajes OOP que soportan concurrencia son los siguientes: 1) μC++ 2) Ada 3) C* 4) C# 5) C++ AMP 6) Charm++ 7) D Programming Language 8) Eiffel SCOOP (Programación Simple concurrente Orientada a Objetos) 9) Emerald (también programación distribuida) 10) Java 11) Join Java - Un lenguaje basado en Java con características de join-calculus. 12) ParaSail 13) Smalltalk
6
Programación de flujo de datos
Programación de flujo de datos o Dataflow programming, es un paradigma de programación que modela un programa como un gráfico dirigido de los datos que fluyen entre las operaciones, implementando así los principios del flujo de datos y la arquitectura (William & Edward, 2013, pág. 14). Los lenguajes de programación de Dataflow comparten algunas características de los lenguajes funcionales, y generalmente se desarrollaron para llevar algunos conceptos funcionales a un lenguaje más adecuado para el procesamiento numérico. Los lenguajes Dataflow que soportan concurrencia son:
1) CAL 2) E (también orientado a objetos) 3) Joule (también programación distribuida) 4) LabView (también asincrona) 5) Lustre (también asincrona) 6) Preesm (también asincrona) 7) Signal (también asincrona) 8) SISAL
Multihilo
Multihilo o Multithreading, El subprocesamiento múltiple se encuentra principalmente en sistemas operativos multitarea. Multithreading es un modelo de programación y ejecución generalizado que permite que múltiples hilos existan dentro del contexto de un proceso (Lewis, 2003, pág. 15). Estos subprocesos comparten los recursos del proceso, pero pueden ejecutarse de forma independiente. El modelo de programación con hilos proporciona a los desarrolladores una abstracción útil de ejecución concurrente. El multihilo también se puede aplicar a un proceso para permitir la ejecución en paralelo en un sistema de multiprocesamiento. Los lenguajes Multihilo son:
1) Cilk 2) Cilk Plus
7
3) C# 4) Clojure 5) Fork - Lenguaje de programación para el modelo PRAM. 6) Java 7) ParaSail 8) Rust 9) SequenceL
8
Estudios de comparación en modelos de programación concurrentes
(NANZ, 2011) Presentó un estudio empírico para comparar la facilidad de uso (comprensión del programa, depuración y escritura) de dos enfoques de programación de concurrencia (SCOOP y Java de subprocesos múltiples). Usan autoestudio para evitar el sesgo de enseñanza, la autoevaluación para verificar la equivalencia de los grupos evaluados y las técnicas de evaluación estándar para evitar la subjetividad en la evaluación de las respuestas. Llegan a la conclusión de que SCOOP es de hecho más fácil de usar que Java de subprocesos múlti ples en lo que respecta a la comprensión y depuración de programas, y equivalente en lo que respecta a la escritura de programas.
PHILIPPSEN (2000), es un extenso catálogo de 111 lenguajes concurrentes orientados a objetos y sus principales características con respecto a los mecanismos utilizados para iniciar y coordinar la concurrencia. Se analizan las ventajas, desventajas e interdependencias de estas características. Se discute el grado de computación y localidad de datos que se puede lograr. El rendimiento se evalúa en términos de factores de rendimiento clave conocidos (despliegue en abanico, concurrencia dentro del objeto y localidad), no en términos de puntos de referencia de ningún tipo. Las desventajas de las características se expresan en términos de encapsulación discontinua, anomalías de herencia, expresividad de las limitaciones de coordinación y elección de implementación (lenguaje frente a biblioteca). Los entornos de programación orientados a la programación distribuida no son considerados. (págs. 917 – 980)
(SCAIFE, 1996) Discute problemas en el diseño y selección de lenguajes orientados a objetos concurrentes y describe algunos principios generales, examinando 29 lenguajes de programación.
(Wyatt, Kavi, & Hufnagel, 1992) Presento una comparación de 14 lenguajes concurrentes orientados a objetos con respecto a comunicación, sincronización, administración de procesos, herencia e intercambios de implementación. Llegan a la conclusión de que ninguno de ellos cumplió con los siete requisitos de Meyer para que un lenguaje esté realmente orientado a objetos, ya que restringen o no permiten la herencia. Los idiomas se seleccionaron según la disponibilidad del material publicado y los manuales detallados. No hay discusión sobre las áreas de aplicación para las cuales los idiomas son más adecuados.
9
Programación concurrente en idiomas específicos
Hoy en día, los lenguajes de programación más comúnmente utilizados que tienen construcciones específicas para concurrencia son Java y Go. Ambos lenguajes utilizan fundamentalmente un modelo de concurrencia de memoria compartida, por otro lado de los lenguajes que usan un modelo de concurrencia de transmisión de mensajes (Modelo actor), Erlang es probablemente el más utilizado en la industria en la actualidad, sin embargo el lenguaje Ada es importante desde el punto de vista histórico en el desarrollo de la programación concurrente. Por ello se describirá en más detalle sobre la concurrencia en dichos lenguajes. Ada
El lenguaje que se convirtió en Ada fue elegido en una competencia patrocinada a fines de la década de 1970 por el Departamento de Defensa de los Estados Unidos (DoD); Ada pretendio convertirse en el lenguaje en el que se escribe el nuevo software relacionado con la defensa. Las primitivas de programación concurrente se incluyeron en el lenguaje porque los diversos documentos de requisitos del DoD ("Steelman" y sus informes predecesores) enumeraron la programación simultánea como esencial para la misión del lenguaje. Ada fue el primer lenguaje destinado a la adopción y uso generalizado en la industria para incluir un conjunto completo de primitivas de programación concurrente. Un proceso en Ada se llama “task” cuya traducción en español es tarea, cada tarea (task) es en realidad un objeto de un tipo de tarea, un tipo de tarea es declarado por el programador; el programador puede, en el caso límite, simplemente declarar tareas individuales, un tipo para cada uno de los cuales es implícitamente declarado por el compilador. Especificaciones de task y cuerpos de task. Una unidad de tarea consiste en una
especificación de tarea y un cuerpo de tarea, la cual se muestra en la figura 1.
Una especificación de tarea que comienza con el tipo de tarea de palabras reservadas declara un tipo de tarea. El valor de un objeto de un tipo de tarea designa una tarea que tiene las entradas, si las hay, que se declaran en la especificación de la tarea; estas entradas también se llaman entradas de este objeto. La ejecución de la tarea está definida por el cuerpo de la tarea correspondiente. (hanna, 1983)
10
Figura 1 Partes de un task
Fases de un task. Burns & Wellings (1997) Afirman que. “La ejecución de un objeto
de tarea tiene tres fases activas principales” (pág. 65). Las cuales son:
1) Activación: la elaboración de la parte declarativa del cuerpo de la tarea (las variables locales en el cuerpo de la tarea se crean y se inicializan durante la activación). El Activador identifica la tarea que creó y activó la tarea. 2) Ejecución normal: la ejecución de las declaraciones visibles dentro del cuerpo de la tarea. 3) Finalización: la ejecución de cualquier código de finalización asociado con cualquier objeto en su parte declarativa.
Figura 2 Estados de tarea
11
La figura 2 muestra las transiciones entre estos estados durante la vida de la tarea. Se dice que la tarea creada está en estado No activado (Unactivated). Luego, el tiempo de ejecución asocia un hilo de control a esta tarea. Si la elaboración de la tarea falla, la tarea va directamente al estado Terminado (Terminated); de lo contrario, la tarea alcanza el estado ejecutable (Runnable) y ejecuta el código de usuario de la tarea. Si este código ejecuta alguna operación que bloquea la tarea (de acuerdo con la semántica de Ada: cita, operación protegida o declaración de demora), alcanza el estado de Suspensión (Sleep) y luego vuelve al estado Ejecutable (Runnable). Cuando la tarea ejecuta una alternativa de terminación de Ada o finaliza la ejecución del código de usuario de Ada, pasa al estado Terminado (Terminated). Erlang
En 1986 Erlang fue diseñado con el objetivo de mejorar el desarrollo de las aplicaciones de telefonía, también para programar sistemas concurrentes, en tiempo real y con tolerancia a fallas distribuidas el cual fue desarrollado por Ericsson y de ahí el nombre. “Erlang es un lenguaje de programación funcional utilizado para crear sistemas de software en tiempo real escalables de forma masiva con requisitos de alta disponibilidad” (ARMSTRONG, 2003, pág. 477). El paralelismo se expresa utilizando el modelo Actor, donde los procesos se crean como hilos de ejecución independientes y luego se comunican a través de mensajes (sin memoria compartida). El lenguaje tiene un fuerte uso industrial en aplicaciones del mundo real. Procesos. En Erlang, cada hilo de ejecución se llama proceso. (Aparte: el término
"proceso" se usa generalmente cuando los hilos de ejecución no comparten datos entre sí y el término "hilo" cuando comparten datos de al guna manera. Los hilos de ejecución en Erlang no comparten datos, por eso son llamados procesos). El BIF (built in function - función incorporada) spawn (generar) de Erlang se usa para crear un nuevo proceso, del siguiente modo: spawn(Module, Exported_Function, List of Arguments). En la figura 3 se muestra, la función “say_something” escribe su primer argumento el número de veces especificado por el segundo argumento. La función “start” inicia dos procesos de Erlang, uno que escribe "hello" tres veces y otro que escribe " goodbye" tres veces. Ambos procesos usan la función “say_something”. Tener en cuenta que una función utilizada de esta manera por spawn, para iniciar un proceso, debe exportarse desde el módulo (es decir, en el “export” al inicio del módulo).
12
Figura 3 Ejemplo de módulo Erlang
Procesos concurrentes y paso de mensajes.
La concurrencia en Erlang es
fundamental para su éxito. En lugar de proporcionar hilos que comparten memoria, cada proceso de Erlang se ejecuta en su propio espacio de memoria y posee su propio heap (montón – estructura de datos) y stack (pila – estructura de datos). Los procesos no pueden interferir entre sí inadvertidamente, como es muy fácil en los modelos de subprocesamiento. Los procesos se comunican entre sí a través del envío de mensajes, donde el mensaje puede ser cualquier valor de datos de Erlang. El envío de mensajes es asíncrono, por lo que una vez que se envía un mensaje, el proceso puede continuar el proceso. Los mensajes se recuperan del buzón del proceso de forma selectiva, por lo que no es necesario procesar los mensajes en el orden en que se reciben. Esto hace que la concurrencia sea más robusta, particularmente cuando los procesos se distribuyen a través de diferentes computadoras y el orden en que se reciben los mensajes dependerá de las condiciones del ambiente de red. La Figura 4 muestra un ejemplo, donde un proceso de "servidor de área" calcula áreas de formas para un cliente.
13
Figura 4 Comunicación entre procesos
Actores en Erlang. En Erlang, que está diseñado para concurrencia, distribución y
escalabilidad, los actores son parte del lenguaje en sí. Debido a sus raíces en la industria de las telecomunicaciones, donde una gran cantidad de procesos concurrentes son normales, es casi imposible pensar en Erlang sin actores, que también se utilizan para proporcionar distribución. Los actores en Erlang se llaman procesos y se inician utilizando la función spawn incorporada. Una aplicación simple que utiliza un actor se puede ver a continuación. En esta aplicación, se define un actor que actúa como contador básico. Enviamos 100.000 incrementos de mensajes al actor y luego le pedimos que imprima su valor interno.
Figura 5 actores en Erlang
14
En la figura 5 las líneas 1 y 2 definen el módulo y las funciones exportadas. Las líneas 4 a 7 contienen la función de ejecución, que inicia un proceso de contador y comienza a enviar mensajes de incremento. El envío de estos mensajes ocurre en las líneas 15 a 18, usando el operador de paso de mensajes (!). Go (Golang)
El lenguaje fue anunciado en noviembre de 2009. Se utiliza en algunos de los sistemas de producción de Google, así como en otras empresas.
Si bien Go es a la vez de propósito general y un lenguaje de sis temas de bajo nivel, una de sus principales fortalezas es el modelo y las herramientas de concurrencia integrados. Muchos otros lenguajes tienen bibliotecas (o extensiones) de terceros, pero la concurrencia inherente es algo unico de los lenguajes modernos, y es una característica central del diseño de Go. (Kozyra, 2014)
El estilo de concurrencia Go es mediante La comunicación de procesos secuenciales (CSP - Communicating sequential processes) la cual utiliza la comunicación como primitiva de sincronización.
CSP: goroutines. goroutines (rutinas go) es una de las unidades de organización más
básicas en un programa Go, un goroutine tiene un modelo simple: es una función que se ejecuta simultáneamente con otros goroutines en el mismo espacio de direcciones. En pocas palabras, un goroutine es una función que se ejecuta simultáneamente (no necesariamente en paralelo) Junto con otro código. Podemos iniciar uno simplemente colocando la palabra clave “go” antes de una función:
Figura 6 creacion de un goroutine
15
Go sigue un modelo de concurrencia llamado modelo fork-join. La palabra fork se refiere al hecho de que en cualquier punto del programa, puede dividir una rama secundaria de ejecución que se ejecutará simultáneamente con su padre (parent). La palabra unión se refiere al hecho de que en algún punto en el futuro, estas ramas concurrentes de ejecución se volverán a unir. Cuando el hijo (child) vuelve a unirse, el padre se llama punto de unión. La Figura 7 muestra una representación gráfica para de dicho modelo:
Figura 7 modelo fork-join de Go
CSP: channels. Los channels (canales) son una de las primitivas de sincronización en
Go, Si bien se pueden usar para sincronizar el acceso de la memoria, se utilizan mejor para comunicar información entre goroutines. “Un channel (canal), sirve como un conducto para una corriente de información; los valores pueden pasarse a lo largo del canal, y luego leer hacia abajo” (Cox-Buday, 2017, pág. 64). Un channel se crea con make (chan val-type). Los canales se tipan por los valores que transmiten. Envía un valor a un canal usando la sintaxis del canal <-. Aquí enviamos "ping" al canal de mensajes que hicimos anteriormente, desde un nuevo goroutine. La sintaxis <-channel recibe un valor del canal. Aquí recibiremos el mensaje "ping" que enviamos anteriormente e imprimirlo. Cuando ejecutamos el programa, el mensaje "ping" se pasa con éxito de una rutina a otra a través de nuestro canal. Por defecto, envía y recibe el bloqueo hasta que tanto el emisor como el receptor estén listos. Esta propiedad nos permitió esperar al final de nuestro programa para el mensaje "ping" sin tener que utilizar ninguna otra sincronización.
16
Figura 8 ejemplo de channel en Go
Java
Desde JDK 1.2 (8 de diciembre de 1998), Java ha incluido un conjunto estándar de clases de colección, el marco de colecciones de Java.
Doug Lea (profesor de ciencias de la computación y actual jefe del departamento de ciencias de la computación de la Universidad Estatal de Nueva York en Oswego) desarrolló un paquete de concurrencia, que comprende varias primitivas de concurrencia y una gran variedad de clases rela cionadas con la colección. (Sun, 1995).
El lenguaje de programación Java y la máquina virtual Java (JVM) se han diseñado para admitir la programación concurrente, y toda la ejecución tiene lugar en el contexto de hilos (threads). Se puede acceder a los objetos y recursos por muchos hilos separados; cada hilo tiene su propia ruta de ejecución, pero puede acceder potencialmente a cualquier objeto en el programa. El programador debe garantizar que el acceso de lectura y escritura a los objetos esté coordinado (o "sincronizado") adecuadamente entre los hilos. La sincronización de subprocesos garantiza que los objetos se modifiquen solo por un subproceso a la vez y que los subprocesos no puedan acceder a los objetos parcialmente actualizados durante la modificación
17
por otro subproceso. El lenguaje Java tiene construcciones integradas para soportar esta coordinación.
Figura 9 Modelo de hilos en Java
Estados de un hilo . Un hilo tiene su propio ciclo de vida, durante el cual puede
encontrarse en diferentes estados. Java controla el estado de los hilos mediante el llamado planificador de hilos, que se encargará de gestionar qué hilo debe ejecutarse en cada momento y en qué estado deben encontrarse el resto de hilos.
Figura 10 Estados de un hilo
En la Figura 10 se aprecian los diferentes estados en los que puede encontrarse un hilo (representados en un recuadro) y qué métodos pueden llevar ese estado al hilo (representados por flechas), dichos estados se describen a continuación:
1) Nuevo. Se ha creado un objeto hilo, pero todavía no se le ha asignado ninguna tarea. Para ello, se ha de llamar a su método start() y el hilo pasará al estado preparado.
18
2) Preparado. El hilo está preparado para ejecutarse, pero el planificador de hilos es quién debe decidir si puede hacerlo o debe esperar (por ejemplo, a que acabe la ejecución otro hilo). 3) En ejecución. Una vez el hilo puede acceder a tiempo de CPU, se ejecutará. Si el hilo finaliza su trabajo completamente, pasará al estado muerto. Si el planificador de hilos decide que ha cumplido su periodo de tiempo y el hilo no ha finalizado su trabajo, pasará al estado preparado y esperará a que el planificador de hilos vuelva a darle permiso para ejecutarse. 4) Bloqueado. El hilo no puede ejecutarse porque espera que ocurra algo. En cuanto ocurra lo que le está dejando bloqueado, pasará al est ado preparado. 5) Muerto. El hilo ha finalizado su tarea y deja de existir.
19
Conclusión
La programación concurrente es necesaria y difícil, pero no es necesari amente complicada. Es necesario porque las restricciones físicas impiden la escala de frecuencia de los procesadores únicos, lo que obliga a la transición a los de núcleo múltiple. Es difícil debido a todos los tipos de errores no determinísticos que permite. Y, sin embargo, no es necesariamente difícil debido a una serie de idiomas de alto nivel y herramientas que se han propuesto para facilitarlo.
20
Bibliografía Burns, A., & Wellings, A. (1997). Concurrency in Ada (2nd edition). Cambridge University Press. AGHA, G. (1986). Actors: a model of concurrent computation in distributed systems. Cambridge, MA, USA: MIT Press. ARMSTRONG, J. (2003). Making reliable distributed systems in the presence of software errors. Swedish Institute of Compuster Science. Cox-Buday, K. (2017). Concurrency in Go. Gravenstein Highway North, Sebastopol, CA: O’Reilly Media, Inc. hanna, g. (1983). Ada '83 Language Reference Manual. The Pentagon, Washington, DC 20301-2081, U.S.A.: Secretary of Defense, Research and Engineering. HOARE, C. (1978). Communicating sequential processes. New York, NY, USA: ACM. Kozyra, N. (2014). Mastering Concurrency in Go. Birmingham, UK: Packt Publishing. Lewis, B. (2003). Threads Primer: A Guide to Multithreaded Programming. Addison-Wesley. MORANDI, B. (2010). SCOOP – A contract-based concurrent objectoriented. NANZ, S. (2011). Design of an Empirical Study for Comparing the Usability of Concurrent. INTERNATIONAL SYMPOSIUM ON EMPIRICAL SOFTWARE ENGINEERING AND MEASUREMENT .
PHILIPPSEN, M. (2000). A survey of concurrent object-oriented languages. Concurrency: Practice and Experience.
SCAIFE, N. (1996). A Survey of Concurrent Object-Oriented Programming. Sun, D. N. (1995). The History of Java Technology . Retrieved 04 30, 2010, from http://www.oracle.com: http://www.oracle.com/technetwork/java/javase/overview/javahistory-index-198355.html William, W., & Edward, A. (2013). Lucid, the Dataflow Programming Language. Academia Press. Wyatt, Kavi, & Hufnagel. (1992). Parallelism in Object-Oriented Languages: a survey. Los Alamitos, CA, USA: IEEE Softw. YELICK, K. (2007). Productivity and performance using partitioned global address space. New York, NY, USA: ACM.