jueves, 24 de noviembre de 2011

Linux - Threads

En esta nueva entrada me gustaría hablar acerca de los hilos en C. No comentaré problemas que pueden surgir debido a la programación concurrente, eso lo dejo para futuras entradas. Es decir en esta entrada hablaré de la definición de hilo y la forma en la que podemos crearlos en C.

Ya he explicado la manera de crear diferentes procesos en Linux. En estos procesos tan solo teníamos una ejecución secuencial del código. Sin embargo, la unidad mínima de procesamiento es el hilo. Es decir, podemos tener un proceso que ejecuta diferentes hilos de ejecución. Además estas aplicaciones multihilo tienen un menor consumo que las aplicaciones multiproceso. Un hilo es mucho más rápido de crear que un proceso. Al cambiar de un hilo a otro se produce un cambio de contexto. Cada hilo posee:
  • Identificador
  • Pila
  • Conjunto de registros
  • Contador de programa
Los hilos comparten ciertos recursos con el resto de hilos como son:
  • Señales
  • Mapa de memoria
  • Ficheros abiertos
  • Semáforos
  • Temporizadores
Para saber más acerca de los hilos podemos visitar alguna página como por ejemplo wikipedia.

Los problemas que pueden presentar los hilos, como ya he dicho, los contemplaré en entradas posteriores. Por tanto a partir de ahora hablaré acerca de cómo funcionan en C. Las funciones necesarias para el manejo de hilos en C se encuentra en la biblioteca pthread.h. Estas funciones son:
  1. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*rutina)(void *), void *arg)
  2. pthread_t pthread_self(void)
  3. int pthread_join(pthread_t thread, void **value)
  4. int pthread_exit(void *value)
En pthread_create tenemos 4 parametros. El primer parámetro guardará el identificador del thread que creamos. El segundo parámetro es un puntero a una struct con los atributos del hilo (podemos pasar NULL). Estos atributos los comentaré en otra entrada. El tercer parámetro es un tipo de puntero especial, este puntero es un puntero que recibirá una función. Esta función será lo que ejecute nuestro hilo. Debemos tener en cuenta que se pasa la dirección de esta función no los parámetros, para esto tenemos el último argumento que es un puntero  y tan solo podemos pasar un parámetro. Como tan solo se puede pasar un parámetro se recomienda que sea una struct que contenga todos los datos que deseamos.

La función pthread_t pthread_self devuelve el identificador de hilo del hilo que la ejecuta. Por otra parte tenemos la función pthread_join esta función servirá para esperar a otro hilo. Recibe un identificador de hilo (parámetro thread) al que debemos esperar. El segundo parámetro es el valor de terminación del hilo. La última función es pthread_exit y es la que finaliza el hilo. Recibe un parámetro que será el valor de terminación (en forma de puntero).

Tres de estas funciones devuelven un int, es decir en caso de error devuelve -1. Todo lo anteriormente mencionado se puede mostrar con un ejemplo bastante sencillo:
    
#include 
#include 
#include 

struct param{
 char *frase;
 int numero;
};
/*
 * Función que ejecutarán los hilos.
 */
void hiloMensaje(struct param *mensa){
 printf("%s %d\n",mensa->frase, mensa->numero);
}

int main() {
 pthread_t thd1, thd2;
 struct param param1 = {"Soy el hilo: ",1};
 struct param param2 = {"Digo otra cosa ",2};
 /*
  * Creamos dos hilos
  */
 /* La función la pasaremos como (void*)nombreFuncion.
  * Es decir, hacemos un CAST a void*.
  * También es importante realizar esto con la dirección de memorio
  * de la variable que contiene los parámetros.
  */
 pthread_create (&thd1, NULL, (void*)hiloMensaje, (void*)&param1);
 pthread_create (&thd2, NULL, (void*)hiloMensaje, (void*)&param2);
 
 /*
  * Esperamos la finalización de los hilos
  */
 pthread_join(thd1, NULL);
 pthread_join(thd2, NULL);
 
 printf("Han finalizado los thread.\n");
}
En algunos casos aparece una línea 39 con etiquetas de cierre. Esto es debido a un error del script que escribe el código para que se pueda copiar y pegar. Es decir se debe ignorar esta línea de código.
Veamos una de las posibles ejecuciones de este programa:
Los hilos pueden ejecutarse en otro orden. Eso depende del algoritmo de planificación de nuestro sistema. Cabe mencionar que para compilarlo (mi SO es Debian 32) he empleado el comando: gcc hilos.c  -lpthread -o hilo
 

2 comentarios:

  1. Hola buenas, como arias si tu metodo hilo mensaje recibe dos o mas estructuras??? por que el hilo no acpeta que pases mas de un parametro al metodo hilo mensaje en este caso a menos yo no pude pasar mas de uno entonces esa es mi duda.

    ResponderEliminar
    Respuestas
    1. Apenas estoy aprendiendo de hilos, pero creo que la solución a tu problema sería crear una 3era struc que contenga a las otras 2. Saludos

      Eliminar