Go to content Go to navigation Go to search

Sistemas Operativos – Manejador de procesos – Parte 2 – Procesos

June 13th, 2010 by JuanK

En el post de Manejador de Procesos 1 – Fundamentos  vimos, entre otros temas, que un proceso es un conjunto de instrucciones que se ejecutan con un objetivo determinado, y pudimos ver de manera superficial de que se compone un proceso.

Estos son los otros dos artículos de la serie:

 

Parte 1 : Manejador de Procesos – Fundamentos

Parte 3 : Manejador de Procesos – Threads

 

Como parte del tema de procesos profundizaremos un poco más al respecto de ellos.

 

El Proceso

Un proceso esta básicamente compuesto por un conjunto de instrucciones, pero hasta allí nada lo diferencia de lo que es un programa guardado en disco, el proceso se define por estar en ejecución – o al menos esperando para ejecución- sino esta en ejecución no hay proceso.

Un proceso en ejecución entonces tiene, además de sus instrucciones, características propias que lo describen y que definen su estado mientras este se ejecuta, estas características son:

 

  • El estado del proceso: el valor de cada uno de los registros el procesador y las las banderas establecidas
  • El conjunto de instrucciones
  • La pila (es decir el Stack)
  • Memoria de trabajo > Espacio de memoria reservado en el heap (es decir el montón de memoria) y sus contenidos

 

Las describiremos con mayor detalle.

 

El Estado Del Proceso

En cada ciclo de reloj, comprendido desde que se envía una instrucción -del conjunto de instrucciones del procesador- hasta que se obtiene una respuesta, existe un estado diferente de cada proceso.

 

Una forma fácil de ver que es el estado de un proceso es imaginar un proceso en ejecución como una película, compuestas por muchos cuadros independientes, si tomamos uno de los cuadros tenemos una fotografía de un único instante en el tiempo de ejecución, esa fotografía es el estado del proceso.

 

En ese estado podemos identificar que datos tenia el procesador en cada uno de sus registros en ese momento, así como las banderas que se encontraban activadas.

Esto permite, por ejemplo y como lo vimos en el post anterior, suspender un proceso de repente y volverlo a activar posteriormente justo donde se encontraba, simplemente tomando su estado para y en otro momento restableciéndolo el proceso podrá seguir con la ejecución justo donde estaba.

 

El Conjunto de Instrucciones

No se como explicar esto… pues el conjunto de instrucciones que componen el proceso… jajajaja

Rabbid

 

La Pila – El Stack

A bajo nivel la mayoría del trabajo no se hace accediendo directamente a los objetos sino a los registros y a una útil herramienta llamada stack, como su nombre lo indica el stack es una pila donde los elementos se colocan uno sobre otro y solo es accesible de manera inmediata el elemento que esta en la cima de la pila. Allí es donde los objetos se almacenan de manera temporal previo a su utilización.

 

La porción de memoria donde se localiza el stack (stack segment) esta alineada con la porción de memoria donde están las instrucciones de un programa (code segment)

 

Su funcionamiento es muy sencillo y consta de dos instrucciones principales: POP y PUSH.

 

POP quita un elemento de la cima de la pila y lo coloca en uno de los registros: image

 

PUSH coloca un elemento de uno de los registros en la cima de la pila:

image 

Un stack solo pertenece a un único proceso,  el stack se crea en el momento que el programa se carga en memoria.

 

A quien desee una explicación más detallada al respecto nuevamente le recomiendo que estudie el Tutorial de Assembler.

 

Memoria de Trabajo

De manera habitual los tipos valor (como enteros, caracteres sencillos, flotantes etc. y algunas estructuras más complejas) son guardados en el stack, mientras que los tipos referencia son guardados en la memoria de trabajo.

 

Cuando en programación se usa un objeto por referencia realmente sucede que en el stack se guarda una dirección que apunta a la memoria de trabajo, exactamente a donde se encuentra el objeto referenciado.

image De esta forma un objeto puede tener referenciadas varias porciones de memoria como parte de su memoria de trabajo, y es el sistema operativo quien lleva un inventario de que páginas de memoria han sido asignadas a un proceso determinado, y a la vez lleva un inventario de que porciones de esa página se están usando desde los objetos del proceso.

 

Con la información que hemos revisado hasta el momento ya podemos meternos en temas u poco más complejos, pero no se preocupen que mantendré el estilo que he usado hasta ahora, veremos solo la información necesaria para entender de que se trata el asunto y dejaremos los altos tecnicismos para los libros o para otras web dedicadas al tema.

Estos son los otros dos artículos de la serie:

Parte 1 : Manejador de Procesos – Fundamentos

Parte 3 : Manejador de Procesos – Threads

 

Bookmark and Share

Sistemas Operativos – Manejador de procesos – Parte 1 – Fundamentos

April 18th, 2010 by JuanK

Esta es una serie 2 post introductorios acerca de lo que es el manejador de procesos, la idea es tener un concepto muy general de lo que hace esta parte de todo sistema operativo, sin embargo es un tema muy extenso y que puede llegar a ser bastante complejo, por lo cual cabe aclarar que por el momento solo trataremos los conceptos de manera muy superficial.

 

Estos son los otros dos artículos de la serie:

 

Parte 2 : Manejador de Procesos – Procesos

Parte 3 : Manejador de Procesos – Threads

 

El manejador de procesos (también llamado planificador, scheduler, calendarizador etc.) es la parte fundamental de todo sistema operativo, de hecho se puede decir que para crear un sistema operativo básico basta con crear cuatro componentes fundamentales:

 

  • Planificador de procesos
  • Administrador de memoria
  • Manejador de E/S (como mínimo con controladores para video, teclado y disco)
  • Sistema de archivos

 

El manejador de procesos es el encargado, como su nombre lo indica, de permitir le ejecución de los diferentes procesos en una o varias CPU. A simple vista esta tarea es sencilla, pero esta lejos de serlo.

 

El procesador es un dispositivo que ejecuta un conjunto de instrucciones y devuelve un resultado, así que desde el punto de vista del procesador el concepto de proceso no existe más allá de ejecutar una instrucción en cada ciclo de procesamiento; es el  sistema operativo quien determina que es un proceso en si: un conjunto de instrucciones agrupadas con un(os) objetivo(s)  especifico(s).

 

Cuando estamos utilizando un sistema operativo como Windows siempre tenemos la percepción de que hay múltiples programas ejecutándose al mismo tiempo, podemos ver varias ventanas abiertas mientras escuchamos música, navegamos por internet y diligenciamos una hoja de cálculo de excel, pero esto no es más que una ilusión.

 

Para simplificar un poco el trabajo examinaremos la situación cuando solo hay presente un procesador de un único núcleo.

 

Funcionamiento básico de una CPU

La CPU, como ya lo mencionamos, solo puede ejecutar una instrucción a la vez, pero como es esto?

 

Bueno la forma mas sencilla de explicarlo es con un ejemplo: digamos que queremos sumar los valores 2+3 utilizando la CPU, la CPU tiene una especie de ‘ranuras’ llamadas registros algunas de estas ranuras reciben los nombres de Ax, Bx, Cx (pero hay varias más.) y son utilizados por la CPU como fuente de entrada y salida de información.

 

Lo que se hace entonces  para la suma es colocar los valores a sumar en los registros, esto es un mini ejemplo en lenguaje ensamblador:

 

mov AX, 2 ; poner el número 2 en el registro AX

add AX, 3 ;sumar al contenido de AX el valor 3, la respuesta queda en AX

 

veamos estos dos pasos en el siguiente gráfico (lo he expandido a 4 pasos para mayor claridad)

image 

El procesador posee un registro que es un apuntador que le permite saber en que instrucción del programa se encuentra de tal manera que cada vez que ejecuta una instrucción el mueve al apuntador a la siguiente instrucción a ser ejecutada.

 

Cualquier instrucción ejecutada por la CPU funciona de manera similar, utilizando los registros como ranuras de intercambio de datos.

 

Cómo se ejecutan varios procesos?

De acuerdo al tema tratado anteriormente pudimos ver que una CPU solo puede ejecutar una instrucción a la vez, y como es de suponerse dicha instrucción pertenece a un proceso determinado.

Hay varias maneras de llevar a cabo la ejecución de procesos

Sistemas Operativos Monotarea

La CPU por si sola no puede iniciar la ejecución de otro proceso, es el sistema operativo es quien le dice a la CPU cuando comenzar a ejecutar un conjunto de instrucciones determinado, sin embargo la CPU ejecutaría todas las instrucciones de un proceso hasta finalizar y en ese momento continuaría la ejecución del sistema operativo (que en si es otro proceso) el cual seleccionaría el siguiente proceso a ejecutar suspendiéndose a si mismo hasta que el proceso finalice, luego nuevamente  volvería a seleccionar un nuevo proceso y así sucesivamente hasta que no hubiesen procesos por ejecutar.

 

Algunos dirán y como es que se vuelve a ejecutar el sistema operativo cuando acaba de terminar un proceso?, bueno el truco es sencillo, devolvámonos a algunos sistemas mono tarea tipo DOS en sus primeras versiones, si hacíamos un programa en C este al final del main siempre tenia la instrucción return, pues bien el compilador al compilar código convertía esa expresión return en instrucciones de maquina que hacían que la siguiente ‘línea’ de código a ejecutar fuera… el sistema operativo, así que básicamente todo programa hecho finaliza con una instrucción para devolver el control al sistema operativo.

 

Este tipo de comportamiento es el habitual en sistemas operativos mono-proceso , es decir que solo pueden ejecutar un proceso a la vez de tal forma que todos los procesos deben esperar su turno en una larga fila de procesos pendientes: esto también es conocido como: planificación por lotes.

 

image

 

Si Windows funcionara de esta manera no podríamos hacer nada con el pues no podríamos tener sino un programa a la vez y esto excluye de manea inevitable los propios servicios que el sistema operativo corre en segundo plano, incluso si mandaras un trabajo de impresión no podrías hacer absolutamente nada más hasta que el trabajo de impresión finalice.

 

Esto esta muy lejos de ser el comportamiento que estamos habituados a ver, es decir un sistema con decenas de procesos ejecutándose ‘al tiempo’, entonces como funciona esto? bueno todo se resuelve con un truco que realiza el sistema operativo.

 

Sistemas Operativos Multitarea

Como su nombre lo indica ‘multitarea’ se refiere a que puede realizar varias tareas a la vez, al menos eso es lo que parece.

 

Realmente lo que sucede es que el sistema operativo esta hecho para tomar la sabia decisión de no permitirle a un programa ejecutarse sino por una fracción de tiempo (muy pequeña), de tal forma que en un solo segundo muchos programas han tenido tiempo de procesamiento, es decir muchos programas se han ejecutado en lapsos de pequeñas fracciones de tiempo. En esencia el concepto es sencillo, implementarlo suele ser más complicado pues hay muchos más aspectos involucrados, estudiaremos algunos.

 

Interrupción de la Ejecución de un Proceso

Al ejecutarse un proceso en un sistema multitarea, este tiene la oportunidad de realizar un conjunto indeterminado de instrucciones, lo que alcance a hacer en un tiempo limitado, una vez ese tiempo se ha cumplido el sistema operativo debe decidir que proceso debe continuar su ejecución ( bien sean procesos de usuario o procesos de sistema ), esto lo hace teniendo en cuenta una lista de procesos y unas listas por prioridades de procesos, donde algunos procesos tienen más tiempo de ejecución que otros y tienen una prioridad mayor que les permite ‘avanzar más rápido en la fila’.

 

El sistema operativo sabe que se ha cumplido el tiempo de ejecución de un proceso cuando recibe una señal de interrupción por parte del procesador, esta señal se activa solo cada determinado tiempo (este lapso de tiempo es llamado Quantum), básicamente existe un microprograma que en ese momento le permite al procesador suspender la ejecución y enviar el control (es decir ejecutar) al sistema operativo para que lleve a cabo la planificación necesaria .

 

Sin embargo hay otros mecanismos que pueden generar interrupciones como por ejemplo:

  • Una Señal enviada desde un dispositivo de hardware
  • Un proceso puede optar por suspenderse a si mismo

 

Hay muchas situaciones donde las dos condiciones anteriores puede ocurrir, este es un ejemplo típico:

 

El proceso P1 se encuentra en ejecución y en un momento determinado espera respuesta desde un dispositivo de E/S(por ejemplo una tarjeta de red), pero no sabe en que momento se recibirá dicha respuesta, así que el proceso se encuentra en espera y suspende su ejecución. El sistema operativo coloca al proceso P2 en ejecución y este comienza a ejecutarse durante su Quantum, seguidamente termina su tiempo de ejecución y siguen en ejecución otros procesos P3…Pn.

 

En un momento determinado el proceso P5 se encontraba en ejecución cuando el dispositivo de red envió la respuesta que estaba esperando P1, el procesador conoce de esa respuesta y genera una nueva interrupción (es decir devuelve el control otra vez al sistema operativo) suspendiendo inmediatamente el proceso en ejecución. El sistema operativo revisa los buffer de los dispositivos de entrada, encuentra la respuesta que esperaba P1 y activa inmediatamente P1 para que este continúe con su ejecución por un nuevo Quantum de tiempo o en tanto no se genere una nueva interrupción cualquiera que sea su origen.

 

Tenemos entonces tres maneras que permiten que un proceso suspenda su ejecución para que otros se ejecuten:

  1. Interrupción por el reloj del procesador (Quantum de tiempo)
  2. Interrupción por dispositivos de E/S
  3. Auto suspensión del proceso o finalización del proceso. 

Estado De La Ejecución De Un Proceso

Ya hemos visto como es que el sistema operativo alterna entre varios procesos para dar la impresión de que esta haciendo varias cosas a la vez, pero puede que alguno de ustedes ya les haya surgido la pregunta: ¿Cómo sabe el sistema en que iba mi proceso justo antes de suspenderlo? veamos el caso anterior (el de 2 +3) en un entorno multitarea:

 

image

 

En la gráfica vemos al proceso P1 justo terminando de finalizar su primera instrucción, así que como respuesta a esta instrucción el procesador dejó el valor 2 en el registro AX, luego viene los demás procesos  cada uno utilizando los registros según sus necesidades como se ve en la gráfica:

image

 

hasta que por alguna razón le vuelve a tocar el turno de ejecución al proceso P1 y ooops!!!  P1 estaba esperando que en  AX estuviera el valor 2 para que así su suma sea 2+3, pero en este momento ya el proceso P1 no tendría en los registros los mismos valores que tenia justo antes de suspenderse!!!

Por otro lado el sistema operativo también necesita saber en que instrucción estaba la ejecución de P1 para continuar justo donde estaba antes de suspender su ejecución, y algunos otros datos más, entonces como hace para que todo pueda continuar normal?

 

Como lo dije anteriormente cuando un proceso se suspende básicamente se devuelve la ejecución al sistema operativo, allí  el sistema lleva a acabo la planificación de procesos y otras tareas, pero que hace realmente?

 

El sistema lo primero que hace es guardar el estado del proceso en algún sitio, el estado del proceso es  una estructura en memoria que guarda los valores de TODOS los registros y banderas del procesador  (las banderas son un registro utilizado por el procesador para indicar situaciones como división por cero, overflow, signo negativo etc.) es decir esto incluye el registro IP(Instruction Pointer) que es un registro que contiene un apuntador que indica al procesador en que instrucción de código va la ejecución, y los registros Ax, Bx, Cx, etc.

 

Una vez ese dato queda guardado el sistema verifica cual es el siguiente proceso que debe tener un Quantum de ejecución, digamos el proceso P2, así que el sistema operativo lee el estado del proceso P2 y comienza a dejar las cosas en su lugar, es decir lee los valores que deberían tener cada uno de los registros , las banderas,etc. y establece esos valores en el procesador, una vez todos los valores están establecidos los últimos valores que establece el sistema son los de los registros de segmento y el registro IP, una vez realizada esta labor inicia la ejecución de P2 hasta que sea interrumpido y se continúe con la labor de planificación una y otra vez.

Si desean más información acerca de los registros los invito a consultar este Tutorial de Assembler.

 

Esto es todo por el momento, los más conocedores me perdonaran por todas las cosas que he podido pasar por alto pero recuerden que esto es solo un post introductorio y no pretendo detallar las cosas más allá de los conocimientos generales, de igual forma cualquier duda o corrección que tengan es bienvenida.

 

Saludos.

 

Estos son los otros dos artículos de la serie:

 

Parte 2 : Manejador de Procesos – Procesos

Parte 3 : Manejador de Procesos – Threads

 

Bookmark and Share

Sistemas Operativos – Manejador de procesos – Parte 3 – Threads

October 18th, 2009 by JuanK

Hola, esta es la tercera parte de la serie de Sistemas operativos, la cual confieso he abordado ahora con un objetivo diferente al de enseñar solo sistemas operativos. Esta serie de artículos esta direccionada a tener claros los fundamentos para luego iniciar a trabajar con LA TPL (Task Parallel Library) incluida ahora en el Framework 4.0.

Estos son los dos artículos anteriores:

 

Parte 1 : Manejador de Procesos – Fundamentos

Parte 2 : Manejador de Procesos – Procesos

 

En la primera parte identificamos la manera en que trabaja una CPU y diferenciamos los sistemas mono tarea y los sistemas multitarea donde pudimos ver como hace el sistema para ejecutar varios procesos  la vez, así mismo revisamos el tema de lo que es el estado de ejecución de un proceso en un entorno multitarea.

 

En la segunda parte abordamos los conceptos de proceso, contexto, memoria de trabajo, stack y con conjunto de instrucciones.

 

Ahora revisaremos un tema muy importante, hasta ahora todo ha girado entorno a lo que es un proceso de manera cruda, pero las cosas están a punto de cambiar gracias a los Threads.

 

Qué es un Thread y su Uso

Un Thread es un mecanismo que permite a una aplicación realizar varias tareas a la vez de manera concurrente.

Los Threads son una ampliación del concepto de multitarea, si bien multitarea se refiere a la capacidad de un sistema para ejecutar varios procesos a la vez, en un comienzo esto hacia referencia a que más de una aplicación se estuviera ejecutando de manera concurrente, sin embargo pronto se hizo notoria la necesidad  de que una misma aplicación hiciera varias cosas a la vez. Allí nacieron los Threads.

En un sistema multitarea podemos tener los procesos A, B y C ejecutándose simultáneamente, pero que pasaba si el proceso A debía mostrar una interfaz gráfica y de paso estar escribiendo un archivo a la vez? no era posible; el proceso debía terminar de escribir en disco antes de volver a trabajar en su interfaz gráfica lo cual no era precisamente algo deseable. Así que surgió la idea de permitir que un proceso pueda tener una o mas tareas ejecutándose a la vez o al menos que así lo percibiera el usuario, de tal forma que cada vez que a un proceso le correspondiera un Quantum de ejecución el sistema alterne entre ejecutar una de sus tareas u otra.

 

Esto conlleva a la necesidad de reestructurar el concepto de proceso, ya que un proceso no es la unidad mínima de ejecución puesto que ahora el proceso es un conjunto de tareas ( en adelante hilos o threads).

Un proceso que en apariencia no utiliza threads realmente se esta ejecutando en un único thread.

 

Consideraciones de los Procesos y los Thread

De acuerdo a lo que acabamos de ver debemos tener en cuenta un par de cosas.

  • La memoria de trabajo del proceso (de lo cual hablábamos en la parte2) sigue siendo asignada por proceso, los thread dentro del proceso comparten todos la misma región  de memoria, el mismo espacio de direcciones.
  • El sistema operativo asigna Quantums de ejecución a cada thread creado, y en efecto ya no calendariza procesos sino cada uno de los hilos en ejecución en el sistema
  • Cada hilo tiene su propio contexto (estado de ejecución), así que cada vez que que se suspende un hilo para permitir la ejecución de otro, su contexto es guardado y restablecido nuevamente solo cuando es su turno de ejecución.
  • Al ser la unidad mínima de ejecución cada thread tiene su propio stack
  • El proceso si  bien ya no es la unidad de ejecución sigue siendo parte fundamental en el funcionamiento del sistema ya que el proceso hace parte de la asignación de prioridad de ejecución, es al que se le asigna memoria y de hecho es al que se le asignan los recursos. El hilo es solo quien se ejecuta ( sin demeritar en absoluto algo tan importante como esto ).

 

Usar thread no implica necesariamente ejecución en paralelo

Qué sucede si estamos utilizando varios threads en una aplicación que se ejecuta en una  maquina con una sola CPU?

Si bien la impresión del usuario es que se están ejecutando varias cosas al tiempo ya esta claro que esto es así pues en la CPU solo se puede ejecutar una cosa a la vez, lo que esta pasando realmente es que los thread están alternando tiempo de ejecución de una manera tan rápida que el usuario percibe que se están ejecutando al tiempo.

 

Pero por otro lado, qué sucede si la  maquina tiene más de una CPU?

En  este caso las cosas pueden cambiar, si nuestra aplicación tiene dos hilos y nuestra maquina tiene dos CPU en efecto cada thread se podría ejecutar en una CPU diferente, en este caso si se puede habar de ejecución en paralelo, aunque no necesariamente pues puede darse el caso en que, debido a la necesidad del sistema de calendarizar  threads de otros procesos, ambos thread se ejecuten en la misma CPU en un momento dado, en ese momento no habría paralelismo.

 

Pero hay otro escenario

Que pasa si mi maquina tiene 2 CPU pero mi aplicación esta utilizando más de 2 thread?

Lo que sucederá es que solo dos de esos thread se estarán ejecutando en paralelo en un momento dado (aunque ya vimos que esto no es necesariamente lo que sucede), y el sistema operativo alternara la ejecución de dichos thread de tal forma que todos tengan Quantums asignados, pero solo podrán haber máximo 2 en paralelo.

 

Es cierto que usar threads hará que mi aplicación se ejecute más rápido?

De acuerdo a lo que vimos en la sección anterior podemos concluir rotundamente que : DEPENDE.

 

Como ya vimos si tu maquina tiene solo 1 CPU realmente hará tu aplicación mas lenta, pero con la ventaja de poder efectuar varias tareas a la vez (en apariencia), pero si tienes tantas o más CPU como threads en ejecución el rendimiento si que mejorara, es decir si tienes 2 thread y 2 CPU seguramente que si estarás haciendo dos cosas a la vez y no una cosa cada vez.

 

El efecto contrario se evidencia toda vez que trates de ejecutar más threads que las CPU que tienes, es decir si vas a ejecutar 20 threads y solo tienes 2 CPU en vez de ganar rendimiento realmente lo que harás será castigarlo puesto que esos thread estarán compitiendo por el tiempo de CPU, lo cual se traduce en múltiples y frecuentes cambios de contexto que harán perder el preciado tiempo de CPU en la lógica necesaria par cambiar de un thread a otro.

 

En estos escenarios es conveniente administrar la ejecución de los  thread para que solo se ejecuten tantos thread como CPUS existan, y solo entren en ejecución threads nuevos cuando hayan CPUS disponibles. Esto es muy engorroso de hacer pero es allí donde la TPL es de gran ayuda.

 

Otra cosa importante de notar es que la creación y la administración de threads es costosa desde el punto de vista del uso de CPU así que si una aplicación que se ejecuta en una maquina con más de una CPU requiere ejecutar una tarea corta  en partes paralelas  probablemente sea mucho mas rápido ejecutarla normalmente que abrirla en threads, mientras que en una tareas suficientemente grande el tiempo invertido en crear y administrar los threads puede ser proporcionalmente insignificante.

 

Diferencias entre Threads del kernel y Threads de Usuario ( Fibras / Fibers ).

Si, hay diferentes tipos de thread, dependiendo de la estructura del sistema operativo esto puede variar.

Pero en términos generales existen los tipos de thread que he mencionado inicialmente.Veremos como funciona en Windows.

 

Los thread de Kernel

Todo sistema operativo tiene un kernel, el kernel encargado de todo lo que en  esencia es el sistema operativo ofrece muchas funcionalidades, una de ellas crear threads ya que son su unidad minina de ejecución y funcionan  muy bien tal como lo hemos visto. 

 

En Windows cada vez que se crea un thread se crea un objeto del kernel que tiene toda la información necesaria respecto a que proceso, cual código ejecutable del thread, etc. están asignados a dicho thread. Este objeto thread existe en el espacio de direcciones asignadas al kernel.

Recordemos que cada proceso solo puede acceder a los objetos o áreas de memoria dentro de su propio espacio de direcciones, entonces Cómo hace un proceso para acceder a un objeto thread que esta en otro espacio de direcciones ( el del kernel )? bueno el kernel como tal se encarga de eso asignándole al proceso un manejador al thread, el kernel mantiene una tabla de que identificadores de recursos tiene asignado el proceso, así que cuando un proceso quiere acceder a algún objeto del kernel, en este caso threads, utiliza funciones de la API de Windows que con el identificador del objeto hacen llamados al kernel los cuales son quienes en ultima instancia manipulan al objeto en su propio espacio de direcciones del kernel.

 

Entonces, cada vez que en nuestro proceso utilizamos un thread y queremos modificar su comportamiento o verificar su información estadística lo que sucede tras bambalinas es que se hacen llamados al kernel. El kernel proporciona acceso a funcionalidades que puedes modificar o supervisar el funcionamiento del thread.

 

El kernel se encarga de manera automática de calendarizar la ejecución de cada uno de los thread en ejecución. Si un thread de un proceso invoca a un dispositivo de I/O como por ejemplo la impresora, el thread queda suspendido hasta que la impresora le conteste pero otros thread del mismo proceso seguirán ejecutándose.

Los thread de usuario

Básicamente son los mismos thread de kernel con la diferencia en que estos no son administrados por el kernel del sistema operativo, es decir el sistema operativo no sabe que existen. Son administrador por los programas de usuario.

Un ejemplo de estos son los thread creados en .Net Framework o en java, todos estos thread son creados, calendarizados y administrados por el runtime de cada uno de ellos, el sistema operativo en esencia no sabe nada de ellos. Cada thread del kernel puede tener tener dentro de si uno o mas thread de usuario. el sistema operativo solo calendariza threads de kernel.

 

Entonces, cada vez que en nuestro proceso utilizamos un user thread y queremos modificar su comportamiento o verificar su información estadística lo que sucede tras bambalinas es que se hacen llamados a funciones dentro del propio espacio de direcciones del proceso y este se encarga de hacer el trabajo necesario. En adelante me referiré a los thread de usuario como fiber.

 

El propio programa se encarga de manera automática de calendarizar la ejecución de cada uno de los fiber en ejecución.

Si un fiber de un proceso invoca a un dispositivo de I/O como por ejemplo la impresora, el fiber queda suspendido hasta que la impresora le conteste pero los otros fiber del mismo proceso también se bloquearan y no seguirán ejecutándose, porque? recordemos que el sistema operativo no conoce dichos threads así que si uno se bloquea para el sistema operativo es como si todo el proceso estuviese bloqueado así que este tipo de thread son totalmente bloqueantes del proceso cuando están a la espera de respuesta de un dispositivo.

 

Para solucionar esto, Windows ofrece mecanismos que permiten asociar un fiber a un thread de kernel nuevo independiente , de tal forma que si por ejemplo el java virtual machine detecta que uno de sus thread ( que son en realidad fibers ) queda bloqueado en espera de un dispositivo, la maquina de java para no bloquear los otros thread del proceso crea un nuevo thread de sistema operativo y lo asocia con ese fiber para que el thread principal ( donde corren los demas fiber ) no quede bloqueado.

 

Diferencias

Dado lo que he explicado anteriormente podemos contemplar los siguientes aspectos:

 

  • Los thread de usuario ( fibers ) son mucho más eficientes en escenarios con varios thread que los thread del kernel. Principalmente por dos razones:

1- Los thread de usuario no requieren ser conmutados en modo kernel sino en modo usuario lo cual permite hacer la conmutación entre threads de manera más rápida al no tener que alternar de contexto.

2- No son calendarizados de manera preferente, sino que de manera ‘manual’ deben ser suspendidos o reactivados, lo que da la opción de hacer una calendarización mucho más adecuada de acuerdo al juego de threads que se estén ejecutando.

  • Los thread de usuario tienen la desventaja de que no tienen mayor soporte del sistema operativo lo que conlleva a que hay que hacer mucho trabajo de manera manual, por ejemplo efectuar la calendarización .
  • Los thread de usuario bloquean a todos los thread del proceso cuando estos están bloqueados a espera de una llamada al kernel o a un dispositivo de IO, lo cual hace que se pierda la funcionalidad de procesamiento paralelo. Algunos sistemas operativos como es el caso de Windows, proveen funcionalidades para convertir fiber a kernel thread y viceversa , lo cual facilita dar solución a estos escenarios de bloqueo.
  • En términos generales es mucho mas recomendable trabajar con Kernel Threads que con Fibers, dada su mayor complejidad los fibers pueden traer mas problemas de lo que solucionan. Sin embargo hay escenarios donde la implementación de fibers es muy recomendable y de hecho casi un deber como es en los siguientes casos:

1- migrar una aplicación de Linux/Unix a Windows

2- crear un runtime de ejecución de programas como es el caso del CLR o del  java virtual machine.

3- crear una aplicación profundamente compleja e intensiva a nivel de manejo de threads

 

Eso es todo!

Estos son los dos artículos anteriores:

 

Parte 1 : Manejador de Procesos – Fundamentos

Parte 2 : Manejador de Procesos – Procesos

 

Bookmark and Share