operating system - sistemas - Relación entre un kernel y un hilo de usuario.
que es un hilo (5)
Cuando dicen map, significan que cada hilo del núcleo está asignado a un cierto número de hilos en modo usuario.
Los subprocesos del núcleo se utilizan para proporcionar servicios privilegiados a las aplicaciones (como las llamadas al sistema). El kernel también los utiliza para realizar un seguimiento de todo lo que se está ejecutando en el sistema, la cantidad de recursos asignados a qué proceso y para planificarlos.
Si sus aplicaciones hacen un uso intensivo de las llamadas al sistema, habrá más subprocesos de usuario por subproceso del kernel y sus aplicaciones se ejecutarán más lentamente. Esto se debe a que el subproceso del núcleo se convertirá en un cuello de botella, ya que todas las llamadas del sistema pasarán a través de él.
Sin embargo, por el otro lado, si sus programas rara vez utilizan llamadas al sistema (u otros servicios del kernel), puede asignar un gran número de subprocesos de usuario a un subproceso del kernel sin mucha penalización de rendimiento, aparte de la sobrecarga.
Puede aumentar el número de subprocesos del kernel, pero esto agrega sobrecarga al kernel en general, por lo que mientras los subprocesos individuales respondan mejor con respecto a las llamadas al sistema, el sistema en su conjunto se volverá más lento.
Es por eso que es importante encontrar un buen equilibrio entre el número de subprocesos del núcleo y el número de subprocesos de usuario por subproceso del núcleo.
¿Existe una relación entre un núcleo y un hilo de usuario?
Algunos libros de texto del sistema operativo dicen que " asigna un (muchos) hilos de usuario a uno (muchos) hilos del núcleo". ¿Qué significa el mapa aquí?
Las hebras de usuario se administran en el espacio de usuario, lo que significa que la programación, el cambio, etc. no son del núcleo.
Dado que, en última instancia, el kernel del sistema operativo es responsable de cambiar el contexto entre "unidades de ejecución": sus subprocesos de usuario deben estar asociados (es decir, "mapa") a un objeto programable del kernel: un subproceso del kernel [+1].
Entonces, dados los subprocesos de usuario N, se podrían usar subprocesos N del núcleo (un mapa 1: 1). Eso le permite aprovechar el multiprocesamiento de hardware del kernel (que se ejecuta en varias CPU) y ser una biblioteca bastante simplista, básicamente, simplemente aplazar la mayor parte del trabajo al kernel. Sin embargo, hace que su aplicación sea portátil entre sistemas operativos, ya que no está llamando directamente a las funciones de subproceso del kernel. Creo que los subprocesos POSIX ( PThreads ) son la implementación preferida * nix, y que sigue el mapa 1: 1 (haciéndolo virtualmente equivalente a un subproceso del núcleo). Sin embargo, esto no está garantizado, ya que dependería de la implementación (una razón principal para usar PThreads sería la portabilidad entre núcleos).
O, usted podría usar solo 1 hilo del núcleo. Eso le permitiría ejecutarse en sistemas operativos que no sean multitarea o estar completamente a cargo de la programación. La programación del modo de usuario de Windows es un ejemplo de este mapa N: 1.
O bien, puede asignar un número arbitrario de hilos del núcleo: un mapa N: M. Windows tiene Fibers , lo que le permitiría asignar N fibras a los hilos del núcleo M y planificarlas de forma cooperativa. Un conjunto de subprocesos también podría ser un ejemplo de esto: N elementos de trabajo para M subprocesos.
[+1] Un proceso tiene al menos 1 subproceso de kernel, que es la unidad de ejecución real. Además, un subproceso de núcleo debe estar contenido en un proceso. Los sistemas operativos deben programar el hilo para que se ejecute, no el proceso.
Según Wikipedia y Oracle , los subprocesos de nivel de usuario están en realidad en una capa montada en los subprocesos del núcleo; no es que los subprocesos del kernel se ejecuten junto con los subprocesos de nivel de usuario, sino que, en general, las únicas entidades que realmente son ejecutadas por el procesador / sistema operativo son los subprocesos del kernel.
Por ejemplo, supongamos que tenemos un programa con 2 subprocesos de nivel de usuario, ambos asignados (es decir, asignados) al mismo subproceso del núcleo. A veces, el subproceso del núcleo ejecuta el primer subproceso de nivel de usuario (y se dice que actualmente este subproceso del núcleo está asignado al primer subproceso de nivel de usuario) y otras veces el subproceso del núcleo ejecuta el segundo subproceso de nivel de usuario. Entonces, decimos que tenemos dos subprocesos de nivel de usuario asignados al mismo subproceso de núcleo.
Como aclaración :
El núcleo de un sistema operativo se llama su kernel , por lo que los subprocesos en el nivel del kernel (es decir, los subprocesos que el kernel conoce y administra) se denominan subprocesos del kernel, las llamadas al núcleo del SO para servicios pueden llamarse llamadas del kernel, y. ... La única relación definida entre las cosas del kernel es que están fuertemente relacionadas con el núcleo del sistema operativo, nada más.
http://www.informit.com/articles/printerfriendly.aspx?p=25075
Implementando hilos en el espacio de usuario
Hay dos formas principales de implementar un paquete de hilos: en el espacio de usuario y en el kernel. La elección es moderadamente controvertida, y también es posible una implementación híbrida. Ahora describiremos estos métodos, junto con sus ventajas y desventajas.
El primer método es colocar el paquete de hilos completamente en el espacio del usuario. El kernel no sabe nada de ellos. En lo que concierne al núcleo, está administrando procesos ordinarios de un solo hilo. La primera ventaja, y la más obvia, es que un paquete de subprocesos de nivel de usuario se puede implementar en un sistema operativo que no admite subprocesos. Todos los sistemas operativos solían caer en esta categoría, e incluso ahora algunos todavía lo hacen.
Todas estas implementaciones tienen la misma estructura general, que se ilustra en la Fig. 2-8 (a). Los subprocesos se ejecutan sobre un sistema de tiempo de ejecución, que es una colección de procedimientos que administran subprocesos. Ya hemos visto cuatro de estos: thread_create, thread_exit, thread_wait y thread_yield, pero usualmente hay más.
Cuando los subprocesos se administran en el espacio de usuario, cada proceso necesita su propia tabla de subprocesos privada para realizar un seguimiento de los subprocesos en ese proceso. Esta tabla es análoga a la tabla de procesos del kernel, excepto que solo realiza un seguimiento de las propiedades por hilo, como el contador de programa de cada hilo, el puntero de pila, los registros, el estado, etc. El sistema de tiempo de ejecución administra la tabla de hilos. Cuando un subproceso se mueve al estado preparado o al estado bloqueado, la información necesaria para reiniciarlo se almacena en la tabla de subprocesos, exactamente de la misma manera que el kernel almacena información sobre los procesos en la tabla de procesos.
Cuando un hilo hace algo que puede hacer que se bloquee localmente, por ejemplo, a la espera de que otro hilo en su proceso complete algún trabajo, llama a un procedimiento del sistema en tiempo de ejecución. Este procedimiento verifica si el hilo debe ponerse en estado bloqueado. Si es así, almacena los registros del hilo (es decir, los suyos) en la tabla de hilos, busca en la tabla un hilo listo para ejecutarse y vuelve a cargar los registros de la máquina con los valores guardados del nuevo hilo. Tan pronto como el puntero de la pila y el contador de programas se hayan cambiado, el nuevo hilo cobrará vida nuevamente automáticamente. Si la máquina tiene una instrucción para almacenar todos los registros y otra para cargarlos todos, todo el cambio de hilo se puede hacer en un puñado de instrucciones. Hacer el cambio de subprocesos de esta manera es al menos un orden de magnitud más rápido que la captura en el kernel y es un argumento sólido a favor de los paquetes de subprocesos de nivel de usuario.
Sin embargo, hay una diferencia clave con los procesos. Cuando un hilo termina de ejecutarse por el momento, por ejemplo, cuando llama a thread_yield, el código de thread_yield puede guardar la información del hilo en la propia tabla de hilos. Además, puede llamar al programador de hilos para seleccionar otro hilo para ejecutar. El procedimiento que guarda el estado del hilo y el planificador son solo procedimientos locales, por lo que invocarlos es mucho más eficiente que hacer una llamada al kernel. Entre otras cuestiones, no se necesita trampa, no se necesita un cambio de contexto, no es necesario vaciar la memoria caché, etc. Esto hace que la programación de hilos sea muy rápida.
Los hilos a nivel de usuario también tienen otras ventajas. Permiten que cada proceso tenga su propio algoritmo de programación personalizado. Para algunas aplicaciones, por ejemplo, aquellas con un hilo recolector de basura, no tener que preocuparse de que un hilo se detenga en un momento inconveniente es una ventaja. También se escalan mejor, ya que los subprocesos del kernel requieren invariablemente algo de espacio de tabla y espacio de pila en el kernel, lo que puede ser un problema si hay un gran número de subprocesos.
A pesar de su mejor rendimiento, los paquetes de subprocesos de nivel de usuario tienen algunos problemas importantes. El primero de ellos es el problema de cómo se implementan las llamadas de bloqueo del sistema. Supongamos que un hilo se lee desde el teclado antes de que se haya pulsado alguna tecla. Dejar que el hilo haga que la llamada al sistema sea inaceptable, ya que esto detendrá todos los hilos. Uno de los objetivos principales de tener hilos en primer lugar era permitir que cada uno use llamadas de bloqueo, pero evitar que un hilo bloqueado afecte a los demás. Con el bloqueo de llamadas al sistema, es difícil ver cómo se puede lograr este objetivo fácilmente.
Todas las llamadas al sistema podrían cambiarse para que no se bloqueen (por ejemplo, una lectura en el teclado solo devolvería 0 bytes si no hubiera caracteres en el búfer), pero no es atractivo que requiera cambios en el sistema operativo. Además, uno de los argumentos para los subprocesos de nivel de usuario era precisamente que podían ejecutarse con los sistemas operativos existentes. Además, cambiar la semántica de lectura requerirá cambios en muchos programas de usuario.
Otra alternativa es posible en el caso de que sea posible saber por adelantado si se bloqueará una llamada. En algunas versiones de UNIX, existe una llamada al sistema, selección, que permite a la persona que llama saber si se bloqueará una posible lectura. Cuando esta llamada está presente, el procedimiento de lectura de la biblioteca puede reemplazarse por uno nuevo que primero realiza una llamada de selección y luego solo realiza la llamada de lectura si es seguro (es decir, no se bloqueará). Si la llamada de lectura se bloquea, la llamada no se realiza. En su lugar, se ejecuta otro hilo. La próxima vez que el sistema en tiempo de ejecución obtenga el control, puede verificar de nuevo para ver si la lectura ahora es segura. Este enfoque requiere la reescritura de partes de la biblioteca de llamadas del sistema, es ineficiente y poco elegante, pero hay pocas opciones. El código colocado alrededor de la llamada del sistema para realizar la comprobación se denomina chaqueta o envoltorio.
Algo análogo al problema de bloquear las llamadas al sistema es el problema de los fallos de página. Los estudiaremos en el cap. 4. Por el momento, es suficiente decir que las computadoras pueden configurarse de tal manera que no todos los programas estén en la memoria principal a la vez. Si el programa llama o salta a una instrucción que no está en la memoria, ocurre una falla en la página y el sistema operativo irá y obtendrá la instrucción que falta (y sus vecinos) del disco. Esto se llama un error de página. El proceso se bloquea mientras se ubica y lee la instrucción necesaria. Si un hilo causa un fallo en la página, el núcleo, sin saber siquiera acerca de la existencia de hilos, bloquea todo el proceso hasta que se completa la E / S del disco, incluso aunque otros hilos pueden ser ejecutables.
Otro problema con los paquetes de subprocesos de nivel de usuario es que si un subproceso comienza a ejecutarse, ningún otro subproceso en ese proceso se ejecutará a menos que el primer subproceso renuncie voluntariamente a la CPU. Dentro de un solo proceso, no hay interrupciones de reloj, por lo que es imposible programar procesos a la manera de turnos (turnos). A menos que un hilo entre en el sistema de tiempo de ejecución por su propia voluntad, el programador nunca tendrá una oportunidad.
Una posible solución al problema de los subprocesos que se ejecutan para siempre es hacer que el sistema en tiempo de ejecución solicite una señal de reloj (interrupción) una vez por segundo para darle control, pero esto también es difícil de programar. Las interrupciones periódicas del reloj a una frecuencia más alta no siempre son posibles, e incluso si lo son, la sobrecarga total puede ser considerable. Además, un subproceso también puede necesitar una interrupción del reloj, lo que interfiere con el uso del reloj del sistema en tiempo de ejecución.
Otro argumento, y probablemente el más devastador contra los subprocesos a nivel de usuario, es que los programadores generalmente quieren subprocesos precisamente en aplicaciones donde los subprocesos se bloquean a menudo, como, por ejemplo, en un servidor web de multiproceso. Estos hilos están constantemente haciendo llamadas al sistema. Una vez que se ha producido una trampa en el kernel para llevar a cabo la llamada del sistema, es casi imposible que el kernel cambie de subprocesos si el anterior ha bloqueado, y hacer que el kernel haga esto elimina la necesidad de hacer llamadas de sistema selectas constantemente. Compruebe si las llamadas al sistema de lectura son seguras. Para las aplicaciones que están esencialmente vinculadas por completo a la CPU y que rara vez se bloquean, ¿cuál es el objetivo de tener subprocesos? Nadie propondría seriamente calcular los primeros n números primos o jugar al ajedrez usando hilos porque no hay nada que ganar al hacerlo de esa manera.
- Esta es una pregunta acerca de la implementación de la biblioteca de hilos.
- En Linux, un subproceso (o tarea) podría estar en el espacio del usuario o en el espacio del kernel. El proceso ingresa al espacio del kernel cuando le pide al kernel que haga algo por syscall (lectura, escritura o ioctl).
- También hay un llamado kernel-thread que se ejecuta siempre en el espacio del kernel y no representa ningún proceso de usuario.