Una tarea se lleva a cabo en la ejecución de un programa, que da como resultado un proceso. Cada tarea incorpora una o varias subtareas, mientras que estas subtareas se llevan a cabo como funciones dentro de un programa por los subprocesos. El sistema operativo (kernel) desconoce los subprocesos en el espacio del usuario.
Hay dos tipos de subprocesos, subprocesos de nivel de usuario (ULT) y subprocesos de nivel de kernel (KLT).
- Subprocesos de nivel de usuario:
subprocesos en el espacio de usuario diseñados por el desarrollador de la aplicación que utilizan una biblioteca de subprocesos para realizar subtareas únicas.
- Subprocesos a nivel del kernel:
subprocesos en el espacio del kernel diseñados por el desarrollador del sistema operativo para realizar funciones únicas del sistema operativo. Similar a un controlador de interrupciones.
Existe una fuerte relación entre los subprocesos a nivel de usuario y los subprocesos a nivel de kernel.
Dependencias entre ULT y KLT:
- Uso de la biblioteca de subprocesos:
la biblioteca de subprocesos actúa como una interfaz para que el desarrollador de la aplicación cree una cantidad de subprocesos (de acuerdo con la cantidad de subtareas) y administre esos subprocesos. Esta API para un proceso se puede implementar en el espacio del kernel o en el espacio del usuario. En la aplicación en tiempo real, la biblioteca de subprocesos necesaria se implementa en el espacio del usuario. Esto reduce la llamada del sistema al kernel cada vez que la aplicación necesita actividades de creación, programación o gestión de subprocesos. Por lo tanto, la creación de subprocesos es más rápida, ya que solo requiere llamadas a funciones dentro del proceso. El espacio de direcciones de usuario para cada subproceso se asigna en tiempo de ejecución. En general, reduce varios gastos generales de interfaz y arquitectura, ya que todas estas funciones son independientes del soporte del kernel. - Sincronización:
las subtareas (funciones) dentro de cada tarea (proceso) se pueden ejecutar de forma simultánea o paralela según la aplicación. En ese caso, el proceso de subproceso único no es adecuado. Evoca un proceso multiproceso. Se asigna una subtarea única a cada subproceso dentro del proceso. Estos subprocesos pueden usar la misma sección de datos o una sección de datos diferente. Por lo general, los subprocesos dentro del mismo proceso compartirán la sección de código, la sección de datos, el espacio de direcciones, los archivos abiertos, etc.
Cuando las subtareas se realizan simultáneamente al compartir la sección de código, puede resultar en inconsistencias en los datos. En última instancia, requiere técnicas de sincronización adecuadas para mantener el flujo de control para acceder a los datos compartidos ( sección crítica ).
En un proceso de subprocesos múltiples, la sincronización se adoptó utilizando cuatro modelos diferentes:
- Bloqueos de exclusión mutua: esto permite que solo un subproceso a la vez acceda al recurso compartido.
- Bloqueos de lectura/escritura: esto permite escrituras exclusivas y lecturas simultáneas de un recurso compartido.
- Semáforo de conteo: este conteo se refiere a la cantidad de recursos compartidos a los que se puede acceder simultáneamente a la vez. Una vez que se alcanza el límite de conteo, los subprocesos restantes se bloquean.
- Variables de condición: esto bloquea el subproceso hasta que se cumple la condición (ocupado en espera).
Todos estos modelos de sincronización se llevan a cabo dentro de cada proceso utilizando la biblioteca de hilos. El espacio de memoria para las variables de bloqueo se asigna en el espacio de direcciones de usuario. Por lo tanto, no requiere la intervención del kernel.
1. Programación:
el desarrollador de la aplicación durante la creación del subproceso establece la prioridad y la política de programación de cada subproceso ULT utilizando la biblioteca de subprocesos. En la ejecución del programa, en función de los atributos definidos, la biblioteca de subprocesos realiza la programación. En este caso, el programador del sistema no tiene control sobre la programación de subprocesos, ya que el kernel desconoce los subprocesos ULT.
2. Cambio de contexto:
cambiar de un subproceso ULT a otro subproceso ULT es más rápido dentro del mismo proceso, ya que cada subproceso tiene su propio bloque de control de subprocesos, registros y pila únicos. Por lo tanto, los registros se guardan y restauran. No requiere ningún cambio de espacio de direcciones. Todo el cambio se lleva a cabo dentro del espacio de direcciones del usuario bajo el control de la biblioteca de subprocesos.
3. E/S asíncrona:
después de una solicitud de E/S, los subprocesos ULT permanecen en estado bloqueado, hasta que recibe el reconocimiento (ack) del receptor. Aunque sigue a la E/S asíncrona, crea un entorno síncrono para el usuario de la aplicación. Esto se debe a que la propia biblioteca de subprocesos programa otro ULT para que se ejecute hasta que el subproceso bloqueado envíe sigpoll como confirmación a la biblioteca de subprocesos de proceso. Solo entonces la biblioteca de subprocesos reprograma el subproceso bloqueado.
Por ejemplo, considere un programa para copiar el contenido (leer) de un archivo y pegarlo (escribirlo) en el otro archivo. Además, una ventana emergente que muestra el porcentaje de finalización del progreso.
Este proceso contiene tres subtareas, cada una asignada a un ULT,
- Subproceso A: lea el contenido del archivo de origen. Almacene en una variable global X dentro del espacio de direcciones del proceso.
- Subproceso B: lea la variable global X. Escriba en el archivo de destino.
- Subproceso C: muestra el porcentaje de progreso realizado en una representación gráfica.
Aquí, el desarrollador de la aplicación programará el flujo de control múltiple dentro de un programa utilizando la biblioteca de subprocesos.
Orden de ejecución: comienza con el subproceso A, luego el subproceso B y luego el subproceso C.
El subproceso A y el subproceso B comparten la variable global X. Solo cuando después del subproceso A escribe en X, el subproceso B puede leer X. En ese caso, la sincronización es para ser adoptado en la variable compartida para evitar que el subproceso B lea datos antiguos. El cambio de contexto del subproceso A al subproceso B y luego el subproceso C tiene lugar dentro del espacio de direcciones del proceso. Cada subproceso guarda y restaura los registros en su propio bloque de control de subprocesos (TCB). El subproceso C permanece en estado bloqueado hasta que el subproceso B inicia su primera operación de escritura en el archivo de destino. Esta es la razón por la que la indicación gráfica de 100 % aparece unos segundos después de la finalización del proceso.
Dependencia entre ULT y KLT:
La única dependencia importante entre KLT y ULT surge cuando un ULT necesita los recursos del Kernel . Cada subproceso ULT está asociado a un procesador virtual llamado proceso ligero. La biblioteca de subprocesos lo crea y lo combina con ULT según las necesidades de la aplicación. Cada vez que se invoca una llamada al sistema, el programador del sistema crea un subproceso a nivel de kernel y lo programa para los LWP. Estos KLT están programados para acceder a los recursos del núcleo por el programador del sistema que desconoce el ULT. Mientras que el KLT conoce cada ULT asociado a él a través de LWP.
¿Qué pasa si la relación no existe?
Si no hay asociación entre KLT y ULT, entonces, de acuerdo con el núcleo, cada proceso es un proceso de subproceso único. En ese caso,
- El programador del sistema puede programar un proceso con subprocesos que tienen menos prioridad o subprocesos inactivos. Esto conduce a la inanición de subprocesos de alta prioridad, lo que a su vez reduce la eficiencia del sistema.
- Cuando se bloquea un solo hilo, se bloquea todo el proceso. Entonces, la utilización de la CPU, incluso en un sistema multinúcleo, será mucho menor. Aunque puede haber subprocesos ejecutables, el kernel considera cada proceso como un proceso de un solo subproceso y asigna solo un núcleo a la vez.
- El programador del sistema puede proporcionar un segmento de tiempo único independientemente del número de subprocesos dentro de un proceso. Un proceso de un solo subproceso y un proceso con 1000 subprocesos proporcionados con el mismo intervalo de tiempo harán que el sistema sea más ineficiente.