Servidores Multiproceso PID=1 atiende A Tema 2: Aplicaciones Multihilo, Cliente Servidor 1 t=1. A puja t=1. B puja Multiples Clientes Concurrente Web Main () for (;;) Web new_connection = accept (i, NULL, NULL); Process_new_connection(); Fork() Fork() PID=2 atiende B PID=3 atiende.. process_new_connection() if ((pid = fork()) == 0) child_main(slot); ap_scoreboard_image- >parent[slot].pid = pid; return 0; 2 Porqué Multitarea (multiples hilos o procesos) Para poder cancelar tareas independientemente. Algunos problemas son intrinsecamente paralelos: Simuladores, Servidores, Recolectores,.. Para beneficiarse de hardware con multiples procesadores. Creación de procesos P_padre int pid; if (pid= fork()) == -1) perror( error ); else if (pid == 0) /*código del proc. hijo*/ else /* código del proc. padre */ El núcleo del SO. con la llamada fork(): 1. Busca una entrada libre en la tabla de procesos y reservar memoria. 2. Asigna un identificador único al pro. hijo. 3. Realiza las copias del contexto del proc. padre para el proc. hijo. 4. Copia las tablas de control de ficheros del proc. padre para el proc. hijo. 5. Retorna al proceso padre el pid del hijo y al hijo el valor cero. 3 P_hijo 4
Procesos pesados vs. ligeros (I) Proceso pesado = proceso unix o win32 o.. Proceso ligero = hilo (thread). Un proceso pesado en un sistema operativo se representa por su código, datos en memoria, y el estado de los registros de la máquina PCB. Los hilos de un mismo proceso pesado COMPARTEN el espacio de memoria. Procesos pesados vs. ligeros (II) La compartición de una CPU entre multiples tareas de tal manera que se minimice el tiempo requerido para cambiar entre tareas. Esto se consigue compatiendo el máximo posible del entorno de ejecución del programa entre las diferente tareas de tal manera que muy poca información de estado se necesita guardar y cargar cuando se cambie de tareas. Los hilo siempre existen dentro de un proceso pesado, lo necesitan. Para poder soportar procesos ligeros (hilos de control), se dispone de múltiples pilas, una por cada hilo creado. 5 6 Implementaciones de Hilos Hilos en Java (I) A parent process may spawn child processes. parent process A process may spawn child threads a process main thread Una clase Thread gestiona un único hilo secuencial de control. Los hilos pueden crearse y destruirse dinámicamente. child processes child thread 1 child thread 2 Thread La clase Thread ejecuta instrucciones incluidas en su método. El código real ejecutado depende de la implementación dada para el método en una clase derivada. Los hilo siempre existen dentro de un proceso pesado, lo necesitan. Programas que implementan la gestión de hilos, p.ej. Java Virtual Machine. Las aplicaciones multihilo se ejecutan dentro del proceso del programa. También existen sistemas operativos que implementan en su kernel la gestión de hilos: Windows NT, y muchas variantes de Unix. MyThread class MyThread extends Thread public void //... en este caso los hilos también están dentro de un proceso. 7 8
Ejemplo Hilos en Java (I) import SomeThread ; public class RunThreads public static void main (String[] args) SomeThread p1 = new SomeThread (1); p1.start(); SomeThread p2 = new SomeThread (2); p2.start(); SomeThread p3 = new SomeThread (3); p3.start(); // end class RunThreads public class SomeThread extends Thread int myid; SomeThread(int id) this.myid = id; public void run( ) int i; for (i = 1; i < 11; i++) System.out.println ("Thread"+myID + ": " + i); //end class SomeThread Una clase Thread tiene que implementar el metodo, Una clase Thread se inicia llamando al metodo start(). 9 Ejecución de Ejemplo Salida Ejecución RunThreads: Thread3: 1 Thread3: 2 Thread3: 3 Thread1: 1 Thread1: 2 Thread1: 3 Thread1: 4 Thread1: 5 Thread1: 6 Thread1: 7 Thread1: 8 Thread1: 9 Thread1: 10 Thread3: 4 Thread3: 5 Thread3: 6 Thread3: 7 Thread3: 8 Thread3: 9 Thread3: 10 Thread2: 1 Thread2: 2 Thread2: 3 Thread2: 4 Thread2: 5 Thread2: 6 Thread2: 7 Thread2: 8 Totalmente Concurrente (aunque la salida de linux vs. Window suele diferir) Salida Ejecución RunThreads con sleep(10): Thread1: 1 Thread2: 1 Thread3: 1 Thread1: 2 Thread2: 2 Thread3: 2 Thread2: 3 Thread1: 3 Thread3: 3 Thread2: 4 Thread1: 4 Thread3: 4 Thread2: 5 Thread3: 5 Thread1: 5 Thread2: 6 Thread3: 6 Thread1: 6 Thread2: 7 Thread3: 7 Thread1: 7 Thread2: 8 Thread3: 8 Cada 10 seg. los 3 hilos escriben concurrentemente. 10 Hilos en Java (II) Se puede implementar el método directamente desde el interfaz Runnable, y asociarle un Thread para su ejecución. Este manera de usar hilos es más versátil, ya que puede derivarse de otras clases. Runnable MyRun target Thread Public interface Runnable public abstract void ; class MyRun implements Runnable public void //... 11 Ejemplo Hilos en Java (II) public class RunThreads2 public static void main (String[] args) Thread p1 = new Thread(new SomeThread2(1)); p1.start(); Thread p2 = new Thread(new SomeThread2(2)); p2.start(); Thread p3 = new Thread(new SomeThread2(3)); p3.start(); Un constructor de clase Thread: public Thread(Runnable target) class SomeThread2 implements Runnable int myid; SomeThread2(int id) this.myid = id; public void int i; for (i = 1; i < 11; i++) System.out.println ("Thread"+myID + ": " + i); //end class SomeThread 12
Ciclo de vida de un hilo en Java hilo finalizado? (I) start() sleep(),join() public class RunThreads3 public static void main (String[] args) int originalthreadcount = Thread.activeCount( ); for (int i=0; i<10; i++) Thread p = new Thread(new SomeThread3()); p.start(); start() comienza el hilo, siempre llama a sleep(x) duerme el hilo un tiempo. join() espera a que otro hilo finalice. 13 while (Thread.activeCount() > originalthreadcount ) // loop until all child threads have exited. // todos los hilos finalizados, continua. 14 hilo finalizado?(ii): isalive() hilo finalizado? (III): join() // Create and start a thread Thread thread = new MyThread(); thread.start(); // Create and start a thread Thread thread = new MyThread(); thread.start(); // Check if the thread has finished // in a non-blocking way while (thread.isalive()) // Thread has not finished else // otro hilo finalizado, continua. // Wait indefinitely for the thread to finish try Bloqueante thread.join(); // otro hilo finalizado, continua.. catch (InterruptedException e) // Thread was interrupted 15 16
Race Condition en Threads Syncronize en Threads class SomeThread3 implements Runnable static int count=0; SomeThread3() super(); public void update(); static public void update( ) int mycount = count; int second = (int)(math.random( ) * 500); try Thread.sleep(second); catch (InterruptedException e) mycount++; count = mycount; System.out.println("count= "+count); Instruction execution order: Hilo 1 llama update, Hilo 2 llama update, Hilo 1: count = 1 Time Hilo 2: count = 2 Hilo 3: count = 2 Hilo 4: count = 1 Hilo 5: count = 1 No DESEADO 17 class SomeThread3 implements Runnable static int count=0; SomeThread3() super(); public void update(); static public synchronized void update( ) int mycount = count; int second = (int)(math.random( ) * 500); try Thread.sleep(second); catch (InterruptedException e) mycount++; count = mycount; System.out.println("count="+count); Instruction execution order: Hilo 1 llama update, Hilo 1: count = 1 Hilo 2 llama update, Hilo 2: count = 2 Hilo 3 llama update, Hilo 3: count = 3 Time Hilo 4 llama update, Hilo 4: count = 4 18 Multiples Clientes Concurrentes Paradigma Cliente Servidor Multiples Cliente Un Servidor t=1. A puja 50E por BMW Hilo 1 atiende A Hilo 2 atiende B Servidor sin conexión: Usa IPC sin conexión (p.ej., datagram socket) Las sesiones con clientes concurrentes se pueden intercalar. t=1. B puja 60E por BMW H1 H2 H3 ebay Hilo 3 atiende C Servidor con conexión: Usa IPC con conexión (p.ej. stream-mode socket ) Sesiones con clientes concurrentes solo pueden ser secuenciales. Concurrencia necesita servidor multitarea. t=1. C Lee Puja Actual de BMW. 19 20
Sesiones de clientes concurrentes con servidor sin conexión Echo1 client 1 client2 21 Servidor con Sockets sin conexión public class Echo1 public static void main(string[] args) // instantiates a datagram socket for both sending and receiving data MyDatagramSocket mysocket = new MyDatagramSocket(serverPort); while (true) // forever loop DatagramMessage request = mysocket.receivemessageandsender(); String msg = request.getmessage( ); mysocket.sendmessage(request.getaddress( ), request.getport( ), msg); //end while public class MyDatagramSocket extends DatagramSocket MyDatagramSocket(int portno) throws SocketException super(portno); public void sendmessage(inetaddress receiverhost, int receiverport, string ); public String receivemessage( ); public DatagramMessage receivemessageandsender( ); //end class Servidor = Sesión cliente. 22 Servidores Iterativos (socket con conexión) Sesiones cliente consecutivas. Echo2 Client 1 Message 1a Echo 1a Message 2a Message 1b Echo 1b Message. Echo 2a Message 2b Echo 2b Client 2 Servidor Iterativo (socket con conexión) public class Echo2 public static void main(string[] args) Socket myconnectionsocket = new Socket(serverPort); while (true) // forever loop MyStreamSocket mydatasocket = new MyStreamSocket (myconnectionsocket.accept( )); boolean done = false; while (!done) = mydatasocket.receivemessage( ); if ((.trim()).equals (endmessage)) mydatasocket.close( ); done = true; //end if else mydatasocket.sendmessage(); //end else //end while!done //end while forever servidor. sesión cliente. 23 24
Servidor concurrente: sesiones concurrentes Sequence diagram Echo3 accept Echo3 Echo3 thread 1 EchoClient 1 EchoClient2 Echo3 client 1 client2 accept Echo3 thread 2 25 26 Servidor MultiHilo import java.io.*; import java.net.*; public class Echo3 public static void main(string[] args) int serverport = 7; // default port String ; try // instantiates a stream socket for accepting // connections Socket myconnectionsocket = new Socket(serverPort); while (true) // forever loop // wait to accept a connection MyStreamSocket mydatasocket = new MyStreamSocket (myconnectionsocket.accept( )); // Start a thread to handle this client's sesson Thread thethread = new Thread(new EchoThread(myDataSocket)); thethread.start(); //end while forever // end try catch (Exception ex) ex.printstacktrace( ); // end catch //end main // end class Cliente Por cada cliente: Nuevo thread, Start thread. Hilo1 JVM Hilo2 Thread new Thread() Thread.start() PID3 27 Hilo Atiende un Cliente import java.io.*; class EchoThread implements Runnable static final String endmessage = "."; MyStreamSocket mydatasocket; EchoThread(MyStreamSocket mydatasocket) this.mydatasocket = mydatasocket; public void run( ) boolean done = false; String ; try while (!done) = mydatasocket.receivemessage( ); if ((.trim()).equals (endmessage)) mydatasocket.close( ); done = true; //end if else mydatasocket.sendmessage(); //end else //end while!done // end try catch (Exception ex) System.out.println("Exception " + ex); // end catch //end run //end class Cliente Constructor recibe un DataSocket. El código en se ejecuta para cada petición. Hilo1 JVM Hilo2 Thread PID3 28