2.2.1 Bibliotecas
Una biblioteca de hilos proporciona al programador una API (Application Programming Interface) para crear y administrar hilos.
Figura 7. Abstracción de biblioteca.
Hay dos formas principales de implementarla:
-
Primer enfoque: : Proporcionar una biblioteca ubicada en el espacio de usuario sin soporte de
kernel.
- Códigos y estructuras de datos para la biblioteca en espacio de usuario.
- Invocar una función en la biblioteca da como resultado una llamada de función local en el espacio del usuario y no una llamada de sistema.
-
Segundo enfoque: Implementar una biblioteca a nivel de kernel soportada directamente por el SO.
- Códigos y estructuras de datos para la biblioteca en espacio de kernel.
- Invocar una función en la API para la biblioteca generalmente resulta en una llamada de sistema al kernel.
Existen dos estrategias generales para crear múltiples hilos:
-
Hilos asincrónicos: Una vez que el padre crea un hilo hijo, el padre reanuda su ejecución, de
modo que el padre y el hijo se ejecutan de manera simultánea e independiente uno del otro.
- Debido a que los hilos son independientes, generalmente hay poco intercambio de datos entre ellos.
-
Hilos sincrónicos: Se produce cuando el hilo principal crea uno o más hilos hijos y luego debe
esperar a que todos sus hilos hijos finalicen antes de reanudarse.
- Los hilos hijos realizan el trabajo en simultáneo, pero el padre no puede continuar hasta que este trabajo se haya completado.
- Una vez finalizado cada hilo hijo se une (joins) con su padre. Solo después de que todos los hijos se hayan unido (joined), el padre puede reanudar la ejecución.
- Por lo general, los hilos sincrónicos implican un intercambio de datos significativo entre ellos. Por ej.: el hilo padre puede combinar los resultados por sus hijos.
A continuación se presenta un ejemplo de código implementado en lenguaje de programación C.
#include <stdio.h> #include <stdlib.h> #include <pthread.h> // Estructura para pasar múltiples argumentos a la función del hilo typedef struct { int thread_id; char* message; } ThreadArgs; // Función que se ejecutará en el primer hilo void* threadFunction1(void* args) { ThreadArgs* thread_args = (ThreadArgs*)args; printf("Hilo %d: %s\n", thread_args->thread_id, thread_args->message); pthread_exit(NULL); // Terminar el hilo } // Función que se ejecutará en el segundo hilo void* threadFunction2(void* args) { ThreadArgs* thread_args = (ThreadArgs*)args; printf("Hilo %d: %s\n", thread_args->thread_id, thread_args->message); pthread_exit(NULL); // Terminar el hilo } int main() { // Definir la estructura de argumentos para cada hilo ThreadArgs args1 = {1, "Hola desde el primer hilo!"}; ThreadArgs args2 = {2, "Hola desde el segundo hilo!"}; // Declarar las variables de hilo pthread_t thread1, thread2; // Crear los hilos y pasar las funciones junto con los argumentos if (pthread_create(&thread1, NULL, threadFunction1, (void*)&args1) != 0) { perror("Error al crear el primer hilo"); // Imprimir error si falla la creación del hilo exit(EXIT_FAILURE); } if (pthread_create(&thread2, NULL, threadFunction2, (void*)&args2) != 0) { perror("Error al crear el segundo hilo"); // Imprimir error si falla la creación del hilo exit(EXIT_FAILURE); } // Esperar a que los hilos terminen su ejecución if (pthread_join(thread1, NULL) != 0) { perror("Error al unir el primer hilo"); // Imprimir error si falla la espera del hilo exit(EXIT_FAILURE); } if (pthread_join(thread2, NULL) != 0) { perror("Error al unir el segundo hilo"); // Imprimir error si falla la espera del hilo exit(EXIT_FAILURE); } // Imprimir mensaje del hilo principal printf("Hilo principal: Ambos hilos han terminado su ejecución.\n"); return 0; }
La ejecución asíncrona significa que los hilos pueden ejecutarse en paralelo, y su progreso no sigue un orden predecible. La función pthread_join se utiliza para sincronizar el hilo principal con los hilos secundarios, permitiendo al programa principal esperar a que los hilos completen sus tareas antes de continuar. Esto es útil para coordinar y gestionar la ejecución de hilos en un programa.
Reflexiona la siguiente pregunta que será tratada en la sesión de clase.
¿Qué funciones desconoces del código 2 mostrado anteriormente?