400 likes | 648 Views
Programando con Hilos POSIX*. Intel Software College. Objetivos. Explorar las funciones de la librería Pthreads para crear y sincronizar hilos. ¿Qué son los pthreads?. Estándar POSIX.1c Interfaz en lenguaje C Los hilos existen dentro del mismo proceso Todos los hilos son pares
E N D
Programando con Hilos POSIX* Intel Software College
Objetivos • Explorar las funciones de la librería Pthreads para crear y sincronizar hilos Programming with POSIX* Threads
¿Qué son los pthreads? • Estándar POSIX.1c • Interfaz en lenguaje C • Los hilos existen dentro del mismo proceso • Todos los hilos son pares • No es un modelo explícito padre-hijo • Excepto: “main thread” contiene toda la información del proceso Programming with POSIX* Threads
pthread_create • int pthread_create(tid, attr, function, arg); pthread_t *tid • descriptor del hilo creado const pthread_attr_t *attr • atributos del hilo a crearse void *(*function)(void *) • función que será mapeada al hilo void *arg • argumento que se envía a la función Programming with POSIX* Threads
pthread_create Detalles • Inicia un hilo ejecutando la función • Descriptor del hilo retornado por medio de la estructura pthread_t • Especifica NULL para usar los atributos por default • Un solo argumento enviado a la función • Si no tiene argumentos, especifica NULL • Verificar códigos de error! EAGAIN – recursos insuficientes para crear el hilo EINVAL – atributo inválido Programming with POSIX* Threads
#include <stdio.h> #include <pthread.h> void *hello (void * arg) { printf(“Hello Thread\n”); } main() { pthread_t tid; pthread_create(&tid, NULL, hello, NULL); } Eejemplo: Creación del hilo ¿Qué sucede? Programming with POSIX* Threads
Esperando un Thread • int pthread_join(tid, val_ptr); pthread_t tid • manejador de un hilo a esperar void **val_ptr • valor de salida devuelto por un hilo Programming with POSIX* Threads
pthread_join Detalles • Un hilo espera a que un hilo con descriptor tid termine • Solo espera a que un hilo se una • El hilo debe ser unible • Un valor de salida se devuelve del hilo unido • Tipo devuelto es (void *) • Usar NULL si no se espera un valor de retorno ESRCH - hilo (pthread_t) no encontrado EINVAL - hilo (pthread_t) no unible Programming with POSIX* Threads
Estados de un hilo • Los hilos Pthread tienen dos estados • Unible (joinable) • Desacoplado (detached) • Por default los hilos son unibles • Los recursos se mantienen hasta el pthread_join • Pueden ser reseteados con atributos o una llamada API • Los hilos desacoplados no pueden unirse • Los recursos pueden reclamarse en la terminación • No se pueden resetear a ser unibles Programming with POSIX* Threads
#include <stdio.h> #include <pthread.h> #define NUM_THREADS 4 void *hello (void *arg) { printf(“Hello Thread\n”); } main() { int i; pthread_t tid[NUM_THREADS]; for (i = 0; i < NUM_THREADS; i++) pthread_create(&tid[i], NULL, hello, NULL); for (i = 0; i < NUM_THREADS; i++) pthread_join(tid[i], NULL); } Ejemplo: Múltiples Hilos Programming with POSIX* Threads
Activdad 1 - “HelloThreads” • Modifica el ejemplo previo para para mostrar • El mensaje “Hello Thread” apropiaido • Número de hilo único • Usa el la variable del ciclo for del CreateThread • Salida ejemplo: • Hello from Thread #0 • Hello from Thread #1 • Hello from Thread #2 • Hello from Thread #3 Programming with Windows Threads
¿Qué falla? • ¿Qué se muesta de myNum? void *threadFunc(void *pArg) { int* p = (int*)pArg; int myNum = *p; printf( “Thread number %d\n”, myNum); } . . . // from main(): for (int i = 0; i < numThreads; i++) { pthread_create(&tid[i], NULL, threadFunc, &i); } Programming with POSIX* Threads
for(int i=0;i<numThreads;i++) { pthread_create(&tid[i], NULL, thread, (void *) &i); } Contenido de la dirección 0x0001004 void *thread(void *pArg) { int *p =(int *) arg; int mynum = *p; printf(“…….. %d\n",mynum); pthread_exit(NULL); } i=0x0001004 0 1 pArg=0x0001008 0x0001004 1 p=0x000100C mynum=0x0001010 1 Programming with POSIX* Threads
Solución – Almacenamiento “Local” void *threadFunc(void *pArg) { int myNum = *((int*)pArg); printf( “Thread number %d\n”, myNum); } . . . // from main(): for (int i = 0; i < numThreads; i++) { tNum[i] = i; pthread_create(&tid[i], NULL, threadFunc, &tNum[i]); } Programming with POSIX* Threads
Pthreads Variables Mutex • Simple, flexible, y eficiente • Permiten estructuras de programación correctas para evitar condiciones de concurso • Nuevos tipos • pthread_mutex_t • Variable mutex • pthread_mutexattr_t • Atributos de mutex • Antes de usar, mutex debe ser inicializada Programming with POSIX* Threads
pthread_mutex_init • int pthread_mutex_init( mutex, attr ); pthread_mutex_t *mutex • mutex a ser inicializada const pthread_mutexattr_t *attr • atributos a ser establecidos a mutex ENOMEM – memoria insuficiente para mutex EAGAIN – recursos insuficientes (otros que no son memoria) EPERM - no privilegios para ejecutar la operación Programming with POSIX* Threads
Inicialización Alternativa • Puede usarse el inicializador estático PTHREAD_MUTEX_INITIALIZER • Usa los atributos por default • El programador debe poner atención al alcance de los mutex • Deben ser visibles a los hilos pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER; Programming with POSIX* Threads
pthread_mutex_lock • int pthread_mutex_lock( mutex ); pthread_mutex_t *mutex • mutex que intenta hacer el lock Programming with POSIX* Threads
pthread_mutex_lock Detalles • Intenta hacer el lock del mutex • Si el mutex está bloqueado por otro hilo, el hilo que llama al lock se bloquea • Mutex es detenido por el hilo que lo llama hasta que se desbloquea • Mutex lock/unlock deben ser pares, si no puede ocurrir un interbloqueo EINVAL - mutex invalido EDEADLK – el hilo llamante ya es dueño del mutex Programming with POSIX* Threads
pthread_mutex_unlock • int pthread_mutex_unlock( mutex ); pthread_mutex_t *mutex • mutex a ser desbloqueado EINVAL - mutex es inválido EPERM - el hilo llamante no es dueño del mutex Programming with POSIX* Threads
#define NUMTHREADS 4 pthread_mutex_t gMutex; // ¿porque debe ser global? int g_sum = 0; void *threadFunc(void *arg) { int mySum = bigComputation(); pthread_mutex_lock( &gMutex ); g_sum += mySum; // los hilos acceden uno a la vez pthread_mutex_unlock( &gMutex ); } main() { pthread_t hThread[NUMTHREADS]; pthread_mutex_init( &gMutex, NULL ); for (int i = 0; i < NUMTHREADS; i++) pthread_create(&hThread[i],NULL,threadFunc,NULL); for (int i = 0; i < NUMTHREADS; i++) pthread_join(hThread[i]); printf (“Global sum = %f\n”, g_sum); } Exjemplo: Uso del mutex Programming with POSIX* Threads
f(x) = 1 4.0 dx = (1+x2) 0 4.0 (1+x2) Ejemplo de Integración Numérica 4.0 static long num_steps=100000; double step, pi; void main() { inti; double x, sum = 0.0; step = 1.0/(double) num_steps; for (i=0; i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0 + x*x); } pi = step * sum; printf(“Pi = %f\n”,pi); } 2.0 0.0 1.0 X Programming with Windows Threads
Actividad 2 - Calculando Pi • Paraleliza la integración numérica usando hilos de Posix* • Como pueden las iteraciones de los ciclos dividirse entre los hilos • ¿Qué variables pueden ser locales? • ¿Qué variables necesitan ser visibles a todos los hilos? static long num_steps=100000; double step, pi; void main() { inti; double x, sum = 0.0; step = 1.0/(double) num_steps; for (i=0; i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0 + x*x); } pi = step * sum; printf(“Pi = %f\n”,pi); } Programming with Windows Threads
Variables Condición • Los semáforos son condicionales de acuerdo al contador del semáforo • Las variables condición están asociadas con una condición arbitraria • Las mismas operaciones: wait y signal • Proveen exclusión mutua Programming with POSIX* Threads
Variable condición y Mutex • Un mutex está asociado con una variable condición • Protege la evaluación de la expresión condicional • Previene condiciones de concurso entre los hilos que están enviando la señal y los hilos que esperan en la variable condición Programming with POSIX* Threads
Señales perdidas y falsas • Una señal a una variable de condición no se guarda • Si no hay un hilo esperando, la señal se pierde • Un hilo puede interbloquearse esperando una señal que no será enviada • Una variable de condición (rara vez) puede recibir señales falsas • Si las señales se hacen predecibles la ejecución es más lenta • Se requiere volver a probar la expresión de condición Programming with POSIX* Threads
Se niega la condición se necesita proceder Puede ser opcional Algoritmo de variables de condición • Evita problemas con señales perdidas y señales falsas adquiere mutex; while (condición es verdadera) espera en la variable de condición; ejecuta región crítica; actualiza condición; envía señal a los hilos que esperan; libera mutex; El mutex se libera automáticamente cuando el hilo espera Programming with POSIX* Threads
Variables Condición • pthread_cond_init, pthread_cond_destroy • Inicializa/destruye variables de condición • pthread_cond_wait • El hilo duerme hasta que se efectúa un signal a la variable de condición • pthread_cond_signal • Señal que libera la variable de condición • pthread_cond_broadcast • Broadcast que libera la variable de condición Programming with POSIX* Threads
Tipos de variables de condición • Tipos de datos usados • pthread_cond_t • La variable de condición • pthread_condattr_t • Atributos de la variable de condición • Antes de usar, la variable condición (y el mutex) deben inicializarse Programming with POSIX* Threads
pthread_cond_init • int pthread_cond_init( cond, attr ); pthread_cond_t *cond • variable condición a ser inicializada const pthread_condattr_t *attr • attributosa ser establecidos en la variable de conidición ENOMEM - insuficiente memoria para la variable condición EAGAIN - insuficientes recursos (diferentes a la memoria) EBUSY - variable de condición ya inicializada EINVAL - attr inválido Programming with POSIX* Threads
Inicialización alternativa • Puede usuarse un inicializador estático PTHREAD_COND_INITIALIZER • Usa los atributos por default • Los programadores deben estar atentos a la condición y alcance (del mutex) • Debe ser visible a los hilos pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; Programming with POSIX* Threads
pthread_cond_wait • int pthread_cond_wait( cond, mutex ); pthread_cond_t *cond • Variable condición a esperar pthread_mutex_t *mutex • Debe desbloquearse Programming with POSIX* Threads
pthread_cond_wait Detalles • El hilo se bloquea esperando una señal en cond • El mutex se desbloquea • Permite que otros hilos adquiran el lock • Cuando llega una señal, el mutex será readquirido antes de salir del pthread_cond_wait EINVAL - cond o mutex inválido EINVAL - mutex diferentes para esperaas concurrentes EINVAL - el hilo llamante no es dueño del mutex Programming with POSIX* Threads
pthread_cond_signal • int pthread_cond_signal( cond ); pthread_cond_t *cond • Variable condición a la que se le enviará la señal Programming with POSIX* Threads
pthread_cond_signal Detalles • Envía una señal a una variable condición, desbloquea un hilo bloqueado • Si no hay hilos esperando, no se toma ninguna acción • La señal no se guarda para futuros hilos • El hilo que envía la señal no requiere tener el mutex • Puede ser más eficiente • Puede haber problemas si se usan prioridades de hilos EINVAL - cond es inválida Programming with POSIX* Threads
pthread_cond_broadcast • int pthread_cond_broadcast( cond ); pthread_cond_t *cond • variable condición a recibir la señal Programming with POSIX* Threads
pthread_cond_broadcast detalles • Desbloquea todos los hilos que están esperando una variable de condición • Si no hay hilos esperando, no se toma ninguna acción • Broadcast no se almacena para hilos futuros • El hilo que envía la señal no necesita tener el mutex EINVAL - cond is inválida Programming with POSIX* Threads
Programando con hilos POSIX* Temas cubiertos • Como crear hilos que hagan trabajo encapsulado dentro de las funciones • Coordinar acceso compartido entre hilos para evitar condiciones de concurso Programming with POSIX* Threads