Lectores como tú ayudan a apoyar a MUO. Cuando realiza una compra utilizando enlaces en nuestro sitio, podemos ganar una comisión de afiliado. Leer más.

En Linux, puede crear y administrar subprocesos en C/C++ utilizando la biblioteca de subprocesos POSIX (pthread). A diferencia de otros sistemas operativos, hay poca diferencia entre un hilo y un proceso en Linux. Es por eso que Linux a menudo se refiere a sus subprocesos como procesos ligeros.

Con la biblioteca pthread, puede crear subprocesos, esperar a que terminen y terminarlos explícitamente.

La historia del uso de subprocesos en Linux

Antes de la versión 2.6 de Linux, la implementación del subproceso principal era LinuxThreads. Esta implementación tenía límites significativos en términos de rendimiento y operaciones de sincronización. Un límite en la cantidad máxima de subprocesos que podrían ejecutarse los restringió a 1000.

En 2003, un equipo dirigido por desarrolladores de IBM y RedHat logró hacer que el Biblioteca de subprocesos POSIX nativos

instagram viewer
(NPTL) proyecto disponible. Se introdujo por primera vez en RedHat Enterprise versión 3 para resolver problemas de rendimiento con Java Virtual Machine en Linux. Hoy en día, la biblioteca GNU C contiene implementaciones de ambos mecanismos de subprocesamiento.

Ninguno de estos es una implementación de subprocesos verdes, que una máquina virtual administraría y ejecutaría en modo puramente de usuario. Cuando usa la biblioteca pthread, el núcleo crea un hilo cada vez que se inicia un programa.

Puede encontrar información específica de subprocesos para cualquier proceso en ejecución en los archivos en /proc//task. Esta es la ubicación estándar para la información del proceso bajo el estándar procfs Linux. Para aplicaciones de un solo subproceso, parecerá que hay un registro de tareas con el mismo valor que el PID en este directorio.

Lógica de trabajo de hilos

Los subprocesos son como procesos que se ejecutan actualmente en el sistema operativo. En sistemas de un solo procesador (por ejemplo, microcontroladores), el kernel del sistema operativo simula subprocesos. Esto permite que las transacciones se ejecuten simultáneamente a través del corte.

Un sistema operativo de un solo núcleo realmente solo puede ejecutar un proceso a la vez. Sin embargo, en sistemas multinúcleo o multiprocesador, estos procesos pueden ejecutarse simultáneamente.

Creación de subprocesos en C

Puedes usar el pthread_create función para crear un nuevo hilo. El pthread.h El archivo de encabezado incluye su definición de firma junto con otras funciones relacionadas con el subproceso. Los subprocesos utilizan el mismo espacio de direcciones y descriptores de archivo que el programa principal.

La biblioteca pthread también incluye el soporte necesario para mutex y operaciones condicionales requeridas para operaciones de sincronización.

Cuando usa las funciones de la biblioteca pthread, debe asegurarse de que el compilador vincule el hilo p biblioteca en su ejecutable. Si es necesario, puede indicarle al compilador que se vincule a la biblioteca usando el -l opción:

gcc-o prueba test_thread.c -lpthread

La función pthread_create tiene la siguiente firma:

En tpthread_create(pthread_t *hilo, constantepthread_attr_t *atributo, vacío *(*iniciar_rutina)(vacío *), vacío * argumento)

Devuelve 0 si el procedimiento es exitoso. Si hay un problema, devuelve un código de error distinto de cero. En la firma de la función anterior:

  • El hilo el parámetro es de tipo pthread_t. El hilo creado siempre será accesible con esta referencia.
  • El atributo El parámetro le permite especificar un comportamiento personalizado. Puede usar una serie de funciones específicas de subprocesos que comienzan con pthread_attr_ para configurar este valor. Las posibles personalizaciones son la política de programación, el tamaño de la pila y la política de separación.
  • iniciar_rutina especifica la función que ejecutará el subproceso.
  • argumento representa una estructura de datos genérica pasada a la función por el subproceso.

Aquí hay una aplicación de ejemplo:

#incluir
#incluir
#incluir
#incluir

vacío *obrero(vacío *datos)
{
carbonizarse *nombre = (carbonizarse*)datos;

para (En t yo = 0; yo < 120; i++)
{
tu duerme(50000);
imprimir("Hola desde el nombre del hilo = %s\n", nombre);
}

imprimir("Subproceso %s terminado!\n", nombre);
devolverNULO;
}

En tprincipal(vacío)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabajador, "X");
pthread_create(&th2, NULO, trabajador, "Y");
dormir(5);
imprimir("Saliendo del programa principal\n");
devolver0;
}

Tipos de hilo

Cuando un hilo regresa del principal() función en una aplicación, todos los subprocesos terminan y el sistema libera todos los recursos que utilizó el programa. Del mismo modo, al salir de cualquier subproceso con un comando como un salida(), su programa terminará todos los subprocesos.

Con el pthread_join función, puede esperar a que termine un subproceso en su lugar. El subproceso que utiliza esta función se bloqueará hasta que finalice el subproceso esperado. Los recursos que utilizan del sistema no se devuelven incluso en casos como la terminación de subprocesos que se pueden unir, no programados por la CPU o incluso si no se unen con ptread_join.

A veces hay situaciones en las que unirse con pthread_join no tiene sentido; si es imposible predecir cuándo terminará el hilo, por ejemplo. En este caso, puede asegurarse de que el sistema devuelva todos los recursos automáticamente en el punto donde regresa el hilo.

Para lograr esto, debe iniciar los hilos relevantes con el SEPARADO estado. Al iniciar un hilo, DESPEGAR El estado se puede establecer a través de los valores de un atributo de subproceso o con el pthread_detach función:

En tpthread_attr_setdetachstate(&atributo, PTHREAD_CREATE_DETACHED);
En tpthread_detach(pthread_t hilo);

Aquí hay un ejemplo de uso de pthread_join(). Reemplace la función principal en el primer programa con lo siguiente:

En tprincipal(vacío)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabajador, "X");
pthread_create(&th2, NULO, trabajador, "Y");
dormir(5);
imprimir("saliendo del programa principal\n");
pthread_join (th1, NULO);
pthread_join (th2, NULO);
devolver0;
}

Cuando compile y ejecute el programa, su salida será:

Hola desde el hilo Y
hola desde el hilo x
Hola desde el hilo Y
...
Hola desde el hilo Y
salir del programa principal
hola desde el hilo x
...
hola desde el hilo x
¡Hilo X listo!
Hola desde el hilo Y
Hilo Y hecho!

Terminación de hilo

Puede cancelar un hilo con una llamada a pthread_cancel, pasando el correspondiente pthread_t identificación:

En tpthread_cancel(pthread_t hilo);

Puede ver esto en acción en el siguiente código. De nuevo, sólo el principal la función es diferente:

En tprincipal(vacío)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabajador, "X");
pthread_create(&th2, NULO, trabajador, "Y");
dormir(1);
imprimir("> ¡Cancelando subproceso Y!!\n");
pthread_cancel (th2);
tu duerme(100000);
imprimir("> Cancelando hilo X!\n");
pthread_cancel (th1);
imprimir("saliendo del programa principal\n");
devolver0;
}

¿Por qué se crean hilos?

Los sistemas operativos siempre intentan ejecutar subprocesos en una o más CPU, ya sea desde una lista creada por ellos mismos o desde una lista de subprocesos creada por el usuario. Algunos subprocesos no pueden ejecutarse porque están esperando una señal de entrada/salida del hardware. También pueden estar esperando voluntariamente, esperando una respuesta de otro hilo, o tener otro hilo bloqueándolos.

Puede ajustar los recursos que asigna a los subprocesos que crea utilizando pthread. Esta puede ser una política de programación personalizada, o puede elegir algoritmos de programación como FIFO o Round-robin si lo desea.