THREADS Sistemas Distribuidos Alvaro Ospina Sanjuan Universidad Pontificia Bolivariana Medellín 2010 Threads - procesos livianos Permiten hacer invocaciones de métodos para que se ejecuten en forma paralela al programa principal. Permite tener varias ejecuciones dentro del mismo código por lugares diferentes, pero dentro del mismo proceso. Comparten datos con el programa principal Poseen su propio contador de programa, registros y pila. Compiten con el programa principal por el procesador. Tienen cambios de contexto más rápidos que los procesos. Si el programa principal termina, mata a todos los threads. pthreads POSIX:"Programmers Operating System Interface for UNIX" - Interfaz para programación usando "threads" y lenguaje C en UNIX, establecido en el estándar IEEE POSIX 1003.1c. La implementación de pThreads requiere: Un archivo de encabezado llamado pthread.h Una biblioteca de programación llamada libpthread.a Estandar para threads POSIX (Portable Operating System Interface for UNIX) int pthread_create( pthread_t *tid, const pthread_attr_t *attr, void * (*routine)( void*), void *arg) pthread_exit(): termina el hilo sin terminar el proceso pthread_join(): Esperar a que el thread termine. Pthread_self: Id del thread actual. Compilación: gcc –o ejecutable -lpthread fuente.c Hilos pthread_t * es un puntero a un identificador de thread. pthread_attr_t * son los atributos de creación del hilo. Hay varios atributos posibles, como por ejemplo la prioridad. Se puede pasar NULL, con lo que el hilo se creará con sus atributos por defecto, generalmente es suficiente. void *(*)(void *) una función que admite un puntero void * y que devuelve void *. Esta función es la que se ejecutará como un hilo aparte. El hilo terminará cuando la función termine o cuando llame a la función pthread_exit() (o que alguien lo mate desde otra parte del código). Es bastante habitual hacer que esta función se meta en un bucle infinito y quede suspendida en un semáforo o a la espera de una señal para hacer lo que tenga que hacer y volver a quedar dormida. void * es el parámetro que se le pasará a la función anterior cuando se ejecute en el hilo aparte. De esta manera nuestro programa principal puede pasar un único parámetro (que puede ser cualquier cosa, como una estructura compleja) a la función que se ejecutará en el hilo. La función Creación de Hilos #include <pthread.h> ... pthread_t pthreadID; int param; ... void * Thread_routine(void *arg) { ... } pthread_create( &pthreadID, //Identificador numérico NULL, //Atributos ("joinable", etc.) Thread_routine, //Rutina funcional del "thread" (void *) param ); //Argumentos Destrucción de Hilos • Los "threads" pueden eliminarse por alguno de los siguientes eventos: – – • Ejecución de pthread_exit(status) Ejecución, por parte de otro "thread" de pthread_cancel(...) – Finalización del proceso dueño. – Finalización de la rutina principal (main(...)). Hay que considerar que cuando un "thread" es terminado abruptamente, sus apuntadores no son eliminados. Sincronización Hilos • • La vinculación ("joinning") es un procedimiento común para la sincronización de "threads". Cuando se ejecuta una vinculación, el "thread" invocador se bloquea hasta que el otro especificado termine. – pthread_join(threadID,&status) – pthread_detach(threadID,&status) Ejercicios de threads Ejercicio 1 Ejercicio 2 Ejercicio 3 Ejercicios calculo de pi Solución es escalable Ejercicios de threads • • Vamos a realizar división de trabajo Para este caso, de los m intervalos vamos a asignar n a cada “thread” (siendo n=m/cantidad_threads) Solución es escalable Ejercicio 1 #include<pthread.h> #include<stdio.h> #include<string.h> // Funcion que ejecuta el hilo void * function_thr(char *cadena){ sleep(5); printf("Hilo %d:mi cadena es: %s\n",pthread_self,cadena); pthread_exit(pthread_self); } int main(void){ pthread_t id; printf("Creando thread ...\n"); char *cadena=strdup("soy un thread"); pthread_create(&id, NULL,(void *)&function_thr, (void *) cadena); printf("Ppal: Esperando que el thread termine..\n"); pthread_join(id,NULL); printf("Ppal: el thread termino\n"); return 0; } Ejercicio 2 #include<pthread.h> #include<stdio.h> #include<string.h> //parametros de la funcion struct parametros{ int num; char *cadena; }; // Funcion con varios parametros que llegan en un puntero a estructura void * function_thr(struct parametros *p){ printf("Hilo:numero %d y mi cadena es: %s\n",p->num,p->cadena); pthread_exit(pthread_self); } int main(void){ //se llena la estructura de parametros del metodo struct parametros param; param.cadena=strdup("soy un thread"); param.num=15; // se lanza el thread pthread_t id; pthread_create(&id, NULL,(void *)&function_thr, (void *) &param); printf("Ppal: Esperando que el thread termine..\n"); pthread_join(id,NULL); printf("Ppal: el thread termino"); return 0; } Ejercicio 3 #include<pthread.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_THREADS 3 // cantidad de threads que se lanzan struct parametros{ int num; char *cadena; }; pthread_t tabla_thr[MAX_THREADS]; //arreglo con id de los threads struct parametros param[MAX_THREADS]; //arreglo con los parametros de los threads //funcion que recibe un puntero a la estructura de parametros del thread void * function_thr(struct parametros *p){ printf("Hilo:numero %d y mi cadena es: %s\n",p->num,p->cadena); pthread_exit(pthread_self); } int main(void){ printf("Creando threads ...\n"); int i; for(i=0;i<MAX_THREADS;i++){ param[i].cadena=strdup("soy un thread"); param[i].num=i; pthread_create(&tabla_thr[i], NULL,(void *)&function_thr, (void *) &param[i]); } printf("Ppal: Esperando que los threads terminen..\n"); for(i=0; i<MAX_THREADS;i++){ pthread_join(tabla_thr[i], NULL); printf("Ppal: el thread %d termino\n",i); } printf("Todos terminaron...\n"); return 0;