Busquedas

Programación multihilo en C
Viernes, 10 de Octubre de 2008 00:16

Las tendencia actual en los microprocesadores a la hora de aumentar el rendimiento se centra en añadir cada vez mas cores o núcleos, un ejemplo de esto son los los Core 2 Duo (Segun modelo) con 2 y 4 o incluso los 8 núcleos del procesador Cell de la PlayStation 3. Para poder aprovechar estos recursos por completo os planteo este artículo en el que hablaré de como hacer programación multihilo en C.

 

programación general
TAGS:  , , ,

Antes de entrar en harina veamos que es un hilo:
 
Un hilo de ejecución es una característica que permite a una aplicación realizar varias tareas concurrentemente. Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente, por ejemplo si programamos videojuegos podemos tener un hilo para la IA, otro para la física y otro para el renderizado de los gráficos, pero todos ellos se ejecutarán de manera paralela.
 
Los hilos se distinguen de los procesos en que los procesos son independientes, llevan bastante información de estados, e interactúan sólo a través de mecanismos de comunicación dados por el SO. Por otra parte, muchos hilos generalmente comparten otros recursos de forma directa.
 
Si bien los hilos son generados a partir de la creación de un proceso, podemos decir que un proceso es un hilo de ejecución, conocido como Monohilo. Pero las ventajas de los hilos se dan cuando hablamos de Multihilos, que es cuando un proceso tiene múltiples hilos de ejecución los cuales realizan actividades distintas, que pueden o no ser cooperativas entre sí. Los beneficios de los hilos se derivan de las implicaciones de rendimiento.
 
Las funciones que necesitaremos conocer para tratar con hilos son las siguientes (obtenidas de POSIX Threads):
 

Identificación de Hilos


int pthread_equal(pthread_t tid1, pthread_t tid2);
Retorna: no cero si es igual, cero en otro caso
Compara dos identificados de hilos tid1 y tid2 
pthread_t pthread_self(void);
Retorna: la ID del hilo que la llamó
Para obtener identificador de un hilo

Creación de Hilos

int pthread_create(pthread_t * restrict tidp,
const pthread_attr_t * restrict attr,
void * ( * start_routine ) (void *),
void * restrict arg);

tidp: salida, puntero a id del hilo
attr: entrada, para definir atributos del hilo, null para default
start_routine: entrada, función a correr por el hilo
arg: entrada, argumento de la función del hilo.
La función debe retornar un * void, el cual es interpretado
como el estatus de término por pthread_join

Término de un Hilo

void pthread_exit (void * rval_ptr); rval_ptr queda disponible para otros hilos al llamar pthread_join
rval_ptr debe existir después del término del hilo.
int pthread_join(pthread_t tid, void ** rval_ptr);
El hilo llamante se bloquea hasta el término del hilo indicado.
Si el hilo en cuestión es cancelado, rval_prt toma el valor
PTHREAD_CANCELED
Si no estamos interesados en el valor retornado, poner NULL.
int pthread_cancel(pthread_t tid);
Permite a un hilo cancelar otro hilo del mismo proceso.
Retorno 0 es OK, !=0 => error.
Equivale a si el hilo indicado llamara
pthread_exit(PTHREAD_CANCELED); sin embargo, un hilo puede
ignorar este requerimiento o controlar cómo se cancela.
pthread_cancel sólo hace un requerimiento, pero no lo fuerza.
int pthread_setcacelstate(int state, int * oldstate); Permite cambiar el estado del hilo a
PTHREAD_CANCEL_ENABLE (default) o
PTHREAD_CANCEL_DISABLE, en este estado el hilo ignora
llamados a pthread_cancel que le afecten.

 

 

Detaching y Joining en hilos (desasociar y reunión)

int pthread_detach(pthread_t tid); retorna 0 es OK, !=0 => error.
 
A continuación un ejemplo de código en el que se crean 8 hilos y se les asocia una funcion(la misma) a cada hilo, después se le pasa un valor aleatorio como parámetro y por ultimo se recibe lo que devuelve cada hilo.
 

threads.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_THREADS 8

//estructura para pasar parametros a los hilos
typedef struct {
   int id,valor;
} parameters;

parameters parametros[MAX_THREADS];
pthread_t tabla_hilos[MAX_THREADS];

//funcion que se carga en cada hilo
void *funcion_thread(parameters *p) {
 printf("Ejecutando la función en el thread con id %d al que se le ha pasado el valor %d\n", p->id,p->valor);
 pthread_exit(p->valor);
}

int main(void){
 int i, *res;

 //creamos tantos threads como MAX_THREADS
 printf("\nCreando threads...\n\n");
 for (i=0; i<MAX_THREADS; i++) {
    parametros[i].id = i;
    parametros[i].valor=rand()%100;

    pthread_create(&tabla;_hilos[i], NULL, (void *)&funcion;_thread,(void *)¶metros;[i]);
 }

 // esperamos que terminen todos los threads
 printf("\nThreads creados. Esperando que terminen...\n\n");
 for (i=0; i<MAX_THREADS; i++) {
     int *aux;
     pthread_join(tabla_hilos[i],&aux;);
     printf("El thread %d devolvio el valor %d\n", i,aux);
 }

 return 0;
}


nota: Cuando trabajamos con hilos debemos pasar los parámetros a las funciones asociadas a estos hilos mediante una estructura.
 
Podemos compilar el programa de la siguiente forma: 
$ gcc threads.c -o threads -lpthread
 
Tras compilar y ejecutar este programa genera el siguiente resultado:
 
 
Para descargar el código fuente: threads.c.zip

Si te gustó el articulo sientete libre de subscribete al feed rss
Comentarios (2)
2 Jueves, 15 de Enero de 2009 02:02
greenbite
Holas Manuel, la verdad es que POSIX no lo se, pero yo para esas cosas siempre uso la libreria STL de C++, tiene colas, pilas, etc... y si necesitas ejemplos o información mira el tomo 2 de Thinking in C++ en esta dirección:

http://www.odioworks.com/download/TICPP-2nd-ed-Vol-two.zip
1 Miércoles, 14 de Enero de 2009 12:44
manueldavid
Hola Miguel. ¿Sabes si POSIX tiene estructuras de datos como colas y cosas así?

Saludos.

Agrega tu comentario

Tu nombre:
Comentario: