PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

31
Programación Paralela Programación con Threads 1 PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela Programación con THREADS • David R. Butenhof: Programming with POSIX Threads. Addison-Wesley. 1996. Cap 1, 2, 3, 4 Ejemplos en: www.awl.com/cseng/titles/0-201-63392-2

description

PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela. Programación con THREADS David R. Butenhof: Programming with POSIX Threads. Addison-Wesley. 1996. Cap 1, 2, 3, 4 Ejemplos en: www.awl.com/cseng/titles/0-201-63392-2. Threads/Procesos. Thread tiene: - PowerPoint PPT Presentation

Transcript of PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Page 1: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 1

PROGRAMACIÓN PARALELA

Tema 2: Lenguajes y modelos de programación paralela

Programación con THREADS

• David R. Butenhof: Programming with POSIX Threads. Addison-Wesley. 1996.

Cap 1, 2, 3, 4

Ejemplos en:

www.awl.com/cseng/titles/0-201-63392-2

Page 2: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 2

• Thread tiene:– Dirección de instrucción– Pila– Registro de datos

• Proceso tiene:– Lo del thread +– Espacio de direcciones– Descriptores de ficheros

• Threads en un proceso comparten:– Espacio de direcciones– Descriptores de ficheros

Threads/Procesos

Page 3: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 3

• Thread:– Entidad capaz de actividad independiente

• Elementos compartidos:– Memoria– Objetos para sincronización (mutex)

• Mecanismos de comunicación:– Indicar cambios en datos compartidos (variables condición)– Los threads esperan a que se cumpla una condición– Se pueden señalar o hacer broadcast

Elementos de programación con Threads

Page 4: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 4

• Contexto de ejecución:

Debe mantenerse independiente

• Política de Scheduling:

Determina qué contexto se ejecuta en cada instante y el paso de uno a otro

• Sincronización:

Mecanismos para coordinar el uso de recursos compartidos: mutex, variables de condición, semáforos, eventos, mensajes, ...

Control de concurrencia

Page 5: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 5

• Beneficios:– Explotación del paralelismo– Explotación de concurrencia (I/O)– Estilo de programación

• Inconvenientes:– Overhead por creación de threads– Sincronización: más bloqueos al haber más threads– Colisiones en el acceso a memoria– Más difícil la depuración: debuggers, trazadores, puntos de ruptura,

repreducción de la ejecución, ...

• Uso de programación con threads:– Computación intensiva– Varios procesadores– Solapamiento computación y I/O– Aplicaciones servidor distribuidas

Uso de Threads

Page 6: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 6

Programa:

Un único proceso que procesa comandos simples en los que se dice que recuerde una alarma después de un intervalo de tiempo.

Inconveniente:

Sólo se puede procesar una alarma detrás de otra.

Ejemplo alarm secuencial

Page 7: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 7

int main (int argc, char *argv[]){ int seconds; char line[128]; char message[64];

while (1) { printf ("Alarm> "); if (fgets (line, sizeof (line), stdin) == NULL) exit (0); if (strlen (line) <= 1) continue; /* Parse input line into seconds (%d) and a message * (%64[^\n]), consisting of up to 64 characters * separated from the seconds by whitespace. */ if (sscanf (line, "%d %64[^\n]", &seconds, message) < 2) { fprintf (stderr, "Bad command\n"); } else { sleep (seconds); printf ("(%d) %s\n", seconds, message); } } }

Page 8: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 8

Programa:

el proceso principal lee peticiones de alarma,

pone en marcha un proceso hijo por cada petición de alarma,

cada proceso hijo espera el tiempo correspondiente y escribe el mensaje de alarma.

Ejemplo alarm_fork, procesos

Page 9: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 9

#include <sys/types.h>#include <wait.h>

int main (int argc, char *argv[]){ int status; char line[128]; int seconds; pid_t pid; char message[64]; ... else { pid = fork (); if (pid == (pid_t)-1) errno_abort ("Fork"); if (pid == (pid_t)0) { /*If we're in the child, wait and then print a message*/ sleep (seconds); printf ("(%d) %s\n", seconds, message); exit (0); } else {/*In the parent, call waitpid() to collect any children that have already terminated*/ do { pid = waitpid ((pid_t)-1, NULL, WNOHANG); if (pid == (pid_t)-1) errno_abort ("Wait for child"); } while (pid != (pid_t)0); } } } }

Page 10: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 10

Ejemplo alarm_thread, threads

Programa:

Como el de procesos pero usando threads.

Usa:– pthread_create, para crear un thread e indicar la rutina que tiene que ejecutar,– pthread_detach, para retomar los recursos una vez acaba el thread,– pthread_exit, para acabar el thread

Page 11: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 11

#include <pthread.h>

typedef struct alarm_tag { int seconds; char message[64];} alarm_t;

/*Rutina que usan los threads*/void *alarm_thread (void *arg){ alarm_t *alarm = (alarm_t*)arg; int status;

status = pthread_detach (pthread_self ()); if (status != 0) err_abort (status, "Detach thread"); sleep (alarm->seconds); printf ("(%d) %s\n", alarm->seconds, alarm->message); free (alarm); return NULL;}

Page 12: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 12

int status; char line[128]; alarm_t *alarm; pthread_t thread;

while (1) {

...

alarm = (alarm_t*)malloc (sizeof (alarm_t));

if (alarm == NULL)

errno_abort ("Allocate alarm");

if (sscanf (line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) {

fprintf (stderr, "Bad command\n");

free (alarm);

} else {

status = pthread_create (&thread, NULL, alarm_thread, alarm);

if (status != 0)

err_abort (status, "Create alarm thread");

}

}

Page 13: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 13

pthread_t thread;

int pthread_equal (pthread_t t1,pthread_t t2);

int pthread_create (pthread_t *thread,const pthread_attr_t *attr,void *(*start)(void *),void *arg);

Int sched_yield (void);

pthread_t pthread_self (void);

int pthread_exit (void *value_ptr);

int pthread_detach (pthread_t thread);

int pthread_join (pthread_t thread,void **value_ptr);

Uso de threads

Page 14: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 14

• Un thread se representa por un identificador, de tipo pthread_t• Un thread se pone en marcha llamando a la función cuya dirección se

pasa como tercer parámetro de pthread_create. Esta función recibe un argumento de tipo void * y devuelve lo mismo. Devuelve un identificador de thread.

• pthread_self lo puede usar un thread para conocer su identificador.• pthread_equal se usa para comprobar si dos indentificadores de thread

se refieren al mismo thread.• pthread_detach se usa para decir al sistema que puede utilizar los

recursos que se asignaron al thread. El detach lo puede hacer cualquier thread que sepa su identificador de thread. En la creación se puede especificar con un atributo que no se quiere tener control sobre el thread.

• pthread_join se usa para bloquear hasta que acaba el thread. Libera los recursos del thread.

Uso de threads

Page 15: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 15

• Se puede sincronizar asegurando el acceso en exclusión mutua a variables. Se usan mutex.

• O usando variables condición, que comunican información sobre el estado de datos compartidos

Sincronización

Page 16: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 16

• pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;Un mutex se representa por una variable de tipo pthread_mutex_t.No se debe hacer copias de mutex, pero sí se pueden copiar punteros a

mutex, para usarlos varios threads.Para crear un mutex estático con atributos por defecto se usa la macro

PTHREAD_MUTEX_INITIALIZER.• int pthread_mutex_init (pthread_mutex_t *mutex,

pthread_mutexattr_t *attr);Se usa para inicializar un mutex dinámicamente o con atributos que no son

los de defecto.Cada mutex se debe inicializar una única vez antes de usarse.• int pthread_mutex_destroy (pthread_mutex_t *mutex);Para destruir un mutex.Lo normal es asociar el mutex con los datos que protege, y destruir el

mutex antes de liberar la memoria de esos datos.

Creación y destrucción de mutex

Page 17: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 17

• int pthread_mutex_lock (pthread_mutex_t *mutex);

Bloquea un mutex.

No se puede bloquear un mutex cuando el thread ya lo tiene bloqueado. Esto devuelve un código de error, o se bloquea el thread.

• int pthread_mutex_unlock (pthread_mutex_t *mutex);

Para desbloquear mutex.

No se puede desbloquear un mutex desbloqueado, ni un mutex bloqueado por otro thread, pues los mutex pertenecen a los threads que los bloquean.

• int pthread_mutex_trylock (pthread_mutex_t *mutex);

Bloquea un mutex si no está bloqueado.

Bloqueo y desbloqueo de mutex

Page 18: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 18

• Se utiliza una lista de alarmas, ordenadas por tiempo de expiración.

typedef struct alarm_tag {

struct alarm_tag *link;

int seconds;

time_t time; /* seconds from EPOCH */

char message[64];

} alarm_t;

pthread_mutex_t alarm_mutex=PTHREAD_MUTEX_INITIALIZER;

alarm_t *alarm_list = NULL;

Ejemplo alarm_mutex

Page 19: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 19

• Se usa un único thread para tratar las alarmas.

• Acaba cuando acaba el thread principal.

Se podría modificar usando una variable que indique que se ha acabado el trabajo. Cuando el thread encuentra la lista vacía y esa variable a fin puede acabar con pthread_exit.

• Con sched_yield se cede el procesador a otro thread, y si no hay ninguno esperando vuelve el control al que llama.

Ejemplo alarm_mutex

Page 20: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 20

void *alarm_thread (void *arg){ alarm_t *alarm; int sleep_time; time_t now; int status;/*Bucle infinito para procesar los comandos*/ while (1) { status = pthread_mutex_lock (&alarm_mutex); if (status != 0) err_abort (status, "Lock mutex"); alarm = alarm_list; if (alarm == NULL) sleep_time = 1; /*Si vacía esperar un segundo*/ else { alarm_list = alarm->link; now = time (NULL); /*Si no tomar el primero*/ if (alarm->time <= now) sleep_time = 0; /*Y calcular espera*/ else sleep_time = alarm->time - now; } status = pthread_mutex_unlock (&alarm_mutex); if (status != 0) err_abort (status, "Unlock mutex"); if (sleep_time > 0) sleep (sleep_time); else sched_yield (); /*If a timer expired, print the message and free the structure.*/ if (alarm != NULL) { printf ("(%d) %s\n", alarm->seconds, alarm->message); free (alarm); } } }

Page 21: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 21

int main (int argc, char *argv[]){ int status; char line[128]; alarm_t *alarm,**last,*next; pthread_t thread; status = pthread_create (&thread, NULL, alarm_thread, NULL); if (status != 0) err_abort (status, "Create alarm thread"); while (1) { printf ("alarm> "); if (fgets (line, sizeof (line), stdin) == NULL) exit (0); if (strlen (line) <= 1) continue; alarm = (alarm_t*)malloc (sizeof (alarm_t)); if (alarm == NULL) errno_abort ("Allocate alarm"); if (sscanf (line,"%d %64[^\n]",&alarm->seconds,alarm->message)<2) { fprintf (stderr, "Bad command\n"); free (alarm); } else { status = pthread_mutex_lock (&alarm_mutex); if (status != 0) err_abort (status, "Lock mutex"); alarm->time = time (NULL) + alarm->seconds; last = &alarm_list; /*Insertar la nueva alarma*/ next = *last; while (next != NULL) { if (next->time >= alarm->time) { alarm->link = next; *last = alarm; break; } last = &next->link; next = next->link; } if (next == NULL) { *last = alarm; alarm->link = NULL; } status = pthread_mutex_unlock (&alarm_mutex); if (status != 0) err_abort (status, "Unlock mutex"); } } }

Page 22: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 22

• Problemas:– Una vez se toma una alarma de la cola se espera hasta

que expira.– Cuando no hay alarmas que atender espera un

segundo. Durante este tiempo puede venir otra alarma que haya que atender.

• Solución:

Usar variables condición.

Ejemplo alarm_mutex

Page 23: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 23

• pthread_cond_t cond=PTHREAD_COND_INITIALIZER;Una variable condición se representa por una variable de tipo

pthread_cond_t.No se debe hacer copias de variables condición, pero sí se pueden

copiar punteros a ellas, para usarlas varios threads.Para crear una variable condición estática con atributos por defecto se

usa la macro PTHREAD_COND_INITIALIZER.• int pthread_cond_init (pthread_cond_t *cond,

pthread_condattr_t *attr);Se usa para inicializar una variable condición dinámicamente o con

atributos que no son los de defecto.Cada variable condición se debe inicializar una única vez antes de

usarse.• int pthread_cond_destroy (pthread_cond_t *cond);Para destruir una variable condición.Lo normal es asociar el mutex y la variable condición con los datos que

protegen.

Creación y destrucción de variables condición

Page 24: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 24

• int pthread_cond_wait (pthread_cond_t *cond,

pthread_mutex_t *mutex);

Cada variable condición se asocia a un mutex.

Cuando un thead espera en una variable condición el mutex debe estar bloqueado.

La operación wait desbloquea el mutex antes de bloquear el thread, y lo bloquea antes de volver a la ejecución.

El predicado se debe testear después de bloquear el mutex y antes de esperar en la varaible condición.

El predicado se debe testear al ser activado.• int pthread_cond_timedwait (pthread_cond_t *cond,

pthread_mutex_t *mutex,

struct timespec *expiration);

Espera como mucho el tiempo que se indica.

Espera en variables condición

Page 25: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 25

• Int pthread_cond_signal (pthread_cond_t *cond);

Activa un thread que espera en la variable condición.

• Int pthread_cond_broadcast (pthread_cond_t *cond);

Activa todos los threads que esperan en la variable condición.

Cuando los threads se activan tendrán que volver a evaluar el predicado y algunos de ellos posiblemente se volverán a bloquear.

Activación de variables condición

Page 26: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 26

• El thread está en una variable condición mientras espera para dar la alarma.

• Si el main procesa una nueva alarma activa al threads para que compare la alarma que está esperando a procesar con la nueva alarma.

• Se usa una función para insertar en la lista de alarmas. Será llamada por el main y el thread.

Ejemplo alarm_cond

Page 27: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 27

typedef struct alarm_tag {

struct alarm_tag *link;

int seconds;

time_t time; /* seconds from EPOCH */

char message[64];

} alarm_t;

pthread_mutex_t alarm_mutex=PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t alarm_cond=PTHREAD_COND_INITIALIZER;

alarm_t *alarm_list = NULL;

time_t current_alarm = 0;

Ejemplo alarm_cond

Page 28: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 28

void alarm_insert (alarm_t *alarm){ int status; alarm_t **last, *next;/*Es necesario que el thread que llama haya bloqueado el mutex*/ last = &alarm_list; next = *last; while (next != NULL) { if (next->time >= alarm->time) { alarm->link = next; *last = alarm; break; } last = &next->link; next = next->link; } if (next == NULL) { *last = alarm; alarm->link = NULL; }/*Activar el thread si no está ocupado o la nueva alarma es la primera*/if (current_alarm == 0 || alarm->time < current_alarm) { current_alarm = alarm->time; status = pthread_cond_signal (&alarm_cond); if (status != 0) err_abort (status, "Signal cond"); } }

Page 29: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 29

void *alarm_thread (void *arg){ alarm_t *alarm; struct timespec cond_time; time_t now; int status, expired; status = pthread_mutex_lock (&alarm_mutex); if (status != 0) err_abort (status, "Lock mutex"); while (1) { current_alarm = 0; while (alarm_list == NULL) { status = pthread_cond_wait (&alarm_cond, &alarm_mutex); if (status != 0) err_abort (status, "Wait on cond"); } alarm = alarm_list; alarm_list = alarm->link; now = time (NULL); expired = 0; if (alarm->time > now) { cond_time.tv_sec = alarm->time; cond_time.tv_nsec = 0; current_alarm = alarm->time; while (current_alarm == alarm->time) { status = pthread_cond_timedwait (&alarm_cond, &alarm_mutex, &cond_time); if (status == ETIMEDOUT) { expired = 1; break; } if (status != 0) err_abort (status, "Cond timedwait"); } if (!expired) alarm_insert (alarm); } else expired = 1; if (expired) { printf ("(%d) %s\n", alarm->seconds, alarm->message); free (alarm); } } }

Page 30: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 30

int main (int argc, char *argv[]){ int status; char line[128]; alarm_t *alarm; pthread_t thread; status = pthread_create (&thread, NULL, alarm_thread, NULL); if (status != 0) err_abort (status, "Create alarm thread"); while (1) { printf ("Alarm> "); if (fgets (line, sizeof (line), stdin) == NULL) exit (0); if (strlen (line) <= 1) continue; alarm = (alarm_t*) malloc (sizeof (alarm_t)); if (alarm == NULL) errno_abort ("Allocate alarm"); if (sscanf (line, "%d %64[^\n]",&alarm->seconds, alarm->message) < 2) { fprintf (stderr, "Bad command\n"); free (alarm); } else { status = pthread_mutex_lock (&alarm_mutex); if (status != 0) err_abort (status, "Lock mutex"); alarm->time = time (NULL) + alarm->seconds; alarm_insert (alarm); status = pthread_mutex_unlock (&alarm_mutex); if (status != 0) err_abort (status, "Unlock mutex"); } }}

Page 31: PROGRAMACIÓN PARALELA Tema 2: Lenguajes y modelos de programación paralela

Programación Paralela Programación con Threads 31

En el capítulo 4, con ejemplos.

Utilizar el que se crea conveniente para programar en threads la primera práctica.

• Pipeline:

Cada thread ejecuta la misma operación sobre secuencia de datos de entrada, y pasa el resultado a otro thread.

• Granja de trabajadores:

Los threads trabajan independientemente sobre datos distintos.

• Cliente/servidor:

Un cliente pide a un servidor que haga un trabajo.

Puede ser una petición anónima que se manda a una cola de trabajos.

Modelos de programación