Você está na página 1de 33

Tópicos Avanzados de

Programación

Tema III: Programación Concurrente

MRYSI: Ángel Salas Martinez


asalas@tecmartinez.edu.mx
Contenido

Programación Concurrente (MultiHilos)

3.1 Concepto de Hilo.


3.2 Comparación de un programa de flujo único contra uno de
flujo múltiple.
3.3 Creación y control de Hilos
3.4 Sincronización de Hilos.
Ejemplo de Programación Concurrente

Cuando los programas descargan archivos extensos como clips de


audio o video desde Internet, los usuarios no desean esperar hasta
que se descargue todo un clip completo para empezar a
reproducirlo.
Para resolver este problema, podemos poner varios subprocesos
a trabajar; un subproceso descarga un clip mientras otro lo
reproduce. Estas actividades se realizan en forma concurrente
para evitar que la reproducción del clip tenga interrupciones,
sincronizamos los subprocesos de manera que el subproceso de
reproducción no empiece sino hasta que haya una cantidad
suficiente del clip en memoria, como para mantener ocupado al
subproceso de reproducción.
Programación Concurrente
Para definirla correctamente, debemos diferenciar entre
programa y proceso.

Programa:
Conjunto de sentencias/instrucciones que se ejecutan
secuencialmente. Se asemeja al concepto de clase dentro de la
POO. Es por tanto un concepto estático.

Proceso:
Básicamente, se puede definir como un programa en ejecución.
Líneas de código en ejecución de manera dinámica. Se asemeja al
concepto de objeto en POO.
Programación Concurrente

La concurrencia aparece cuando dos o mas procesos son


contemporáneos. Un caso particular es el paralelismo
(programación paralela).

Los procesos pueden “competir” o colaborar entre si por los


recursos del sistema. Por tanto, existen tareas de colaboración y
sincronización.
Programación Concurrente

La programación concurrente se encarga del estudio de las


nociones de ejecución concurrente, así como sus problemas de
comunicación y sincronización.
4.1 Concepto de Hilo.

Hilo / Thread
Un hilo es un proceso que se ejecuta en un contexto diferente y
simultáneamente al que lo crea. es decir, crea un subproceso.

Todos los threads de una aplicación se encuentran contenidos en un


proceso – la unidad del sistema operativo en la cual una aplicación
corre.

La principal diferencia es que los procesos se encuentran totalmente


aislados de otros procesos, mientras que los threads comparten el
montículo de memoria (heap) con otros threads de la misma
aplicación. Esto hace que los threads sean muy útiles: un thread puede
recuperar datos en segundo plano, mientras que otro thread va
mostrando los datos mientras llegan.
Ejemplo
Threads y procesos
Proc 1 Proc 2 Proc 3

h1 h2 h3 h4 h5 hn thread
h6

Sistema Operativo

Los Thread pueden estar en 2 Niveles :


Nivel usuario: Ejemplo los hilos creados en Java
Nivel Sistema Operativo: Hilos del sistema, que a su ves dan soporte a los
hilos del usuario mediante un API
Beneficios de los Threads
4.2 Comparación de un programa de flujo
único contra uno de flujo múltiple.

Un programa de flujo único:


También conocido como programa de tarea única o mono -hilo
(single-thread) utiliza un único flujo de control (thread) para
controlar su ejecución.
Muchos programas no necesitan la potencia o utilidad de
múltiples tareas. sin necesidad para especificar explícitamente
que se quiere un único flujo de control, muchos de los applets
y aplicaciones son de flujo único.
4.2 Comparación de un programa de flujo
único contra uno de flujo múltiple.

Un programa de flujo Multiple:


También conocido como programa multitarea o multi –hilo,
(multithreaded). permite que cada tarea comience y termine tan pronto
como sea posible. Este comportamiento presenta una mejor respuesta a
la entrada en tiempo real.

Los navegadores utilizan diferentes tareas ejecutándose en paralelo


para realizar varias tareas, "aparentemente" de forma concurrente. Por
ejemplo, en muchas páginas Web se puede desplazar la página e ir
leyendo el texto antes de que todas la imágenes estén presentes en la
pantalla. En este caso, el navegador está descargando las imágenes en
una tarea y soportando el desplazamiento de la página en otra tarea
diferente.
Ciclo de vida de un subproceso
El programa
inicia el subproceso

Adquiere bloqueo
Se completa E/S
Interrupt
El intervalo expira
Wait Notify
slepp notifyAll
Ciclo de vida de hilos
 Un nuevo subproceso empieza su ciclo cuando hace la
transición al estado nuevo; permanece en este estado hasta
que el programa inicia el subproceso, con lo cual se coloca en el
estado ejecutable.
 Se considera que un subproceso en el estado ejecutable está
ejecutando su tarea.

 Algunas veces, un subproceso ejecutable cambia al estado en


espera mientras espera a que otro subproceso realice una
tarea.
 Un subproceso en espera regresa al estado ejecutable sólo
cuando otro subproceso notifica al subproceso esperando que
puede continuar ejecutándose.
Ciclo de vida de hilos
 Un subproceso ejecutable puede entrar al estado en espera
sincronizado durante un intervalo específico de tiempo. Regresa
al estado ejecutable cuando ese intervalo de tiempo expira, o
cuando ocurre el evento que está esperando.
 Los subprocesos en espera sincronizado y en espera no pueden
usar un procesador, aun cuando haya uno disponible.
 Un subproceso ejecutable puede cambiar al estado en espera
sincronizado si proporciona un intervalo de espera opcional
cuando está esperando a que otro subproceso realice una tarea.
Dicho subproceso regresa al estado ejecutable cuando se lo
notifica otro subproceso, o cuando expira el intervalo de
tiempo; lo que ocurra primero.
Ciclo de vida de hilos
 Otra manera de colocar a un subproceso en el estado en espera
sincronizado es dejar inactivo un subproceso ejecutable.
 Un subproceso inactivo permanece en el estado en espera
sincronizado durante un periodo designado de tiempo(conocido como
intervalo de inactividad), después del cual regresa al estado
ejecutable. Los subprocesos están inactivos cuando, en cierto
momento, no tienen una tarea que realizar.
 Un subproceso ejecutable cambia al estado bloqueado cuando trata
de realizar una tarea que no puede completarse inmediatamente, y
debe esperar temporalmente hasta que se complete esa tarea.

 Un subproceso ejecutable entra al estado terminado (algunas veces


conocido como el estado muerto) cuando completa exitosamente su
tarea, o termina de alguna otra forma (tal vez debido a un error).
Creación y ejecución de
subprocesos
 El medio preferido de crear aplicaciones en Java con
subprocesamiento múltiple es mediante la implementación de
la interfaz Runnable

Un objeto Runnable representa una “tarea” que puede ejecutarse


concurrentemente con otras tareas.

La interfaz Runnable declara un solo método, run, el cual contiene el código


que define la tarea que debe realizar un objeto Runnable. Cuando se crea e
inicia un subproceso que ejecuta un objeto Runnable, el subproceso llama al
método run del objeto Runnable, el cual se ejecuta en el nuevo subproceso.
Objetos Runnable y la
clase Thread

En Java para utilizar la multitarea debemos de


usar la clase Thread (es decir que la clase que
implementemos debe heredar de la clase
Thread) y la clase Thread implementa
la Interface Runnable. En el siguiente diagrama
de clase mostramos la Interface Runnable y la
clase Thread con sus principales métodos:
Creación de Hilos

Existen dos modos de crear Hilos en Java


 Extender la clase Thread
 Implementar la interface Runnable
Prioridades y Programación de
subprocesos
Todo subproceso tiene una prioridad en el rango entre
ThreadPriority.Lowest y ThreadPriority.Highest.
Estos valores provienen de la enumeración ThreadPriority
(espacio de nombres System.Threading), la cual consiste de los
valores Lowest, BelowNormal, Normal, AboveNormal y Highest.
De manera predeterminada, cada subproceso tiene la prioridad
Normal.
Prioridades y Programación
de subprocesos
El trabajo del programador de subprocesos es mantener el subproceso
de mayor prioridad en ejecución en todo momento y, si hay más de un
proceso de mayor prioridad, debe asegurarse que todos los
subprocesos se ejecuten durante un cuanto cada uno, en forma cíclica
(round-robin).

La prioridad de un subproceso puede ajustarse mediante la propiedad


Priority, la cual acepta valores de la enumeración ThreadPriority. Si el
valor especificado no es una de las constantes válidas de prioridad de
subprocesos, se produce una excepción ArgumentException.
4.3 Creación y control de Hilos
(Subprocesos)
Ejemplo:
El programa crea tres subprocesos de ejecución, cada uno con la
prioridad predeterminada Normal. Cada subproceso muestra un
mensaje indicando que estará inactivo durante un intervalo
aleatorio de 0 a 6000 milisegundos, y luego se vuelve inactivo.
Cuando cada subproceso despierta, muestra su nombre, indica
que ha dejado de estar inactivo, termina y entra al estado
Stopped (detenido).

El programa consta de dos clases: ProbadorSubprocesos (la cual


crea los tres subprocesos, e ImpresoraMensajes, que define a un
método Imprimir que contiene las acciones que cada subproceso
llevará a cabo.
Practica Hilos1 (java)
package hilos;

public class ProbadorSubprocesos {

public static void main(String[] args) {


ImpresoraMensajes subproceso1 = new ImpresoraMensajes();
ImpresoraMensajes subproceso2 = new ImpresoraMensajes();
ImpresoraMensajes subproceso3 = new ImpresoraMensajes();

subproceso1.setName("Subproceso1");
subproceso2.setName("Subproceso2");
subproceso3.setName("Subproceso3");

System.out.println("Iniciando Procesos...");
subproceso1.start();
subproceso2.start();
subproceso3.start();
System.out.println("Procesos Iniciados...");
}

}
Practica Hilos1 (java)
package hilos;
public void imprimir() {
import java.util.Random;
Thread actual = Thread.currentThread();
import java.util.logging.Level;
System.out.println(actual.getName()+
import java.util.logging.Logger;
" va estar inactivo "+tiempoInactividad+
public class ImpresoraMensajes extends Thread{ " milisegundos");
try {
private final int tiempoInactividad; Thread.sleep(tiempoInactividad);
private static final Random aleatorio = } catch (InterruptedException ex) {
new Random();
Logger.getLogger(
public ImpresoraMensajes() {
ImpresoraMensajes.class.getName()).
tiempoInactividad = aleatorio.nextInt(6001);
} log(Level.SEVERE, null, ex);
}
@Override System.out.println(actual.getName()+
public void run() { " Dejo de estar inactivo ");
imprimir(); }
}
}
Hilos2 (java)
Vamos a simular el proceso de cobro de un supermercado; es decir, unos
clientes van con un carro lleno de productos y una cajera les cobra los
productos, pasándolos uno a uno por el escáner de la caja registradora.
En este caso la cajera debe de procesar la compra cliente a cliente, es
decir que primero le cobra al cliente 1, luego al cliente 2 y así
sucesivamente.
Para ello vamos a definir una clase "Cajera" y una clase "Cliente" el cual
tendrá un "array de enteros" que representaran los productos que ha
comprado y el tiempo que la cajera tardará en pasar el producto por el
escaner; es decir, que si tenemos un array con [1,3,5] significará que el
cliente ha comprado 3 productos y que la cajera tardara en procesar el
producto 1 '1 segundo', el producto 2 '3 segundos' y el producto 3 en '5
segundos', con lo cual tardara en cobrar al cliente toda su compra '9
segundos'.
Practica_Subprocesos2
Elaborar un Formulario, que contenga 2 botones, uno se llamara
btIniciar y el segundo btMostrar, una barra de Procesos que
mostrara el avance de la consulta. La acción del primer botón
consistirá en simular la espera de una consulta a la BD, un
aproximado de 4 segundos y posteriormente enviar un mensaje
de transacción concluida a través de un Mensaje emergente
(JOptionPane), Al momento de iniciar el evento del botón Iniciar
Proceso, también se deberá mostrar el avance del proceso a
través de una etiqueta lbProceso ubicada en la parte superior de
la barra de proceso.
4.4 Sincronización de Hilos.
Una de las ventajas de utilizar varios subprocesos en una aplicación es
que cada subproceso se ejecuta de forma asincrónica.

En las aplicaciones para Windows, esto permite realizar las tareas que
exigen mucho tiempo en segundo plano mientras la ventana de la
aplicación y los controles siguen respondiendo.

En las aplicaciones de servidor, el multithreading proporciona la


capacidad de controlar cada solicitud de entrada con un subproceso
diferente. De lo contrario, no se atendería cada nueva solicitud hasta
que se hubiera satisfecho totalmente la solicitud anterior.
Sincronización de Hilos.

Sin embargo, la naturaleza asincrónica de los subprocesos


significa que el acceso a recursos como identificadores de
archivos, conexiones de red y memoria se deben coordinar.

De lo contrario, dos o más subprocesos podrían tener acceso al


mismo tiempo al mismo recurso, cada uno desprevenido de las
acciones del otro.

El resultado serían daños imprevisibles en los datos.


Sincronización de Hilos.

Para resolver este problema, es necesario proporcionar a un


proceso a la vez el acceso exclusivo al código que manipula los
datos compartidos.

Durante ese tiempo, otros subprocesos que deseen manipular los


datos deben mantenerse en espera.

Cuando el subproceso con acceso exclusivo a los datos complete


sus manipulaciones de datos, se debe permitir que uno de los
subprocesos en espera proceda.
Sincronización de Hilos.

sincronización de subprocesos (exclusión mutua)

Ocurre cuando cada subproceso que acceda a los datos


compartidos excluye a todos los demás de hacerlo en forma
simultánea.

C# utiliza los monitores del .NET Framework para realizar la


sincronización.
La clase Monitor proporciona los métodos para bloquear objetos
e implementar el acceso sincronizado a los datos compartidos.
Sincronización de Hilos.
Bloquear un objeto significa que sólo un subproceso puede
acceder a ese objeto en un momento dado. Cuando un
subproceso desea adquirir el control exclusivo sobre un objeto,
invoca al método Enter() de Monitor para adquirir el bloqueo
sobre ese objeto de datos.

Cada objeto tiene un bloque de sincronización (SyncBlock) que


mantiene el estado del bloqueo de ese objeto.
Fuentes de información

 Sharp, John, Visual C# 2008, 1 Edición, Anaya Multimedia, España,


2008
 John Dean, Introducción A La Programación Con Java, 1, Mcgraw
Hill, México, 2009
 Deitel Y Deitel, Java Cómo Programar, 7ª Edición, Prentice Hall,
México, 2008
 Deitel Y Deitel, C / C++ Y Java Cómo Programar, 4ta Edición, Prentice
Hall, México, 2004
 Consultado el 11 de Mayo 2015:http://eledwin.com/blog/tutorial-de-
hilos-en-c-con-ejemplos-parte-2-35

Você também pode gostar