2. Procesos - Threads
Dos características importantes de proceso
• Es la unidad de recurso a la cual el SO le asigna recursos.
• Es la unidad de despacho .
En los modernos OS estas 2 características son tratadas
independientemente
• unidad de recurso referida como proceso o tarea
• unidad de despacho referida como thread
3. Procesos - Threads
1) Proceso: (proceso pesado)
– Unidad de propiedad de recursos del proceso
– Tiene muchos atributos
– Es caro de crear, de destruir, de cambiar de contexto, etc.
2) Hilo de ejecución: (proceso ligero, tarea, etc.)
– Actividad concurrente dentro de un proceso pesado
– Pueden existir varios hilos de ejecución en el mismo proceso
– Comparten los recursos del proceso (memoria, ficheros, etc.)
– Tienen pocos atributos (contexto) y son baratos de gestionar
4. Threads
Un thread (LWP Light Weight Process) es flujo de ejecución
de un proceso. Es la unidad básica de utilización del CPU y
está constituida por:
– PC
– Conjunto de registros
– Espacio para pila
Los threads comparten con otros threads:
-- Código
– Datos
– Archivos abiertos, señales.
6. Threads
Multithreading : cuando un OS soporta múltiples threads
dentro de un simple proceso.
Single threading: cuando el OS no reconoce el concepto de
thread.
MS-DOS: un solo proceso, un solo thread
UNIX: múltiples procesos usuarios pero un solo thread por
proceso.
SOLARIS y NT: soportan múltiples threads
8. Threads
• Thread tienen estados de ejecución
– running
– ready
– blocked
• Thread tiene un stack de ejecución.
• El contexto de los threads se salva cuando pierde el
CPU.
• Terminar un proceso acaba con todos los threads
del mismo.
11. Ventajas thread vs Proceso
• Poco tiempo para crear nuevos threads en un
proceso existente.
• Poco tiempo para terminar threads.
• Poco tiempo para switching entre threads.
12. Ejemplos de Threads
•Un thread realiza un menú display y lee los datos de
entrada del usuario, mientras que otro thread ejecuta
comandos usuarios.
•Un file server sobre LAN, un thread para cada
requerimiento
13. Threads
• Los threads tienen acceso al espacio de memoria y
recursos del proceso.
Cuando un threads altera un espacio de memoria, todos los otros del
threads del proceso lo ven.
Un archivo abierto por un thread esta disponible a los otros.
Así que los threads se pueden comunicar entre ellos
sin invocar el kernel. Sin embargo es necesario
sincronizar sus actividades para no tener
inconsistencia en la data.
14. Threads
Todos los threads corren independientemente uno
de otro, en el mismo espacio de direcciones y no son
visibles fuera del proceso.
Si los threads comparten recursos implica que un
cambio de CPU entre threads no es costoso, en
comparación con el cambio de CPU entre procesos.
Principalmente porque no se requiere realizar
trabajos de administración de memoria
15. Implementación de Threads
• Existen dos grandes categorías para la
implementación de los threads
– User-Level Threads (ULT)
– Kernel-Level Threads (KLT)
16. U L T
• El manejo de los threads es hecho por la aplicación
mediante el uso de librerías de threads.
• El OS no está conciente de los threads a nivel de
usuario .
• El switching entre Threads no requiere pasar a
modo kernel .
• Si un thread es bloqueado, causará que todo el
proceso se bloquee
17. Threads a nivel de usuario (ULT)
P
Kernel
Space
User
Space
Threads
Library
User-level threads
Pure User Level
18. Threads Library
Paquete de rutinas para gerenciar los ULTs
Contiene código para
• Crear y destruir threads
• Pasaje de mensaje y data entre threads.
• Planificación de los threads.
• Salvar y recuperar contexto de threads.
19. Ventajas de ULT
• El switching entre threads no requiere de modos
privilegiados (modo kernel). Es decir, los cambios de
contexto entre los hilos a nivel de usuario son rápidos, ya
que no involucran llamadas al sistema.
• La planificación de los threads se realiza dentro del
proceso. El scheduling puede ser específico a la
aplicación.
• ULTs puede correr sobre cualquier OS. Necesita solo la
libraría de threads.
• El sistema operativo crea sólo un hilo en el núcleo por
cada proceso
20. Inconvenientes de ULT
• System call en muchos OS son bloqueantes, esto
implica que cuando un thread ejecuta un System call,
tanto el thread como TODOS los threads del proceso
están bloqueados.
• El kernel puede solamente asignar procesos a
procesadores. Dos threads dentro del mismo proceso NO
pueden correr simultáneamente sobre dos procesadores
distintos.
21. Threads a nivel de kernel (KLT)
• El sistema operativo soporta los threads y proporciona un
conjunto de llamadas al sistema para su manipulación.
• El OS crea un thread kernel por cada thread de usuario.
• El kernel mantiene la información de contexto tanto : de
los procesos como los threads.
• Cambio de contexto entre threads es hecho por el kernel.
• Los threads a nivel de kernel se bloquean y despiertan en
forma independiente.
• El scheduling de los threads es hecho por el kernel.
22. Threads a nivel de Kernel (KLT)
Kernel
Space
User
Space
User -Level threads
Kernel-level threads
P
Kernel-level threads
23. Enfoque Combinado
Algunos OS dan la facilidad de los dos esquemas
ULT/KLT. El cual trata de combinar las ventajas de los
puros esquemas (ULT/KLT) mientras minimiza sus
desventajas.
Un ejemplo de ello es SOLARIS.
En un esquema combinado múltiples threads dentro de
una aplicación pueden correr en paralelo sobre múltiples
procesadores y un system call no bloquea el proceso.
24. Enfoque Combinado
• Creación de threads es hecho en el espacio usuario
• Scheduling y sincronización de threads
mayoritariamente es hecho en el espacio usuario
• Multiples ULTs son mapeados en menos o igual
número de KLTs.
• El programador puede ajustar el número de KLTs
• Combina lo mejor de ambos enfoques,
25. Como se programan threads?
Dos posibilidades
• Utilizando un lenguaje de programación convencional y llamadas
al sistema (o funciones de biblioteca).
– Ejemplo: Hilos POSIX (pthreads) utilizados desde C
• Utilizando construcciones lingüísticas (o clases) de un lenguaje
de programación concurrente
– Ejemplo: tareas en Ada95, threads en Java
- En este caso, el compilador traduce las construcciones
lingüísticas a:
– Llamadas al sistema (hilos a nivel de núcleo)
– Llamadas a bibliotecas propias de soporte de hilos (hilos a
nivel de usuario)
26. Hilos POSIX
1. Existe un hilo (thread) inicial que ejecuta la función main().
2. Este hilo puede crear más hilos para ejecutar otras funciones dentro
del espacio de direcciones del proceso
3. Todos los hilos de un proceso se encuentran al mismo nivel
– Esto significa que son “hermanos”, a diferencia de los procesos
cuya relación es “padre-hijo”.
1. Los hilos de un proceso comparten las variables y recursos globales
(archivos, manejadores de señales, etc.) del proceso
– Además, cada uno tiene una copia privada de sus parámetros
iniciales y de las variables locales de la función que ejecuta
27. Creacion de hilos
Creación de hilos:
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);
donde
– attr es el atributo que contiene las características que tendrá el hilo
(ver después)
– start_routine es la función que ejecutará el hilo
– arg es un puntero a los parámetros iniciales del hilo
– en thread se devuelve el identificador del hilo creado
28. Creacion de hilos (cont II)
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);
Esta llamada:
– Crea inmediatamente el hilo en estado preparado
– Produce que el hilo creado y el creador compitan por la CPU según
la política de planificación del sistema
– Puede ser invocada por cualquier hilo del proceso (no sólo por el
“hilo inicial”) para crear otro hilo
29. POSIX hilos
Atributos de creación de hilos :
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
donde
– attr es el atributo a ser creado/destruido
Mediante estas llamadas:
– Se crea/destruye un atributo de creación de hilos
– La función “init” inicializa attr con los valores por defecto
Estos valores se pueden modificar con funciones específicas
– Se pueden crear múltiples hilos con la misma variable attr
30. POSIX Hilos
Modificación de atributos de creación de hilos :
int pthread_attr_setdetachstate(pthread_attr_t *attr,
int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr,
int *detachstate);
donde
– detachstate indica si otro hilo podrá esperar a la finalización de
este hilo (mediante una instrucción pthread_join):
PTHREAD_CREATE_JOINABLE
PTHREAD_CREATE_DETACHED
31. POSIX Hilos
Modificación de atributos de creación de hilos (ii):
– Existen otras funciones, pero no se van a describir…
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param
*param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param
*param);
...
32. POSIX Hilos
Terminación y espera a la terminación de hilos:
int pthread_exit(void *exit_status);
int pthread_join(pthread_t *thread, void **exit_status);
donde
– exit_status es un puntero a una variable mediante la cual un hilo
que finaliza (pthread_exit) comunica un valor a otro que está
esperando su terminación (pthread_join)
En POSIX,
– un hilo finaliza (voluntariamente) su ejecución cuando:
Finaliza la ejecución de las instrucciones de su función, o bien
Invoca pthread_exit
– la finalización del último hilo de un proceso finaliza el proceso
33. POSIX Hilos
Identificación de hilos:
pthread_t pthread_self(void);
int pthread_equal(pthread_t th1, pthread_t th2);
donde
– pthread_self devuelve el identificador interno del hilo invocante.
– puesto que este identificador puede no ser escalar, la función
pthread_equal sirve para comparar dos identificadores. Esta
función devuelve cero (0) si dos identificadores no son iguales y otro
valor si lo son
Identificación de hilos:
pthread_t pthread_self(void);
int pthread_equal(pthread_t th1, pthread_t th2);
donde
– pthread_self devuelve el identificador interno del hilo invocante.
– puesto que este identificador puede no ser escalar, la función
pthread_equal sirve para comparar dos identificadores. Esta
función devuelve cero (0) si dos identificadores no son iguales y otro
valor si lo son
34. POSIX Hilos...
void *funcion(void *p) {
printf(“Soy un hilo feliz!n”);
}
...
int main( void ) {
pthread_t id_hilo;
pthread_attr_t atributos;
printf(“Hilo principal: principion”);
pthread_attr_init(&atributos);
pthread_create(&id_hilo, &atributos, funcion, NULL);
printf(“Hilo principal: He creado un hermanon”);
pthread_join(id_hilo,NULL);
printf(“Hilo principal: Acabo!”);
}
38. Threads in Unix-Solaris
thr_create create thread
thr_join causes the calling thread to wait until target thread is
finished
thr_exit destroy calling thread
thr_suspend suspend target thread
thr_continue make suspended thread active
thr_setconcurrency set desired number threads active at the same time to a new
parameter
thr_getconcurrency get current concurrency level
thr_setprio set thread relative priority
thr_getprio get relative priority of the thread
thr_yield causes the current thread to yield its execution in favor of another
thread with the same or greater priority
thr_kill kill a thread
thr_keycreate allocate a key that locates data specific to each thread in the process
thr_min_stack amount of space needed to execute a null thread
thr_setspecific binds thread-specific value to the key
thr get-specific gets thread-specific value of the key