1 / 26

T5-multithreading

T5-multithreading. Indice. Proceso vs. Flujos Librerías de flujos Comunicación mediante memoria compartida Condición de carrera Sección Crítica Acceso en exclusión mutua Problemas Abrazos mortales. Procesos vs. Flujos. Hasta ahora…..

raja-mcgee
Download Presentation

T5-multithreading

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. T5-multithreading

  2. Indice • Proceso vs. Flujos • Librerías de flujos • Comunicaciónmediantememoriacompartida • Condición de carrera • SecciónCrítica • Acceso en exclusiónmutua • Problemas • Abrazosmortales

  3. Procesos vs. Flujos • Hasta ahora….. • Una única secuencia de ejecución: Sólo 1 ProgramCounter y una pila • Concurrencia entre procesos, pero dentro de un proceso la ejecución era secuencial (una única secuencia de instrucciones) • No es posible ejecutar concurrentemente diferentes funciones dentro del mismo proceso • Aunque puedan haber partes del código independientes entre si

  4. Ejemplo: aplicación cliente-servidor Cliente 1 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } DATOS GLOBALES Servidor { While(){ Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); } } • Monoproceso: sólo un cliente cada vez • Se desaprovecha las ventajas de la concurrencia y del paralelismo • Multiproceso: un proceso para cada cliente simultáneo que se quiera atender • Ejecución concurrente y/o paralela • Pero… Se desaprovechan recursos • Replicación innecesaria de estructuras de datos que almacenan los mismos valores, replicación del espacio lógico de memoria, mecanismos para intercambiar información,… Cliente 2 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } Cliente N { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … }

  5. CASO : aplicación cliente-servidor Cliente 1 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } DATOS GLOBALES Servidor { While(){ INICIO_proceso Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_proceso } } Cliente 2 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } DATOS GLOBALES Servidor { While(){ INICIO_proceso Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_proceso } } DATOS GLOBALES Servidor { While(){ INICIO_proceso Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_proceso } } DATOS GLOBALES Servidor { While(){ INICIO_proceso Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_proceso } } DATOS GLOBALES Servidor { While(){ INICIO_proceso Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_proceso } } Cliente N { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … }

  6. CASO : aplicación servidor • Alternativa: procesos multiflujo • Permitir diferentes secuencias de ejecución simultáneas asociadas al mismo proceso • ¿Qué necesitamos para describir una secuencia de ejecución? • Pila • Programcounter • Valores de los registros • El resto de características del proceso puede ser única (resto del espacio lógico, información sobre los dispositivos, gestión signals, etc)

  7. Procesos vs. Flujos • Los recursos se siguen asignando en su mayoría a los procesos: • Espacio de direcciones • Dispositivos • Pero el SO planifica a nivel de Flujo (cada flujo necesita 1 CPU) • Los flujos de un proceso comparten todos los recursos asignados al proceso y todas las características • Y cada flujo tiene asociado: • Siguiente instrucción a ejecutar (valor del PC) • Zona de memoria para la pila • Estado de los registros • Un identificador • Proceso tradicional: un sólo flujo de ejecución

  8. CASO : aplicación cliente-servidor Cliente 1 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } DATOS GLOBALES Servidor { While(){ INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO } } Cliente 2 { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … } INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO INICIO_FLUJO Esperar_peticion(); Preparar_respuesta(); Enviar_respuesta(); FIN_FLUJO Cliente N { .. Enviar_peticion(); Esperar_respuesta(); Procesar_respuesta(); … }

  9. Internamente: Procesos vs. Flujos • 1 proceso con N flujos  1 PCB • N secuencias del código del proceso que se pueden ejecutar de forma concurrente • En el PCB hay espacio para guardar los contextos de los N flujos • Descripción de memoria • 1 región de código • 1 región de datos • 1 región de heap + N pilas (1 por flujo)

  10. Internamente: Procesos vs. Flujos • Compartición de memoria • Entre procesos • Por defecto la memoria es privada para un proceso y nadie la puede acceder (hay llamadas a sistema que permiten pedir zonas de memoria compartida entre procesos) • Entre flujos • Todos los threads pueden acceder a todo el espacio lógico de la tarea a la que pertenecen • Cosas a tener en cuenta en la programación con threads • Cada thread tiene su pila propia donde el compilador reserva espacio para sus variables locales, parámetros, y control de su ejecución • Todas las pilas también son visibles por todos los flujos

  11. Utilización de procesos multiflujos • Explotar paralelismo y concurrencia • Mejorar la modularidad de las aplicaciones • Aplicaciones intensivas en E/S • Flujos dedicados sólo a acceder a dispositivos • Aplicaciones servidores

  12. Ventajas de usarflujos • Ventajas de usar varios flujos en lugar de varios procesos • Coste en tiempo de gestión: creación, destrucción y cambio de contexto • Aprovechamiento de recursos • Simplicidad del mecanismo de comunicación: memoria compartida

  13. Gestión a nivel de usuario: Librerías de flujos • Los kernelsofrecen threads, pero su interfaz no es compatible (en general) como en el caso de los procesos, por eso se definió una interfaz implementada a nivel librería usuario. POSIX threads. • POSIX threads (Portable OperatingSystem Interface, definido por IEEE) • Interfaz de gestión de flujos a nivel de usuario • Creación y destrucción • Sincronización • Configuración de la planificación • El API de POSIX es muy potente, dependiendo del kernel la librería implementa toda la funcionalidad o solo parte de ella

  14. Servicios de gestión de flujos • Creación • Procesofork() • Flujos  pthread_create(outPth_id,in NULL, in function_name, in Pparam) • Identificación • Procesos: getpid() • Flujos : pthread_self() • Finalización • Procesos: exit(exit_code) • Flujos:pthread_exit(in Pthexit_code) • Sincronización fin de flujo • Procesos: waitpid(pid,ending_status, FLAGS) • Flujos:pthread_join(in thread_id, outPPexit_code) • Consultad las páginas de man para ver los tipos de datos exactos

  15. Creación de flujos • pthread_create • Crea un nuevoflujoqueejecuta la rutinastart_routinepasándolecomoparámetroarg #include <pthread.h> intpthread_create(pthread_t *th, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); th: contendrá el identificador del thread attr: características del thread (si NULL se le asignanlascaracterísticaspordefecto) start_routine: @ de la rutinaqueejecutará el nuevoflujo. Esarutinapuederecibir un sóloargumenteo de tipo void * (nombre de la función) arg: parámetro de la rutina Devuelve un código de error o 0 si ok

  16. Identificación del flujo • pthread_self • Obtiene el identificador del flujoque la ejecuta #include <pthread.h> intpthread_self(void); Devuelve el identificador del thread

  17. Destrucción de flujos • pthread_exit • La ejecuta el flujo que acaba la ejecución • Se pasa como parámetro el valor de retorno del thread #include <pthread.h> intpthread_exit(void *status); status: valor de retorno del thread Devuelve un código de error o 0 si ok

  18. Comunicaciónmediantememoriacompartida • Los flujos de un proceso pueden intercambiar información a través de la memoria que comparten • Accediendo más de uno a las mismas variables • Problema que puede aparecer: condición de carrera (racecondition) • Cuando el resultado de la ejecución depende del orden el que se alternen las instrucciones de los flujos (o procesos)

  19. Ejemplo: race condition intprimero = 1 /* variable compartida */ /* flujo 1 */ If (primero) { primero --; tarea_1(); } else { tarea_2(); } /* flujo2 */ If (primero) { primero --; tarea_1(); } else { tarea_2(); } RESULTADO INCORRECTO La idea del programador era utilizar este booleano para que se ejecutara primerola tarea1 y luego la 2 (pero cada una solo 1 vez) Lo que no tuvo en cuenta es que estas operaciones no son atómicas!!!

  20. Que tenemos en ensamblador??? haz_tarea: pushl %ebp movl %esp, %ebp subl $8, %esp movl primero, %eax testl %eax, %eax je .L2 movl primero, %eax subl $1, %eax movl %eax, primero calltarea1 jmp .L5 .L2: calltarea2 .L5: leave ret Esto es el if no es 1 instrucción Esto es la resta  no es 1 instrucción Esto es el else Que pasa si hay un cambio de contexto después del movl del if al thread 2???

  21. ¿Qué pasaría?…eax valdrá 1 al volver!! FLUJO 2 FLUJO 1 haz_tarea: pushl %ebp movl %esp, %ebp subl $8, %esp movl primero, %eax testl %eax, %eax je .L2 movl primero, %eax subl $1, %eax movl %eax, primero calltarea1 jmp .L5 .L2: calltarea2 .L5: leave ret haz_tarea: pushl %ebp movl %esp, %ebp subl $8, %esp movl primero, %eax testl %eax, %eax je .L2 movl primero, %eax subl $1, %eax movl %eax, primero call tarea1 jmp .L5 .L2: call tarea2 .L5: leave ret Cambio! Cambio!

  22. Regióncrítica • Región crítica • Líneas de código que contienen condiciones de carrera que pueden provocar resultados erróneos • Líneas de código que acceden a variables compartidas cuyo valor cambia durante la ejecución • Solución • Garantizar el acceso en exclusión mutua a estas regiones de código • ¿Evitar cambios de contexto?

  23. Exclusiónmútua • Acceso en exclusión mutua: • Se garantiza que el acceso a la región crítica es secuencial • Mientras un flujo está ejecutando código de esa región ningún otro flujo lo hará (aunque haya cambios de contexto) • El programador debe: • Identificar regiones críticas de su código • Marcar inicio y fin de la región usando las herramientas del sistema • El sistema operativo ofrece llamadas a sistema para marcar inicio y fin de región crítica: • Inicio: si ningún otro flujo ha pedido acceso a la región crítica se deja que continúe accediendo ,sino se hace que el flujo espere hasta que se libere el acceso a la región crítica • Fin: se libera acceso a la región crítica y si algún flujo estaba esperando el permiso para acceder se le permite acceder

  24. Interfaz pthreadsExc. mutua • A considerar: • Cada región crítica se identifica con una variable (global) de tipo pthread_mutex_t, por lo tanto, necesitamos 1 variable de este tipo por región. • Antes de utilizarla, hay que inicializarla, por lo tanto, antes de crear los threads es lo ideal

  25. Ejemplo: Mutex intprimero = 1 /* variables compartida */ pthread_mutex_t rc1; // Nueva, tambiéncompartida pthread_mutex_init(& rc1,NULL); // INICIALIZAMOS LA VARIABLE, SOLO 1 VEZ ….. pthread_mutex_lock(& rc1); // BLOQUEO if (primero) { primero --; pthread_mutex_unlock (& rc1); //DESBLOQUEO tarea_1(); } else { pthread_mutex_unlock(& rc1); //DESBLOQUEO tarea_2(); }

  26. Exclusiónmútua: consideraciones • Cosas que el programador debe tener en cuenta • Las regiones críticas deben ser lo más pequeñas posibles para maximizar la concurrencia • El acceso en exclusión mutua viene determinado por el identificador (variable) que protege el punto de entrada • No hace falta que tengan las mismas líneas de código • Si varias variables compartidas independientes puede ser conveniente protegerlas mediante variables diferentes

More Related