P. 1
[002] Sistemas Operativos - Gestion de Procesos

[002] Sistemas Operativos - Gestion de Procesos

|Views: 3.661|Likes:
Publicado porGust Alva
El sistema operativo se encarga de
controlar todos los procesos cargados en memoria, de la asignación de la CPU.
El sistema operativo se encarga de
controlar todos los procesos cargados en memoria, de la asignación de la CPU.

More info:

Published by: Gust Alva on Aug 25, 2009
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

08/18/2013

pdf

text

original

Sections

 *HVWLyQ GH 3URFHVRV

Como se vio en la Introducción, en los sistemas operativos actuales se puede disponer de varios programas en memoria que se pueden ejecutar, dependiendo de la política de planificación, de una forma más o menos simultánea. En este capítulo nos vamos a ocupar de cómo el sistema operativo se encarga de controlar todos los procesos cargados en memoria, de la asignación de la CPU a cada uno de los procesos, y, cuando se trate de procesos cooperantes, de la comunicación y sincronización entre ellos.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV 

,QWURGXFFLyQ
Sabemos que la CPU realiza ciertas actividades. En un sistema de tratamiento por lotes (EDWFK), se ejecutan trabajos; en un entorno de tiempo compartido hay programas de usuarios, o tareas; incluso en un ordenador personal, hoy día un usuario puede ejecutar varios programas simultáneamente, uno interactivo, y otros en segundo plano (EDFNJURXQG . La cuestión es cómo llamar a todas estas actividades que realiza la CPU. Pues bien, a estas actividades las denominaremos SURFHVRV. 

&RQFHSWR GH 3URFHVR
Se han oído muchas definiciones de proceso, pero, sin duda, la más popular y acertada es la que dice que “XQ SURFHVR HV XQ SURJUDPD HQ HMHFXFLyQ”. Ya que no es nada fácil dar una definición autoexplicativa de lo que es un proceso, vamos a tratar de explicarlo mediante ideas y ejemplos. Ante todo, se debe tener muy presente que un proceso asocia programa+actividad. Cuando decimos que un proceso es un programa en ejecución, nos referimos al hecho de llevar a cabo o realizar las instrucciones que contiene el programa en el orden establecido. Un programa es una lista de instrucciones escritas en un papel, un fichero en disquete, disco duro, memoria RAM o cualquier otro soporte, pero el simple hecho de que estas instrucciones estén escritas no implica que se estén llevando a cabo. Pues bien, cuando se leen estas instrucciones y se hacen ejecutar, entonces ya tenemos programa+actividad, es decir, un proceso. Hacemos hincapié en DFWLYLGDG para diferenciarlo bien de un mero programa, ya que una característica básica de los programas es que son estáticos. Ya hemos dicho que un programa es una secuencia de órdenes que, por mucho que la miremos, no varía nunca. Las variables no tienen valores, las rutinas no tienen dirección, las condiciones están sin evaluar. Un programa es simplemente XQ DOJRULWPR D HMHFXWDU En cambio, un proceso es dinámico. Tiene vector de estado indicando el momento y estado de su ejecución, las variables tienen valores, las rutinas se encuentran en alguna dirección de memoria, y las condiciones son evaluables. El proceso es OD HMHFXFLyQ GHO DOJRULWPR Un ejemplo que puede describir la relación programa-proceso puede ser el manual de montaje de un aeromodelo que viene despiezado. Las instrucciones de montaje que vienen en la caja son algo estático (por eso aunque dejemos mucho tiempo las instrucciones en la caja, el aeromodelo no aparece construido al cabo de un tiempo. Sin embargo, cuando cogemos las instrucciones y empezamos a hacer lo que indican, es cuando empieza la actividad, entonces comienza el SURFHVR de montaje. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

,QWURGXFFLyQ

&RQFHSWR GH 3URFHVR
¢4Xp HV XQ 3URFHVR"
(V XQ 3URJUDPD HQ (MHFXFLyQ

8Q 3URJUDPD (V HVWiWLFR 1R YDUtD QDGD 1R WLHQH YHFWRU GH HVWDGR → 9DULDEOHV VLQ YDORUHV 5XWLQDV VLQ GLUHFFLyQ &RQGLFLRQHV VLQ HYDOXDU (V HO DOJRULWPR D HMHFXWDU 8Q 3URFHVR (V GLQiPLFR

1R UHTXLHUH SURFHVDGRU

1HFHVLWD SURFHVDGRU /DV YDULDEOHV WLHQHQ YDORUHV 7LHQH YHFWRU GH HVWDGR → /DV UXWLQDV HVWiQ HQ DOJXQD GLUHFFLyQ /DV FRQGLFLRQHV VH SXHGHQ HYDOXDU (V OD HMHFXFLyQ GHO DOJRULWPR

352&(62 (VWDGR 

3URJUDPD  3URFHVDGRU

(VWDGR 

6H QHFHVLWD
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD 

8Q &3  8Q iUHD GH WUDEDMR

SRU SURFHVR

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Si en la construcción del aeromodelo, quien lleva a cabo las instrucciones del manual de montaje es la persona, que lee las instrucciones y las va ejecutando; en un ordenador, el ente que va leyendo las instrucciones del programa (que está en memoria) y ejecutándolas, es la CPU. Así, tenemos que el tándem programa+procesador es el que hace que el estado de desarrollo de un determinado trabajo evolucione y cambie de un estado a otro. Al igual que para la construcción del aeromodelo se necesita un área de trabajo (una mesa o algo similar), para la ejecución de un programa, también se requiere un área de trabajo, esto es, OD SLOD del proceso. La pila es la zona de memoria en la que se guardan los parámetros, variables locales, direcciones de retorno de subprogramas y, en general, los datos temporales del proceso. Un proceso también se caracteriza porque en un momento dado de su ejecución dispone de ciertos valores en los registros del procesador, entre ellos, el &RQWDGRU GH 3URJUDPD que contiene la dirección de la instrucción que va a ejecutar el proceso a continuación. Así, el Contador de Programa es el registro que indica el punto de ejecución del programa en el que se encuentra el proceso. Se debe tener en cuenta que la relación entre un programa y su proceso no es biunívoca. Esto se debe al hecho de que en un momento dado puede haber varios procesos correspondientes al mismo programa. Por ejemplo, en una clase de trabajos manuales pueden estar escritas en la pizarra las instrucciones de montaje de un aeromodelo (un programa) y todos los alumnos están montando un aeromodelo siguiendo las mismas instrucciones (varios procesos). Un ejemplo más informático puede ser el de varios alumnos que, en un momento dado, están utilizando el editor de texto en distintos terminales de un sistema de tiempo compartido. Hay un único programa editor de texto, pero puede haber varios procesos simultáneos ejecutando tal programa. 

'HVFULSWRU GH 3URFHVR
Como ya sabemos, en un sistema multiprogramado se pueden ejecutar simultáneamente varios programas, es decir, en un momento dado puede haber varios procesos. En un sistema con un único procesador no se puede decir que haya varios programas ejecutándose estrictamente de una forma simultánea. En realidad, la posesión del procesador se va repartiendo entre los distintos procesos, dando lugar a una ejecución pseudoparalela. No obstante, por simplicidad, nos referiremos, en general, a ejecución simultánea o paralela, tanto si es estricta (sistema multiprocesador) como si no lo es (con un solo procesador). El FRQWH[WR de un proceso se define como la información necesaria para especificar completamente su estado actual. Esto incluye toda la información que ha de salvarse cuando un proceso pierde la posesión de la CPU, y hay que restaurar cuando se le vuelve a conceder la posesión del procesador. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

El contexto de un proceso, dependiendo del lugar donde reside la información, está formado por tres tipos de información: • Bloque de Control de Proceso (BCP) • Contexto de Memoria • Contexto del Procesador El %ORTXH GH &RQWURO GH 3URFHVR (o Descriptor de Proceso) comprende la información que siempre está en la memoria principal durante la existencia del proceso. El BCP contiene la información relativa a un proceso que requiere el sistema operativo para gestionarlo. Igual que en una empresa se dispone de las fichas de los empleados, con los datos necesarios para la administración (Datos personales, profesionales, salarios, horas extraordinarias, etc.), el sistema operativo dispone de los BCP de cada uno de los procesos que tiene en cada momento. Aunque el contenido de los descriptores de procesos varía de un sistema a otro, en la Figura 2 se puede ver un ejemplo con algunos datos típicos que suelen contener. A lo largo de este capítulo se irá viendo el significado y utilidad de estos datos del BCP, así como las estructuras de datos que contiene el sistema operativo para mantener los BCP’s de todos los procesos. El &RQWH[WR GH 0HPRULD contiene lo que es el programa en sí, es decir, las instrucciones y los datos del programa. Esta parte solamente necesita estar en memoria principal cuando el proceso está realmente en ejecución, o sea, que tiene la CPU asignada; el resto del tiempo, el contexto de memoria puede encontrarse en disco, liberando así espacio de memoria principal. El &RQWH[WR GHO 3URFHVDGRU es la parte del contexto del proceso almacenado en los registros del procesador. En estos registros se mantienen datos tales como el Contador de Programa, el estado de la CPU, el puntero de la pila utilizada por el proceso, registros de control y registros de propósito general para mantener datos de las variables o constantes del programa. Como ya hemos dicho, el BCP es algo así como la ficha de control del proceso, por esto, en él también se encuentra la información necesaria para poder acceder tanto al contexto de memoria como al del procesador.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

,QWURGXFFLyQ

'HVFULSWRU GH 3URFHVR
¢&yPR 9H HO 62 D ORV 3URFHVRV"
0HGLDQWH VX YHFWRU GH HVWDGR HQ XQ 'HVFULSWRU GH 3URFHVR

(O 'HVFULSWRU GH 3URFHVR FRQWLHQH LQIRUPDFLyQ GHO 3URFHVR GH VX 0HPRULD GH (VWDGR GHO 3URFHVDGRU 5HJLVWURV &RQWH[WR GHO SURFHVR

W\SH DESCRIPTOR_PROCESO LV UHFRUG Id_Proceso Siguiente Estado Puntero_Pila Memoria_Utilizada Ficheros_Abiertos Proceso_Padre Procesos_Hijos Dormido_Hasta HQG UHFRUG;

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ" 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV 

6LVWHPDV 0XOWLSURFHVR 3DUDOHOLVPR
En la Introducción ya se vio, por encima, la utilidad de ejecutar varios programas de forma simultánea para evitar el desaprovechamiento de los tiempos de espera de CPU a las respuestas de los dispositivos periféricos en las operaciones de entrada/salida que realiza un proceso. Otra justificación de la ejecución paralela de programas viene dada por las leyes de la física, pues según la Teoría de la Relatividad de Albert Einstein es imposible transmitir señales eléctricas a más velocidad que la de la luz, esto es, unos 30cm por nanosegundo. Esto quiere decir que el tiempo mínimo que puede tardar en transmitirse una señal entre dos componentes de un ordenador separados 30cm es 1ns. O sea, que los ordenadores tendrían que empezar a fabricarse cada vez más pequeños, pero claramente, sabemos que esto tiene ciertas limitaciones. Por otra parte, algunos programas (cálculo científico, tiempo real, etc.) requieren, a menudo, ciertas velocidades de ejecución, para que el resultado sea exitoso. Una forma de conseguir que un programa se ejecute más rápidamente que ejecutando una instrucción tras otra, consiste en dividir el programa en varias tareas o procesos y ejecutándolos en paralelo. Un símil de la vida real puede ser el proceso de fabricación de los automóviles. Las cadenas de montaje de los coches no fabrican primero las ruedas, luego el motor, a continuación el chasis, después la carrocería, luego los cristales, ...; sino que cada uno de estos elementos se fabrica por separado de forma paralela y simultánea, y cuando están todos construidos, se realiza el proceso de ensamblaje para formar el automóvil completo. De esta forma se consigue construirlo en bastante menos tiempo. Ya tenemos, por tanto, dos buenas razones para la multiprogramación: • Los procesos cooperantes, para realizar un trabajo en conjunto. • Mejorar el rendimiento del ordenador, aprovechando la CPU en sus tiempos de espera por dispositivos de E/S, dando lugar a sistemas multiusuario o simplemente de multiproceso. No debemos confundir un sistema PXOWLSURFHVR con PXOWLXVXDULR. Un entorno multiproceso es el que permite varios procesos simultáneos, por ejemplo, una persona en un terminal con ventanas tal que en cada ventana tiene distintos procesos en ejecución (un editor de texto, un reloj, un videoclip, etc.). En este sistema es posible que no haya más puestos de trabajo o terminales, con lo que sería un entorno multiproceso monousuario. Si se dispone de varios terminales en un sistema, entonces, además de multiproceso, es multiusuario.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR 3DUDOHOLVPR
3UREOHPDV GHO 3URFHVDPLHQWR 6HFXHQFLDO
/DV OH\HV GH OD ItVLFD LPSRQHQ OLPLWDFLRQHV GH YHORFLGDG 1R VH DSURYHFKD OD &38

£62/8&,Ð1

352&(6$0,(172 3$5$/(/2 R VHXGRSDUDOHOR 08/7,352*5$0$&,Ð1 0XOWLSOH[DFLyQ GH OD &38 HQWUH SURFHVRV FRQFXUUHQWHV FRRSHUDQWHV R QR

3URFHVRV &RRSHUDQWHV

0XOWLSURFHVR ≠ 0XOWLXVXDULR

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ# 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV 

6LVWHPDV 0XOWLSURFHVDGRU0RQRSURFHVDGRU 0XOWLSOH[DFLyQ GH OD &38
Sabemos que para que un programa se ejecute, hay que convertirlo en proceso, y para que éste evolucione de un estado a otro se requiere un procesador. Si hablamos de sistemas multiproceso, es decir, que hay varios programas simultáneamente en memoria, lo más conveniente para la ejecución más rápida es asignar un procesador a cada uno de los procesos, para que evolucionen todos de una forma realmente paralela o simultánea. Este es el caso de los ordenadores con múltiples procesadores, en los que en un momento dado se encuentran realmente en ejecución varios programas. Si bien esta es la forma más rápida de ejecutar múltiples programas, también resulta ser, obviamente, la más cara. No solamente por la cantidad de hardware utilizado (cuando menos, varias CPU’s), sino también por el hardware y software adicional necesario para poder sincronizar y gestionar múltiples CPU’s, algo mucho más complejo que cuando solamente se dispone de un único procesador. (Resultan mucho más sencillos los departamentos de personal, marketing, fabricación, distribución etc. de una empresa de 2, 3 o 4 empleados, que los de una multinacional de miles de empleados). Ya que la mayoría de los ordenadores actuales de propósito general constan de un sólo procesador, vamos a centrarnos aquí en los ordenadores monoprocesadores, dejando los de múltiples procesadores para otras asignaturas de arquitecturas avanzadas. Si tenemos un sistema operativo multiproceso y contamos con un único procesador, solamente tenemos una elección: +D\ TXH UHSDUWLU HO SURFHVDGRU HQWUH ORV SURFHVRV. De esta manera, lo que conseguimos es simular una máquina multiprocesador, es decir, tendremos un pseudoparalelismo en la ejecución de los procesos. Así, aunque no obtengamos todas las ventajas de una ejecución puramente paralela, sí aprovecharemos el hecho de que durante la ejecución de un programa hay muchos momentos en que no se puede continuar su ejecución hasta que no se produzca algún evento externo a la CPU, como por ejemplo la realización de una operación solicitada a un dispositivo de E/S, la pulsación de un carácter en el teclado, la llegada de un carácter por la línea de comunicaciones, una interrupción generada por un detector, etc. Quizás nos puedan servir como ejemplo las partidas de ajedrez simultáneas que mantienen los maestros de ajedrez con 20 principiantes. Cuando el maestro realiza una jugada con un principiante, éste tarda mucho tiempo hasta que decide mover; mientras tanto, el maestro puede realizar jugadas con el resto de los aprendices, y seguramente, le dará tiempo a hacer un movimiento con cada uno de los rivales antes de que el primero de ellos se haya decidido a mover una figura. En este ejemplo tan optimista, esta partida simultánea se realiza en 1/20 del tiempo que se tardaría si el maestro primero se dedicase por entero a jugar una partida con el primer aficionado, hasta finalizarla; luego comenzar otra partida con el segundo y así sucesivamente hasta haber jugado las 20 partidas. En los casos reales de nuestros ordenadores, el reparto de la CPU no suele resultar tan provechoso como en el caso del maestro de ajedrez, pues a menudo, también hay procesos a los que

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV 

6LVWHPDV 0XOWLSURFHVR
0iTXLQD 0XOWLSURFHVDGRU 8Q 3URFHVR 8Q 3URFHVDGRU

0iTXLQD 0RQRSURFHVDGRU +D\ TXH VLPXODU XQD PiTXLQD PXOWLSURFHVDGRU 6HXGRSDUDOHOLVPR

HO SURFHVDGRU £ +D\ TXH UHSDUWLUSURFHVRV HQWUH ORV
3URFHVR 

3URFHVR 

3URFHVR 

0XOWLSURFHVDGRU

0RQRSURFHVDGRU PXOWLSOH[DGR

3URFHVR HQ HMHFXFLyQ 3URFHVR HQ HVSHUD

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ$ 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

se les quita la posesión de la CPU antes de que ellos la liberen por una de sus esperas a un evento externo, por lo que nos encontramos con procesos que están parados cuando sí podrían ejecutarse de tener una CPU disponible. En el peor de los casos, es decir cuando se disponga de varios procesos que no tienen esperas de E/S, la diferencia entre ejecutarlos en un entorno multiprocesador o monoprocesador es la que se muestra en el gráfico de la Figura 5, en la que se aprecia que la CPU se reparte en porciones de tiempo entre los distintos procesos, por lo que mientras uno se ejecuta, los demás deben esperar su turno de CPU. En este caso decimos que la utilización de la CPU está PXOWLSOH[DGD HQ HO WLHPSR. 

(VWDGRV \ 7UDQVLFLRQHV GH ORV 3URFHVRV
Anteriormente hemos visto que un ejemplo del FLFOR GH YLGD de un proceso podría estar caracterizado por esta secuencia: 1. Se está ejecutando (posee la CPU). 2. Realiza una operación de E/S y se pone a esperar la respuesta (abandona la CPU). 3. Cuando recibe la respuesta de la operación de E/S desea continuar la ejecución (necesita otra vez la CPU). También hemos visto con anterioridad que en otras ocasiones, el tiempo de CPU se reparte en porciones entre todos los procesos que lo solicitan, por lo que un proceso puede ver cómo pierde la posesión del procesador, de forma involuntaria, cuando se le acaba la porción de tiempo que tenía asignada. Este ciclo de vida de un proceso lo podemos ver en la Figura 6. En esta figura, los círculos son recursos o condiciones deseadas por un proceso, mientras que los rectángulos representan las colas de procesos que esperan por tales recursos. Así, vemos que un proceso recién creado inmediatamente quiere ejecutarse, para lo cual necesita la CPU, por lo que pasa a la cola de los procesos que esperan por el procesador (cola de procesos SUHSDUDGRV). Una vez que le llega el turno, ejecuta las instrucciones, hasta que por uno de los motivos mencionados (operación de E/S, fin de la porción de tiempo, etc.) pierde la posesión de la CPU y pasa a la cola del recurso solicitado (Disco 1, Unidad de Cinta 3, esperar a las 2:00 de la mañana). Si la posesión del procesador se ha perdido por finalizar la porción de tiempo asignado o bien porque un proceso de mayor prioridad requiere el procesador, el recurso que necesita el proceso expulsado (o expropiado) es la propia CPU, por lo que pasa a la cola correspondiente (la de los procesos preparados). Este ciclo se repite una y otra vez hasta que el proceso ejecuta su última instrucción, o sea, que finaliza el trabajo, con lo que voluntariamente cede el control de la CPU y da por concluida su existencia como proceso. Así, llegamos ya al diagrama básico de estados de un proceso, que lo vemos representado en la parte superior de la Figura 7. En él tenemos que un proceso está ejecutando instrucciones ((Q (MHFXFLyQ), esperando a que le concedan la CPU
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

para ejecutar instrucciones (3UHSDUDGR), o esperando a que se produzca algún evento externo ((Q (VSHUD o EORTXHDGR).

Tv†‡r€h†ÃHˆy‡vƒ…‚pr†‚

&LFOR GH 9LGD GH XQ SURFHVR
8…rhpvy 

 

35(3$5$'2

&38

Ur…€vhpvy

load store add store read fichero
@†ƒr…hÃ@T

@‘ƒˆy†vy Qr…v‚q‚ 8QV

Qr…v‚q‚ @T Qr…v‚q‚ 8QV Qr…v‚q‚ @T

'LVFR 

9DT8PÃ

store increment write fichero
@†ƒr…hÃ@T

(V OD KRUD

9‚…€vq‚Ãuh†‡h yh†Ã!)

load store add store read fichero
@†ƒr…hÃ@T

Qr…v‚q‚ 8QV

&LQWD 

8DIU6Ã"

Qr…v‚q‚ @T 


Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ%

Vamos a ver cómo se producen las transiciones entre estos tres estados. &UHDFLyQ → 3UHSDUDGR Inicialmente, al crear un proceso, no puede pasar directamente al estado de Espera, pues no se ha ejecutado ninguna instrucción que así se lo indique; por lo tanto, expresa su necesidad de ejecución entrando en la cola de procesos Preparados. 3UHSDUDGR → (Q (MHFXFLyQ Una vez que el proceso está preparado, solamente tiene que esperar a que le llegue el turno. Los turnos del procesador se establecen en función de la política de planificación de la CPU. Cuando le llegue el turno tomará posesión del procesador y empezará a ejecutar instrucciones. Como podemos ver en el gráfico, desde el estado de Ejecución se puede pasar a cualquiera de los otros dos estados (Espera y Preparado). 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR

(VWDGRV GHO 3URFHVR
(Q (MHFXFLyQ 7HUPLQDFLyQ

&UHDFLyQ

3UHSDUDGR

(Q (VSHUD

MAX_PROCESOS : constant 100; type ID_PROCESOS is INTEGER range 0..MAX_PROCESOS; type &2/$B352&(626 is record Primero : ID_PROCESOS := 0; Ultimo : ID_PROCESOS := 0; end record;

3URFHVRV : array [1..MAX_PROCESOS] of DESCRIPTOR_PROCESOS; (QB(MHFXFLyQ : ID_PROCESOS; 3UHSDUDGRV (QB(VSHUD : COLA_PROCESOS; : COLA_PROCESOS;

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ&

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

(Q (MHFXFLyQ → 3UHSDUDGR Pasará a Preparado si abandona la CPU involuntariamente, es decir si se le expulsa (o expropia), bien porque haya terminado su porción de tiempo, o porque haya pasado a Preparado otro proceso de mayor prioridad. (Q (MHFXFLyQ → (VSHUD En cambio, pasa al estado de Espera si cede voluntariamente el procesador, por tener que esperar a que se produzca un evento externo a la CPU. (VSHUD → 3UHSDUDGR Desde el estado de Espera no se puede volver directamente a Ejecución, sino que cuando se haya cumplido el evento externo, para recuperar la posesión del procesador hay que pasar de nuevo por la cola de los procesos preparados. Así tenemos que para conseguir la posesión de la CPU siempre hay que pasar por su cola correspondiente (como un recurso más que es). (Q (MHFXFLyQ → 7HUPLQDFLyQ Como ya hemos dicho antes, el proceso termina cuando ejecuta su última instrucción, luego siempre pasará al estado de Terminado desde Ejecución.

Como hemos visto, a medida que progresa su ejecución, un proceso va cambiando de estado. A excepción de los estados obvios de &UHDFLyQ y 7HUPLQDFLyQ, un proceso tiene dos estados básicos: $FWLYR y (Q (VSHUD $FWLYR El proceso no depende de ninguna condición externa al procesador para poder continuar su ejecución. O bien se está ejecutando, o se encuentra esperando en la cola de procesos Preparados a que le concedan la posesión de la CPU.

(Q (VSHUD El proceso no puede continuar la ejecución. Está bloqueado, a la espera de que se cumpla un evento externo a la CPU, tal como una respuesta de un dispositivo de E/S, que llegue una hora determinada, etc.

Vistos los estados que puede tener un proceso y las transiciones entre ellos, nos interesa saber FyPR HO VLVWHPD RSHUDWLYR OOHYD FRQWURO GH WRGRV ORV SURFHVRV FUHDGRV, cómo se realizan estas colas de procesos y cómo se sabe qué proceso está en ejecución. En un apartado anterior hemos visto que hay una estructura de datos que contiene toda la información de control que requiere el sistema operativo para ocuparse de la gestión o administración del proceso. Nos estamos refiriendo al Descriptor de Proceso o Bloque de Control de Proceso (BCP). Pues bien, entonces lo que el sistema operativo necesita es mantener la colección de todos los BCP’s de los procesos existentes en cada momento. Esta colección de BCP’s se puede organizar de distintas maneras: mediante una cola estática, con una cola dinámica, o simplemente utilizando una tabla, es decir, un vector o array de BCP’s. Así vemos 
$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR 

(VWDGRV GHO 3URFHVR

(1B(-(&8&,Ð1 

35(3$5$'26 3ULPHUR ÓOWLPR

%&3 

%&3 

'LVFR  3ULPHUR ÓOWLPR

&LQWD  3ULPHUR ÓOWLPR

%&3 

%&3 

%&3 

7HUPLQDO  3ULPHUR ÓOWLPR  

%&3        

7DEOD GH %&3V
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

6LJ QLO 6LJ QLO 6LJ  6LJ  6LJ QLO 6LJ QLO 6LJ  6LJ QLO 6LJ QLO         

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ'

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

en el recuadro inferior de la Figura 7 la declaración de Procesos como un array de tamaño Max_Procesos y formado por elementos de tipo Descriptor_Procesos. De esta manera, el sistema operativo puede consultar el BCP de cada proceso accediendo a la tabla Procesos utilizando el identificador del proceso como índice. También se puede apreciar que la variable En_Ejecucion contiene el identificador del proceso que actualmente se encuentra en posesión de la CPU. Por último, podemos observar la implementación del estado de Preparado, o sea, una variable de tipo Cola_Procesos (que hace de cabecera de una cola), que no es más que un registro con dos campos que indican, respectivamente, cuál es el primero y el último elemento de una cola de procesos. Cada elemento de la cola de procesos es un BCP, y si nos fijamos en su declaración de la Figura 3 podemos ver que gracias al campo Siguiente, que es el enlace, resulta fácil formar dicha cola. El campo Siguiente contiene un identificador de proceso (el siguiente en la cola) o bien el valor NIL si es el último de la cola. Habiendo visto cómo se construye la cola de Preparados, resulta fácil imaginar que las colas de procesos para cada uno de los recursos por los que se puede esperar (dispositivos de E/S, etc.) se implementan de igual forma. En la Figura 8 se muestra un ejemplo del estado de los procesos en un momento determinado. Por una parte tenemos que el proceso en Ejecución es el 6, y que la cola de los procesos Preparados está formada por los procesos 7 y 2. No hay ningún proceso esperando para acceder al Disco_1, mientras que por la Cinta_3 están esperando los procesos 3, 4 y 1. Por último, tenemos al proceso 5 que está esperando por el Terminal_1. En la parte inferior de esta Figura 8 tenemos la tabla de BCP’s en la que se pueden observar los valores que toman los campos Siguiente para formar las colas de procesos de este ejemplo. 

&DPELR GH 3URFHVR HQ (MHFXFLyQ &DPELR GH &RQWH[WR
Cuando un proceso en ejecución pierde la posesión de la CPU, se debe a uno de los siguientes motivos: • Llamada al sistema • Interrupción • Fin del proceso Está claro que ante ciertas llamadas al sistema (una petición de E/S, dormir, etc.) el proceso en cuestión queda bloqueado, sin poder continuar la ejecución de instrucciones, hasta que se atienda el servicio solicitado; por esto, cede la posesión del procesador para que pueda ejecutar instrucciones otro proceso que esté preparado. También puede ocurrir que una interrupción anuncie el final de la actual posesión del procesador. Esto será así si la interrupción es la generada por el reloj del sistema y se detecta que se ha consumido la porción de tiempo asignada (en un 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR

&DPELR GH 3URFHVR
HQ HMHFXFLyQ
3HWLFLyQ GH (6 'RUPLU 

+ //$0$'$ $/ 6,67(0$

0RWLYRV + ,17(5583&,Ð1 GHO &DPELR

)LQ GH OD URGDMD GH WLHPSR 6H SUHSDUD XQ SURFHVR GH PD\RU SULRULGDG

+ ),1 '(/ 352&(62 &DPELR HQ 'RV )DVHV

¨ 6HOHFFLRQDU HO 6LJXLHQWH 3URFHVR
3/$1,),&$'25

© &DPELDU HO &RQWH[WR GH (MHFXFLyQ
',63$7&+(5

£ (O &DPELR GH 3URFHVR &RQVXPH 7LHPSR

0LQLPL]DU ORV &DPELRV GH 3URFHVRV

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ(

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

sistema de tiempo compartido); o bien la interrupción la ha generado algún dispositivo de E/S indicando el fin de una operación previamente solicitada, con lo que el proceso que la había requerido sale de su situación de espera y pasa al estado de Preparado. En un entorno de planificación de CPU por prioridades, si este proceso que acaba de pasar a Preparado tiene mayor prioridad que el que está en Ejecución, se le quita a éste último el procesador para asignárselo al proceso de mayor prioridad. Por último, el motivo trivial de pérdida de procesador se debe a que el proceso en Ejecución llega a su fin. Detectado esto, el sistema operativo asigna la CPU a algún proceso preparado. Si un proceso pierde el control de la CPU ¡habrá que asignárselo a otro proceso! Efectivamente, y hay que realizarlo en dos pasos: 1º Seleccionar el siguiente proceso 2º Realizar el cambio de contexto De realizar el primer paso se encarga el SODQLILFDGRU (o VFKHGXOHU), que utilizando la política establecida de planificación a corto plazo selecciona un proceso de la cola de Preparados. Esta política de SODQLILFDFLyQ D FRUWR SOD]R establece la asignación de la CPU a uno de los procesos preparados, mientras que la política de SODQLILFDFLyQ D ODUJR SOD]R se utiliza para elegir uno de los trabajos que están en el disco duro esperando para ser cargados en memoria y comenzar su ejecución. Una vez conocido el identificador del proceso que va a apropiarse de la CPU, hay que cederle el control del procesador, pero no antes de realizar el cambio de contexto. Para esto, se da control al 'LVSDWFKHU, que es la parte del sistema operativo que se encarga de terminar de salvar el contexto del programa que abandona la CPU (o perderlo definitivamente si se debe a una terminación del proceso) y establecer el contexto del proceso seleccionado. De hecho, el último de los pasos de que consta el cambio completo del contexto, consiste en restaurar el Contador de Programa del proceso elegido. Una vez que el registro Contador de Programa es restaurado, la siguiente instrucción que se ejecuta es ya una instrucción del proceso seleccionado. La Figura 12 muestra una secuencia completa de dos cambios de contexto. El primero se debe a la pérdida de la CPU del Proceso A en favor de Proceso B, mientras que en el segundo cambio, el Proceso A recupera el procesador. Veamos con cierto detalle un posible algoritmo que realiza este cambio de contexto. No obstante, este grado de detalle dista bastante de ser completo, ya que para ello habría que particularizar las operaciones el cambio de contexto para un procesador concreto y un conjunto dado de Llamadas al Sistema. • Llamada al sistema o interrupción de un dispositivo. En cualquier caso, esto implica automáticamente una copia del REGISTRO DE ESTADO y del CONTADOR DE PROGRAMA a la Pila del proceso en ejecución, al que llamaremos Proceso A. • Se comienza a realizar el servicio solicitado o el tratamiento de la interrupción. 
$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

&DPELR GH 3URFHVR

(O 3ODQLILFDGRU

6HOHFFLRQD HO 6LJXLHQWH 3URFHVR D (MHFXWDU 6HJ~Q OD 3ROtWLFD GH 3ODQLILFDFLyQ

12 (;38/625(6 3 ),)2 3 (O PiV FRUWR HO SULPHUR 3 3ULRULGDGHV

(;38/625(6 3 5RXQG 5RELQ 3 3ULRULGDGHV

£

),1 '( /$ 52'$-$ '( 7,(032

-- Actualizar el final de la cola Preparados. Procesos(Preparados.Ultimo).Siguiente := En_Ejecución; Preparados.Ultimo := En_Ejecución; -- Seleccionar un proceso. Proceso_Seleccionado := Preparados.Primero; -- Actualizar el principio de la cola Preparados. Preparados.Primero := Procesos(Preparados.Primero).Siguiente; -- Cambiar el contexto del procesador. Dispatcher;

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†Ãà 

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

• Se salvan todos los registros del procesador en la Pila del proceso actualmente en ejecución (el A). A excepción del REGISTRO DE ESTADO (RE), CONTADOR DE PROGRAMA (CP) y PUNTERO DE PILA (PP). • Tras decidir que el proceso en ejecución debe abandonar la CPU, el Planificador elige el proceso que pasará a Ejecución, al que nos referiremos como Proceso B. • Se llama al 'LVSDWFKHU y comienza el cambio de contexto. Se producen las siguientes acciones: 1. El Puntero de Pila del proceso A se guarda en su Descriptor de Proceso. 2. Se carga el Puntero de Pila a partir del PP guardado en el Descriptor del Proceso B. Ahora la Pila de trabajo es la del proceso B 3. Se cargan todos los registros generales del procesador a partir de los datos contenidos en la Pila, a excepción del RE, el CP y el PP. 4. El valor que queda en la cima de la Pila es la dirección de vuelta del último punto en el que se llamó al Dispatcher cuando el proceso B perdió el control de la CPU. 5. Se actualiza la variable En_Ejecución con Proceso_Seleccionado. 6. El Dispatcher termina. Al ejecutar la instrucción de RETORNO DE SUBRUTINA, se devuelve el control al punto en el que se había llamado al Dispatcher para que el proceso B perdiese el control del procesador. 7. El sistema operativo termina de realizar el servicio que el Proceso B le había solicitado, por lo que ejecuta la instrucción máquina RETORNO DE INTERRUPCIÓN. Esta instrucción origina que se cargue el REGISTRO DE ESTADO y el CONTADOR DE PROGRAMA con los dos datos que se sacan de la cima de la Pila. 8. Con el nuevo CONTADOR DE PROGRAMA, la instrucción que se ejecuta es la siguiente al punto en el que el proceso B realizó una Llamada al Sistema (lo que supuso su paso a Espera).

Ya hemos visto que el cambio de CPU de un proceso a otro requiere una serie de acciones que se encargan de realizarlas el Planificador y el 'LVSDWFKHU. Pues bien, estas acciones se ejecutan en un tiempo que, desde luego, no es nulo. La elección del proceso a ejecutar suele ser muy simple y no supone una pérdida de tiempo considerable; pero el cambio de contexto sí puede acarrear una gran cantidad de instrucciones, incluidas operaciones de E/S si los contextos de memoria de los procesos que intervienen hay que salvarlos y traerlos, respectivamente, del disco duro, cosa que suele realizarse en los actuales sistemas con Memoria Virtual. No es deseable, en absoluto, que el tiempo dedicado al cambio de proceso sea considerable. Pensemos en un caso exagerado : si el 20% de las instrucciones ejecutadas en la CPU son las dedicadas a realizar el cambio de ejecución de dos procesos, esto quiere decir que a las instrucciones de los programas del usuario 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

8 h € i v‚ Ãq r ÃQ … ‚ p r † ‚

( O ' LV S D W F K H U
(V HO (QFDUJDGR GH &HGHU H O & R Q W U R O G H OD & 3 8 D O 3 U R F H V R 6 H OH F F LR Q D G R S R U H O 3 OD Q L I LF D G R U

6 X V $ F F LR Q H V % i V LF D V 6 R Q 

ž Ÿ   ¡

7 H U P LQ D U G H V D OY D U H O F R Q W H [ W R G H O 3 U R F H V R $ F W X D OP H Q W H H Q ( M H F X F L y Q ( V W D E OH F H U H O 3 X Q W H U R G H 3 LOD G H O 1 X H Y R 3 U R F H V R T X H 3 D V D D ( M H F X F Ly Q 5 H V W D X U D U OR V 5 H J L V W U R V G H OD & 3 8 D 3 D U W L U G H OD 1 X H Y D 3 L OD H [ F H S W R & 3 \ 5 (

57( 

5 HVWDXUD 5 (  5 HVWDXUD & 3

P R G R X V X D U LR

T v† ‡ r € h † ÃP ƒ r … h ‡ v‰ ‚ † ÃD

B r † ‡ vy  Ãq r ÃQ … ‚ p r † ‚ † ÃÃ

solamente se le dedica el 80% del tiempo de CPU, mientras que, claramente, lo más deseable es que se acercara lo más posible al 100%. De la observación anterior se deduce que conviene: - minimizar el número de cambios de proceso, - o minimizar las operaciones del cambio de contexto. Esta conclusión la tendremos presente en los siguientes apartados, en los que vamos a tratar más a fondo las acciones concretas del Dispatcher y algunas de las políticas más comunes de planificación de CPU.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR 

&DPELR GH 3URFHVR
6,67(0$ 23(5$7,92 352&(62 % SUHSDUDGR
6DOYDU 5HJLVWURV 3B$

352&(62 $ HQ HMHFXFLyQ
S int. o all ys_c

HQ HVSHUD 

 

6HOHFFLRQDU 3URFHVR &DUJDU 5HJLVWURV 3B%

HQ HMHFXFLyQ SUHSDUDGR
6DOYDU 5HJLVWURV 3B%
int. o S ys_ca ll 

 

HQ HVSHUD R SUHSDUDGR

6HOHFFLRQDU 3URFHVR &DUJDU 5HJLVWURV 3B$

HQ HMHFXFLyQ

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

! 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV 

3URFHVR 2FLRVR Veamos ahora una situación, a primera vista comprometida, que se puede dar en un sistema multiproceso. Sabemos que cuando un proceso cede voluntariamente el control de la CPU, el Planificador tiene que elegir otro proceso de usuario que esté preparado, pero ¡Qué pasa si no hay ningún proceso Preparado? Si no hay ningún proceso que quiera ejecutar instrucciones ¡qué hace la CPU? Esta situación no solamente es perfectamente posible, sino que se da con mucha frecuencia. En un sistema con cinco usuarios ¿qué impide que en un instante determinado cuatro de los procesos estén esperando una respuesta del disco duro, la llegada de un carácter por una línea de comunicaciones, o que llegue una hora determinada? La respuesta es: nada. Pues si en este momento el proceso del quinto usuario también realiza una petición a un dispositivo de E/S, también pasa a Espera. En este momento el Planificador tendría que seleccionar un proceso de la cola de Preparados, para darle el control, pero ¡ya no hay más procesos! ¿qué va a hacer la CPU mientras todos los procesos están en Espera? Hemos mencionado solamente los procesos de usuario, pero también hay procesos del sistema operativo que pueden estar realizando servicios que se les haya solicitado con anterioridad, por ejemplo, imprimiendo un fichero. De cualquier forma, tampoco hay nada que impida que en un momento dado no haya ningún proceso con necesidad de ejecutar instrucciones. Para estos casos, en todos los sistemas suele haber un proceso del sistema denominado 3URFHVR 2FLRVR. Este proceso consta de un bucle infinito ejecutando un algoritmo muy sencillo (puede ser incluso la instrucción 1R 2SHUDFLyQ) en el que no figura ninguna instrucción que pueda generar un paso a Espera. El proceso ocioso puede estar continuamente realizando estudios estadísticos de utilización del sistema, calculando decimales del numero π, o cualquier trabajo infinito de la menor prioridad. De esta forma, siempre tendremos un proceso Activo. Diremos que la CPU está ociosa cuando esté ejecutando el Proceso Ocioso. Los procesadores suelen disponer de la instrucción HALT (o WAIT), la cual hace que se detenga la ejecución de instrucciones en la CPU, es decir, se deja de extraer instrucciones de la memoria, y la CPU pasa al estado 'HWHQLGR, en el que permanece hasta que se produce una interrupción, pues en ese momento el procesador la atiende y comienza a ejecutar las instrucciones de su rutina de tratamiento. 

3ODQLILFDFLyQ GH 3URFHVRV
Habiendo visto el ciclo de vida de los procesos, sabemos que un proceso que se está ejecutando, eventualmente, por diversos motivos que se han comentado, abandona la posesión del procesador voluntaria o involuntariamente, por lo que hay

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

que cederle la CPU a un proceso que sea lógicamente ejecutable, es decir, que esté Preparado. Si hay más de un proceso Preparado, el sistema operativo debe decidir cuál de ellos se ejecutará primero. La parte del sistema operativo que le corresponde tomar tal decisión es el 3ODQLILFDGRU, que seleccionará un proceso basado en una política o algoritmo de planificación. El estado de Preparado se implementa como una cola de procesos dispuestos a ejecutar instrucciones con ayuda de la CPU. Ahora bien, debemos a aclarar que esta cola no tiene por que ser una cola FIFO (Primero en Entrar, Primero en Salir), también podría ser una cola ordenada por prioridades, un árbol o, simplemente, una lista desordenada. El Planificador debe seleccionar uno de los procesos de la lista, pero no basándose necesariamente en la propia estructura de la lista. La estructura de la lista únicamente debe ayudar al Planificador a aplicar el algoritmo de planificación. 

&ULWHULRV Antes de ver algoritmos concretos de planificación debemos recordar, que la elección que el Planificador va a realizar debe hacerse persiguiendo “el bien del sistema”, pues es uno de los cometidos del sistema operativo. No obstante, distintas políticas de planificación tienen diferentes propiedades, y favorecen más a un tipo de procesos que a otros. Antes de elegir el algoritmo a utilizar en una situación concreta, debemos considerar las propiedades de varios algoritmos. Se han sugerido muchos criterios para comparar algoritmos de planificación de CPU. Decidir las características que se van a utilizar en la comparación es fundamental para la elección del algoritmo más apropiado. Veamos los criterios de comparación más comúnmente utilizados: • -XVWLFLD. Cada proceso debe conseguir su porción correspondiente de CPU en un tiempo finito. • (ILFLHQFLD. Se debe intentar mantener la CPU ocupada el mayor tiempo posible. Al decir “ocupada” queremos decir ejecutando cualquier proceso que no sea el Proceso Ocioso. En un sistema real, el porcentaje de utilización de CPU suele estar en el rango 40-90%. Una utilización mayor del 90% significaría que el Planificador siempre encuentra procesos en la cola Preparados, o sea, que dicha cola suele contener un número considerable de procesos. En un sistema interactivo, esto puede suponer que los usuarios quizás se están impacientando por obtener las respuestas. • 7LHPSR GH 5HWRUQR (WXUQDURXQG WLPH). Desde el punto de vista de un proceso, el criterio más importante es cuánto tiempo se va a necesitar para ejecutarse completamente. El Tiempo de Retorno es la suma de los periodos que se pasan esperando a cargarse en memoria, esperando en la cola de Preparados, ejecutándose en la CPU, y esperando por operaciones de E/S. Así pues, se debe minimizar el tiempo de retorno de un proceso. Afecta principalmente a los procesos EDWFK. • 7LHPSR GH (VSHUD El algoritmo de planificación de CPU no afecta a la cantidad de tiempo que un proceso se pasa realizando operaciones de E/S, solamente 
$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR

3ODQLILFDFLyQ GH 3URFHVRV

(O 3ODQLILFDGRU VH (QFDUJD GH 6HOHFFLRQDU HO 3URFHVR TXH 3DVD D (MHFXFLyQ  \ 'HFLGH 6HJ~Q XQD 3ROtWLFD %DVDGD HQ $OJXQRV &ULWHULRV -XVWLFLD (ILFLHQFLD 7LHPSR GH 5HWRUQR 7LHPSR GH 5HVSXHVWD 7LHPSR GH (VSHUD 5HQGLPLHQWR

3ROtWLFDV GH 3ODQLILFDFLyQ

1R ([SXOVRUDV EDWFK

([SXOVRUDV PXOWLXVXDULR \ WLHPSR UHDO

3 (O 3ULPHUR HQ /OHJDU 3 (O 0iV &RUWR 3ULPHUR 3 3RU 3ULRULGDGHV

3 7LHPSR &RPSDUWLGR 5RXQG 5RELQ 3 3RU 3ULRULGDGHV 3 0~OWLSOHV &RODV 3 0~OWLSOHV &RODV 5HDOLPHQWDGDV

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

"

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

afecta al tiempo que un proceso se pasa en la cola Preparados. El Tiempo de Espera es la suma de todos los momentos que un proceso pasa en la cola de los procesos preparados. • 7LHPSR GH 5HVSXHVWD. En un sistema interactivo, el Tiempo de Retorno puede no ser un buen criterio. A menudo, un proceso puede producir algunos resultados al principio, y puede continuar calculando nuevos resultados mientras los anteriores se le muestran al usuario. Así, tenemos que otra medida es el tiempo que transcurre desde que se le hace una petición al sistema hasta que empieza a responder, sin tener en cuenta el tiempo que se tarda en mostrar la respuesta completa. • 5HQGLPLHQWR. Se debe maximizar el número de trabajos procesados por unidad de tiempo. Es deseable maximizar la utilización de la CPU y minimizar los tiempos de retorno, de espera y de respuesta, todo ello con la mayor justicia para todos los procesos. Sin embargo, es fácil observar que algunos de estos criterios son contradictorios. Por ejemplo, para que en los procesos interactivos el tiempo de respuesta sea bueno, se puede impedir que se ejecuten procesos batch por el día, reservando para éstos las horas nocturnas en las que no suele haber usuarios en los terminales. Esto no les sentará muy bien a los usuarios que han encargado trabajos en batch, pues ven que el tiempo de retorno se incrementa. Como en otros aspectos de la vida, lo que beneficia a unos, perjudica a otros; así que, en cualquier caso, no habrá que olvidarse nunca del criterio que hace referencia a la justicia. En pro de la justicia, en la mayoría de los casos se suelen optimizar los valores medios, no obstante, bajo algunas circunstancias, es deseable optimizar los mínimos o los máximos valores, en lugar de la media. Por ejemplo, para garantizar que todos los usuarios obtienen un buen servicio, lo que se desea es minimizar el tiempo máximo de respuesta. También se ha sugerido que, en los sistemas interactivos, es más importante minimizar la varianza en el tiempo de respuesta, que minimizar su valor medio. Es preferible un sistema con un tiempo de respuesta razonable y predecible, que otro que aunque por término medio resulte más rápido, sea altamente variable. 

3ROtWLFDV GH 3ODQLILFDFLyQ En los diagramas de estados de los procesos, vimos que cuando un proceso en Ejecución abandona tal estado pasa a Espera o a Preparado, dependiendo si deja el procesador voluntaria o involuntariamente. Si los procesos de un sistema nunca dejan la CPU de forma involuntaria, se dice que la política de planificación de CPU es QR H[SXOVRUD o no expropiativa (QRQ SUHHPSWLYH VFKHGXOLQJ). Por el contrario, si pueden perder la posesión del procesador sin solicitarlo, nos encontramos con una planificación H[SXOVRUD o expropiativa (SUHHPSWLYH VFKHGXOLQJ). 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

Las políticas no expulsoras suelen aplicarse en sistemas batch o en pequeños entornos monousuario, como el sistema operativo MS-DOS o el entorno Windows-95/98, ambos de Microsoft. Algunos algoritmos que se emplean en esta planificación son SULPHUR HQ OOHJDU  SULPHUR HQ VHUYLU, HO PiV FRUWR SULPHUR, y SRU SULRULGDGHV. Por otra parte, los algoritmos expropiativos se utilizan en sistemas de control industrial y entornos multiusuario. Los algoritmos más utilizados aquí incluyen 5RXQG5RELQ, SRU SULRULGDGHV, de P~OWLSOHV FRODV y de P~OWLSOHV FRODV UHDOLPHQWDGDV (como es el caso de Unix y Windows/NT). Veamos a continuación algunos comentarios sobre estos algoritmos. • 3ULPHUR HQ OOHJDU  3ULPHUR HQ VHUYLU Este algoritmo, cuyo nombre abreviaremos con FCFS ()LUVW &RPH  )LUVW 6HUYHG), es, con mucho, el algoritmo más simple. Según este esquema, el primer proceso que reclama la CPU, es el primero en conseguirla. En cuanto a la implementación, no merece la pena dar muchas explicaciones, pues basta con mantener, por ejemplo, una cola FIFO de los descriptores de los procesos que van solicitando la CPU. El tiempo medio de espera es muy variable y raramente es el mínimo. En el gráfico superior de la Figura 14 se muestra un caso que según ese orden de llegada, resulta un tiempo medio de espera de 17 ms. En cambio, si el orden de llegada de los trabajos o procesos hubiera sido T2, T3, T1, se puede comprobar que habría dado lugar a un tiempo medio de espera de 3 ms. Otro problema que puede aparecer al aplicar este algoritmo se da en el siguiente escenario. Supongamos un sistema con esta política FCFS en el que hay un proceso (Proceso-CPU) que consume grandes porciones de CPU y realiza pocas operaciones de E/S. Por el contrario, hay muchos otros procesos con un ciclo en el que realizan frecuentes operaciones de E/S y ejecutan muy pocas instrucciones sobre la CPU (Procesos-E/S). Mientras el Proceso-CPU se ejecuta, los Procesos-E/S acabarán sus operaciones con los dispositivos periféricos y pasarán a la cola Preparados, quedando libres los dispositivos de E/S. En algún momento, el Proceso-CPU acabará por realizar una operación de E/S y pasará a Espera. Los Procesos-E/S, que necesitan poca CPU se ejecutan rápidamente y vuelven a las colas de espera de los periféricos de E/S. La CPU queda ociosa. El Proceso-CPU finaliza la operación de E/S y vuelve a tomar control del procesador. Otra vez, los Procesos-E/S terminarán sus operaciones de E/S y pasarán a Preparados, esperando todos a que el Proceso-CPU realice otra operación de E/S. Cuando se produce esta situación, en la que muchos procesos que necesitan poca CPU esperan por uno que consume mucho tiempo de procesador, se denomina HIHFWR FRQYR\. Este efecto provoca una menor utilización de la CPU y de los periféricos de la que se podría conseguir si se concediese la posesión de la CPU a los procesos que requieren poco tiempo de procesador, en lugar de cedérselo a un proceso que va a hacer esperar mucho tiempo a muchos procesos.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR

3ROtWLFDV GH 3ODQLILFDFLyQ

(O 3ULPHUR HQ /OHJDU 3ULPHUR HQ 6HUYLU
J (V VLPSOH L 7LHPSR GH HVSHUD YDULDEOH 5DUDPHQWH HO PtQLPR L 'HVDSURYHFKD ORV GLVSRVLWLYRV GH (6
7UDEDMR    7LHPSR QHFHVDULR   

7UDEDMR  


7U  7U  


7LHPSR PHGLR GH HVSHUD 

  

(O 0iV &RUWR HO 3ULPHUR
J 2IUHFH VLHPSUH HO PtQLPR WLHPSR PHGLR GH HVSHUD
7UDEDMR    7LHPSR QHFHVDULR   

7U  


7U  

7UDEDMR  

7LHPSR PHGLR GH HVSHUD 

  

J (V ySWLPR L ¢&XiO HV OD QHFHVLGDG UHDO GHO WUDEDMR" 0iV XWLOL]DGR HQ OD SODQLILFDFLyQ D ODUJR SOD]R
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD Br†‡vyÃqrÃQ…‚pr†‚†Ãà # 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

(O PiV FRUWR SULPHUR Este algoritmo, también conocido como SJF (6KRUWHVW -RE )LUVW), concede la CPU al proceso que durante menos tiempo necesita la CPU de forma ininterrumpida. Debe quedar claro que se selecciona el que menor porción de tiempo de CPU necesita en el momento de hacer la elección, no aquel cuyo tiempo total de CPU es el menor de todos. Si dos procesos necesitan el procesador durante el mismo tiempo, se elige uno mediante FCFS. En la parte inferior de la Figura 14 tenemos la aplicación de este algoritmo a nuestro ejemplo. Como se puede ver, consigue el menor tiempo de espera posible. Poniendo a un proceso corto por delante de uno largo, se decrementa el tiempo de espera del corto más de lo que se incrementa el del largo. Consecuentemente, el tiempo medio decrece. Este algoritmo, probablemente el óptimo, se comporta bien en la planificación a largo plazo de los procesos batch, en los que se conocen los requisitos de tiempo total de CPU indicados por el usuario; pero en la planificación de la CPU se presenta el problema de que en el momento en que hay que asignar la CPU, no hay forma de conocer a priori la porción de tiempo que necesita cada proceso, por lo que es difícilmente implementable. Se puede intentar una aproximación al SJF puro, haciendo una estimación de la porción necesaria basándose en estadísticas de ejecuciones anteriores.

• 5RXQG  5RELQ Este algoritmo está especialmente diseñado para los sistemas multiusuario de tiempo compartido. Es similar al FCFS, pero se le añade la expropiación de la CPU cuando la posesión continuada de ésta sobrepasa un tiempo preestablecido (SRUFLyQ GH WLHPSR), que suele ser del orden de 10 a 100 milisegundos. La implementación de este algoritmo se realiza con una cola FIFO para los procesos Preparados. Los nuevos procesos se añaden al final de la cola. Cuando el planificador tiene que seleccionar un proceso, elige el primero de la cola, establece una temporización correspondiente a la porción de tiempo, y le cede el control. Ahora pueden ocurrir dos cosas: 1ª) El proceso termina o realiza una operación de E/S antes de que se acabe su porción de tiempo, en cuyo caso cede la CPU voluntariamente, pasa a espera y el planificador selecciona el siguiente proceso de la cola Preparados. 2ª) El proceso se ejecuta hasta dar lugar a que venza la temporización establecida. En este caso, el dispositivo temporizador genera una interrupción que captura el sistema operativo, dando lugar a que se le expropie la CPU al proceso en ejecución, que pasa al final de la cola Preparados, y a que el planificador seleccione al primer proceso de la cola para pasar a ejecución. Ya habíamos comentado anteriormente la falta de eficiencia que pueden causar los cambios continuos del proceso en ejecución. En el caso de que la política de planificación del procesador sea por Prioridades de los procesos, se nos hace imposible establecer la frecuencia de los cambios, pues vendrá impuesta por los

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6LVWHPDV 0XOWLSURFHVR 

3ROtWLFDV GH 3ODQLILFDFLyQ

7LHPSR &RPSDUWLGR 5RXQG 5RELQ
3URFHVR  3URFHVR  3URFHVR 

3URFHVR HQ HMHFXFLyQ 3URFHVR HQ HVSHUD
7UDEDMR    7LHPSR QHFHVDULR    7U  

7U  7U  7U  7U  
  

7U  

7U  


(O 5HQGLPLHQWR GHO 6LVWHPD 'HSHQGH GH OD 3RUFLyQ GH 7LHPSR

3HTXHxD

*UDQGH )&)6

£

6ROR KD\ FDPELRV GH FRQWH[WR

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

$ 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

fenómenos externos que afectan a los procesos correspondientes. En cambio, si la planificación es por Tiempo Compartido, sí está en nuestra mano establecer porciones de tiempo de CPU muy grandes, tal que en una unidad de tiempo se produzcan muy pocos cambios del proceso en ejecución. Sin embargo, esto no resulta tan fácil de decidir, pues si la porción de tiempo se hace muy grande, el aprovechamiento de la CPU por parte del usuario se ve altamente incrementada, pero, por contra, también ocurrirá que los usuarios de los terminales notarán que “se les tarda mucho en atender”, pues se ha degenerado en una política FCFS. Por el contrario, si la porción se hace muy pequeña, se les atiende enseguida, pero durante muy poco tiempo, con la consiguiente degradación en el aprovechamiento de la CPU por parte del usuario. • 3RU 3ULRULGDGHV Uno de los factores a tener en cuenta en la planificación de los procesos es la justicia, pero justicia no siempre significa un reparto a partes iguales, sino la asignación más conveniente que aconsejen las circunstancias. Así, por ejemplo, tenemos que en un programa de control y supervisión de una central nuclear, compuesto por diversos procesos, no se debe esperar que todos los procesos cuenten inexcusablemente con la misma porción de tiempo de CPU, ni según un turno circular. Evidentemente, no es tan importante el proceso interactivo que se encarga de mostrar a los visitantes un vídeo de la historia de la central y responder a sus preguntas, como los procesos encargados de supervisar los niveles de presión, temperatura, radioactividad, etc., y que en caso de que se sobrepasen los límites de seguridad activan las válvulas y avisos correspondientes. Los criterios para establecer las prioridades pueden ser variados: por razones físicas, como en el caso de los sistemas de tiempo real, por rangos o categorías de los usuarios (sistemas multiusuarios), por factores políticos, etc. En sistemas multiusuario, es muy común tener prioridades por grupos de trabajo o departamentos, y a los procesos de la misma prioridad aplicarles una política reparto de tiempo compartido. Este algoritmo puede ser H[SXOVRU o QR H[SXOVRU. Cuando un proceso llega a la cola Preparados, se compara su prioridad con la del proceso en ejecución. Con un algoritmo expulsor por prioridades, si la prioridad del recién llegado es mayor que la del proceso en ejecución, se le expropia la CPU a este último en favor del recién llegado. Si la política es no expulsora, simplemente se coloca al nuevo proceso a la cabeza de la cola. El algoritmo SJF es un caso particular de este algoritmo con política no expulsora, donde la prioridad es la inversa del tiempo requerido de CPU. Un problema que se puede dar con este tipo de algoritmos de planificación es el bloqueo indefinido o LQDQLFLyQ. Un proceso que está preparado, pero que no adquiere la CPU, se puede decir que está bloqueado en espera de procesador. Pues bien, con un algoritmo por prioridades puede darse el caso de dejar a un proceso de baja prioridad esperando indefinidamente por el procesador si siempre hay algún proceso de alta prioridad que puede “colarse”. (Existe el rumor de que cuando en 1973 se paro el sistema IBM 7094 del Instituto Tecnológico de

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Massachusetts para sustituirlo por otro, se encontró un proceso que llevaba en espera de CPU desde que se había creado en 1967 y todavía no había podido llegar a ejecutarse por primera vez.) Una primera aproximación al problema de la inanición en sistemas con prioridades, puede consistir en repartir la CPU entre los procesos de la misma prioridad, es decir, tener una política de tiempo compartido dentro de cada cola de prioridad. Una técnica más refinada es la del HQYHMHFLPLHQWR. Con esta sistema, la prioridad de los procesos preparados se incrementa gradualmente a medida que esperan en la cola Preparados, donde permanecen hasta alcanzar, inevitablemente, la prioridad necesaria para conseguir la CPU.

T v† ‡ r € h † ÃH ˆ y‡ vƒ … ‚ p r † ‚ 

3 R OtW L F D V G H 3 OD Q L I L F D F Ly Q

3 U L R U LG D G H V H [ S X OV R U D V
+ / R V 3 U R F H V R V 7 L H Q H Q 3 U L R U LG D G H V 7 R P D H O & R Q W U R O G H OD & 3 8 L Q P H G L D W D P H Q W H H O 3 U R F H V R G H 0 D \ R U 3 U L R U LG D G 

$ 3/,&$ &,2 1 (6

* UXSRV GH 3HUVRQDV F D W H J R U tD V

7 LH P S R 5 H D O

£

& X L G D G R F R Q OD , Q D Q L F Ly Q 6 2 /8 &,2 1 (6

3 5 R X Q G 5 R E LQ S R U S U L R U LG D G H V 3 3 U LR U L G D G H V G LQ i P L F D V

´ ( Q Y H M H F LP LH Q W R µ

T v† ‡ r € h † ÃP ƒ r … h ‡ v‰ ‚ † ÃD

B r † ‡ vy  Ãq r ÃQ … ‚ p r † ‚ † ÃÃ

% 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

0~OWLSOHV FRODV Existe otro tipo de algoritmos para situaciones en las que los procesos están claramente clasificados en diferentes grupos. Por ejemplo, una división muy común es la que se hace entre procesos interactivos de primer plano (IRUHJURXQG) y los procesos batch que suelen ejecutarse en un segundo plano (EDFNJURXQG). Estos dos tipos de procesos tiene distintos requisitos en sus tiempos de respuesta, por lo que podrían tener distintos algoritmos de planificación cada uno. Además, los procesos interactivos podrían tener mayor prioridad que los se ejecutan en un segundo plano. Para esto, la cola Preparados podría estar dividida en varias colas separadas, una por cada tipo de proceso. Cada proceso siempre se encola en su cola correspondiente. Así nos encontramos con que para elegir la cola de la que se va a sacar un proceso se utiliza una política, mientras que para seleccionar qué proceso se va a sacar de la cola elegida, se utiliza un algoritmo distinto. También puede ocurrir que en dos colas distintas se utilice la misma política de planificación, por ejemplo, tiempo compartido, pero que la porción de tiempo sea distinta en una cola que en otra.

• 0~OWLSOHV FRODV UHDOLPHQWDGDV Una mezcla de las técnicas de envejecimiento y de las múltiples colas, resulta en las múltiples colas realimentadas. Las distintas colas pueden tener políticas de tiempo compartido, pero las más prioritarias poseen una mayor porción de tiempo. Cuando un proceso lleva mucho tiempo en una cola de poca prioridad, se le pasa a otra cola de mayor prioridad, consiguiendo así mayores porciones de tiempo. 

3ODQLILFDFLyQ HQ 6LVWHPDV 0XOWLSURFHVDGRU Hasta ahora hemos tratado con algoritmos de asignación de CPU en sistemas con un solo procesador. Si se dispone de múltiples procesadores, la planificación se vuelve bastante más compleja. Al igual que en el caso de los sistemas monoprocesador, no existe la solución óptima, sino que ésta depende de varios factores, y siempre hay unos procesos beneficiados y otros perjudicados. Vamos a tratar simplemente algunos conceptos generales sobre la planificación de múltiples CPU’s. Un estudio en profundidad de este apartado puede encontrarse en literatura sobre arquitecturas avanzadas y paralelas. Cuando todos los procesadores de un sistema tienen la misma funcionalidad (VLVWHPD KRPRJpQHR), cualquier procesador disponible puede utilizarse para ejecutar un proceso preparado. Pero si los procesadores son distintos (VLVWHPD KHWHURJpQHR), sólo los programas compilados para un procesador determinado pueden ejecutarse en ese procesador. Este es el caso de los sistemas distribuidos.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

3ODQLILFDFLyQ

&RQ 0~OWLSOHV 3URFHVDGRUHV
/RV SURFHVDGRUHV SXHGHQ VHU

',)(5(17(6 6LVWHPD +HWHURJpQHR &DGD SURFHVDGRU WLHQH VX SURSLD FROD \ VX SURSLD SODQLILFDFLyQ &DGD SURFHVR VH DVLJQD DO WLSR GH SURFHVDGRU TXH OH FRUUHVSRQGH

,*8$/(6 6LVWHPD +RPRJpQHR ¢9DULDV FRODV" L £ &DUJD GHVHTXLOLEUDGD

'HEH KDEHU XQD ~QLFD FROD GH SURFHVRV

$XWRSODQLILFDFLyQ 8Q SURFHVDGRU OLEUH VDFD XQ SURFHVR GH OD FROD £ &8,'$'2

8Q SURFHVDGRU KDFH GH 3ODQLILFDGRU \ UHSDUWH ORV SURFHVRV HQWUH ORV SURFHVDGRUHV

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

& 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

También puede haber algunas limitaciones en la asignación de CPU en los sistemas homogéneos, como es el caso de un programa que haga uso de un dispositivo especial de E/S conectado a un bus privado de un procesador concreto, en cuyo caso solamente se le puede asignar tal CPU para ejecutarse. En el caso de los sistemas heterogéneos, cada procesador dispone de su propia cola Preparados y de su planificación particular, y cada proceso entra en la cola del procesador que le corresponde. En los sistemas homogéneos se podrían tener también varias colas, una por procesador, pero esto podría dar lugar a una carga desequilibrada, con algunas colas con muchos procesos, y otras colas vacías con su CPU ociosa. Para evitar esto, suele ser mejor disponer de una única cola de procesos preparados. Hay dos métodos para sacar los procesos de la cola. • Uno es mediante DXWRSODQLILFDFLyQ, en el que cada procesador que queda libre saca un proceso de la cola. En este método hay que controlar la posibilidad de que dos procesadores intenten sacar simultáneamente al mismo proceso de la cola. • El otro sistema es dedicando un procesador a trabajar como planificador, siendo él el único que saca procesos de la cola y los asigna entre los procesadores, evitando así los conflictos del método anterior. 

/D 3ODQLILFDFLyQ GH $OJXQRV 6LVWHPDV 2SHUDWLYRV Aunque los conceptos de sistemas operativos pueden estudiarse o considerarse en términos puramente teóricos, resulta conveniente observar cómo se han implementado algunos sistemas operativos comerciales. Así, ahora vamos a comentar, aunque solo sea superficialmente, algunas de las decisiones de diseño que se han tomado sobre la planificación de la CPU en Unix, Linux y Windows NT.

8QL[
La primera versión de Unix se desarrolló en 1969 por Ken Thompson en los Laboratorios Bell. Muchas versiones y emulaciones se han hecho desde entonces. Una de las últimas versiones de Unix es la 6\VWHP 9 UHOHDVH , aparecida en 1989. No obstante, muchos otros fabricantes también han desarrollado sus propias versiones de este popular sistema operativo. Así tenemos las versiones de IBM (AIX), HP (HP-UX), Sun (Sun OS y Solaris), DEC (Ultrix) y algunas más. También se han desarrollado versiones para PC’s, como la de Microsoft (Xenix), la de Santa Cruz y la de Tanenbaum (Minix), y para las más variadas plataformas, desde el Macintosh de Apple hasta supercomputadores como el Cray II. Una de las versiones de Unix más populares ha sido la desarrollada en la Universidad de Berkeley por el Departamento de Defensa norteamericano para
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

utilizarlo en instalaciones gubernamentales. Esta versión fue la 4BSD, siendo concretamente la 4.3BSD (año 1986) una de las que tuvieron más auge de utilización. También merece especial mención Linux, que desde mediados de los años 90 ha tenido una espectacular difusión, y al que le trataremos en un apartado particular. Ahora vamos a comentar aquí la política de planificación del procesador utilizada por Unix en su versión 4.3BSD. Ya que se trata de un sistema operativo multiusuario, la planificación de Unix está diseñada para favorecer a los procesos interactivos, para lo cual utiliza una planificación por prioridades, cediendo la CPU en porciones de tiempo al proceso más prioritario. El algoritmo concreto es el de “colas multinivel con realimentación (mediante envejecimiento)”, de tal manera que para procesos con gran carga de CPU el algoritmo de planificación se convierte en URXQGURELQ. Veámoslo con cierto detalle. Las porciones de tiempo son de 100 ms., por lo que cuando un proceso llega al término de su porción sin haber cedido la CPU, se le quita la CPU para cedérsela al proceso preparado con mayor prioridad. Las prioridades, no obstante, son dinámicas, es decir, que la prioridad de un proceso va variando a lo largo de su vida. Aunque las porciones de tiempo son de 100 ms. la reevaluación de las prioridades se realiza una vez por segundo, para que no suponga una sobrecarga considerable. Esto quiere decir que cada segundo se aplica el algoritmo que establece la prioridad de cada proceso. El algoritmo en cuestión es el siguiente: 3 (L) = %DVH +
M M

&38 (L − 1)
M

2
M

+ QLFH

M

&38 =
M

8 (L)
M

2

+

&38 (L − 1) 2

donde 3 L
M

Prioridad del proceso M al comienzo del intervalo L. Cuanto menor sea este número, mayor es la prioridad.
M

%DVH

Prioridad de base del proceso M.

&38 L = Media ponderada exponencial de la utilización de CPU del proceso M en el intervalo L.
M

8M L QLFH
M

= Utilización de CPU del proceso M en el intervalo L. = Factor de ajuste controlado por el usuario. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

El propósito de la prioridad base es establecer bandas fijas de prioridades, de tal manera que a los distintos tipos de procesos se les asigna una prioridad base predeterminada. Las bandas son, en orden de prioridad decreciente, para los siguientes tipos de procesos: • • • • • Procesos de intercambio a disco Procesos de dispositivos de E/S por bloques Procesos de gestión de archivos Procesos de dispositivos de E/S de caracteres Procesos de usuario

Prioridad

Esta jerarquía tiende a proporcionar un aprovechamiento más eficiente de los dispositivos de E/S. Obsérvese que dentro de los procesos de usuario, también se tiende a penalizar a los procesos que consumen mucha CPU, pues cuanto más procesador consume un proceso, menor se hace su prioridad, lo cual termina favoreciendo a los procesos que más utilizan los dispositivos de E/S. Esto tiende a evitar el “efecto convoy” comentado en la planificación FIFO. También debemos observar que ya que se tiene en cuenta (y se penaliza) el consumo de CPU que ha realizado cada proceso en su anterior posesión del procesador, este algoritmo también se comporta como una aproximación a “el más corto - el primero”, el cual ya vimos que ofrece los mejores tiempos medios de espera. Ya que a todos los procesos de usuario se les asigna la misma prioridad base, para este tipo de procesos el algoritmo se comporta como si fuera 5RXQG5RELQ (aunque como ya hemos dicho, favoreciendo a los procesos con poca carga de CPU), no obstante, se puede favorecer en cierta manera a algunos procesos de usuario mediante el comando nice. Debido a este algoritmo con envejecimiento, resulta muy difícil que un proceso pueda apropiarse de forma exclusiva de la CPU evitando así la “inanición” de los procesos.

/LQX[
Linux es otro sistema operativo “tipo Unix” en el que aunque la compatibilidad con Unix era uno de los objetivos de diseño, tiene algunas particularidades que difieren del Unix estándar, entre ellas la política de planificación de procesos, y dada la popularidad que ha adquirido en estos últimos años, merece la pena comentarlo. El desarrollo de Linux comenzó en 1991, cuando el estudiante finlandés Linus Torvalds escribió un pequeño kernel o núcleo para el procesador 80386 de Intel y lo puso a disposición de todo el mundo de forma gratuita a través de Internet. Este núcleo implementaba un subconjunto de la funcionalidad de Unix, pero fue creciendo hasta adquirir la funcionalidad completa. Alrededor del único NHUQHO GH /LQX[ se han construido multitud de programas que constituyen el VLVWHPD /LQX[. Alguno de estos programas se ha construido

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

expresamente para Linux, mientras que otros se han tomado prestados de otros sistemas o proyectos de colaboración. Una GLVWULEXFLyQ GH /LQX[ consta de los componentes estándar de un sistema Linux, más un conjunto de herramientas de administración que ayudan a simplificar la instalación y mantenimiento del sistema. Aunque la primera distribución de Linux fue la de SLS y la de Slackware posiblemente la más popular, hoy día hay numerosas distribuciones, entre ellas: Red Hat, Debian, Caldera, Craftworks, SuSE, Unifix, etc. No obstante, debe tenerse en cuenta que todas ellas comparten el mismo kernel, y los paquetes o utilidades que ofrece cada una suelen ser compatibles con las demás distribuciones. En este apartado vamos a centrarnos en los aspectos de planificación del kernel de Linux en su versión 2.0. Aunque este sistema operativo está preparado para sistemas multiprocesador, aquí vamos a comentar únicamente la planificación con un único procesador. Linux dispone de dos algoritmos de planificación (dos clases de planificación). Uno es el de tiempo compartido, para un reparto justo entre múltiples procesos; el otro está diseñado para tareas de tiempo real, donde las prioridades son más importantes que la justicia. Cada proceso puede acogerse a cualquiera de estas políticas de planificación, y así consta en su BCP. Para los procesos de tiempo compartido, se utiliza un algoritmo basado en créditos. Cada proceso dispone de un cierto número de créditos, de tal manera que para seleccionar la siguiente tarea a ejecutarse, se elige a la que tiene más créditos acumulados. Cada vez que se produce una interrupción de reloj, el proceso en ejecución pierde un crédito; cuando su número de créditos llega a cero, pierde la CPU y se selecciona otro proceso. Cuando no queda ningún proceso preparado con créditos, Linux vuelve a asignar créditos a todos los procesos del sistema según la regla siguiente:
&UpGLWRV = FUpGLWRV UHVWDQWHV + SULRULGDG 2

Este algoritmo considera dos factores: la historia del proceso y su prioridad. Se mantiene la mitad de los créditos de los que el proceso conserva desde la última asignación de créditos, recordando así parte de la historia del comportamiento más reciente del proceso. Los procesos con mucha carga de CPU tienden a gastar sus créditos rápidamente, mientras que los que suelen estar suspendidos en espera de operaciones de E/S van acumulando créditos a lo largo de la historia, de tal manera que cuando estén en espera de la CPU tendrán más prioridad para ejecutarse, lo cual produce un tiempo de respuesta muy rápido para los procesos interactivos. El factor prioridad en el cálculo de la asignación de créditos permite afinar la prioridad real de los procesos. Al asignar una baja prioridad a algunos procesos en EDFNJURXQG, automáticamente recibirán menos créditos que los procesos 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

interactivos, y también recibirán un menor porcentaje de CPU que trabajos similares a los que se les haya asignado una mayor prioridad. Gracias a este sistema de prioridades dinámicas, procesos de distintas prioridades pueden competir por el procesador, evitando así el problema de la inanición. Para tiempo real, Linux implementa los dos algoritmos expulsores o expropiativos requeridos por POSIX: ),)2 y 5RXQG 5RELQ. Esto quiere decir que la información de cada proceso debe indicar si se acoge a planificación de tiempo compartido o de tiempo real, y en caso de ser este último, debe especificar si utiliza el algoritmo ),)2 o 5RXQG 5RELQ. Veamos cómo se comporta la planificación con cada uno de estos dos algoritmos de tiempo real. El algoritmo FIFO es el ya conocido para tiempo real, en el que la CPU siempre se le concede al proceso con mayor prioridad, y no se le quita a no ser que pase a preparado un proceso de mayor prioridad. En cambio, los procesos de la misma prioridad con planificación 5RXQG 5RELQ, se reparten la CPU en idénticas porciones de tiempo por turno rotatorio. Cuando se le solicita al planificador que elija un proceso para pasar a ejecución, busca en la cola de los preparados, eligiendo siempre a un proceso de tiempo real antes que a los de tiempo compartido. Cuando finaliza una rodaja de tiempo, se comprueba la política de planificación del proceso en ejecución. Si es de tiempo compartido se decrementa un crédito, y si ha llegado a cero, se le quita la CPU, cediéndosela al proceso preparado con más créditos. Si es GH WLHPSR UHDO ),)2 FRQWLQ~D FRQ OD HMHFXFLyQ 6L HV GH WLHPSR UHDO FRQ 5RXQG Robin y no hay más procesos preparados de la misma prioridad, continua la ejecución, pero si hay otros procesos preparados de la misma prioridad, se le quita la CPU, se le envía a la cola de preparados, y se le asigna la CPU al siguiente proceso preparado de esa prioridad. Ya que la planificación, en cualquier caso, es expulsora, si un proceso pasa a preparado y es de mayor prioridad que el actual proceso en ejecución, se le asigna la CPU inmediatamente al proceso de mayor prioridad.

:LQGRZV 17
Este sistema operativo nació como consecuencia de que Microsoft decidió construir un nuevo sistema operativo partiendo de cero y con una Nueva Tecnología, que soportara las aplicaciones tanto para OS/2 como para POSIX, Windows y MS-DOS. Hay dos versiones de Windows NT: ZRUNVWDWLRQ (puesto de trabajo para un usuario) y VHUYHU (utilizado como servidor para aplicaciones cliente-servidor), sin embargo ambas utilizan el mismo núcleo, por lo que las características de planificación que comentaremos aquí se aplican a las dos versiones. Aunque Windows NT dispone de un sistema de protección para múltiples usuarios, no debe entenderse como un sistema multiusuario, pues no permite múltiples
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

usuarios conectados simultáneamente (aunque sí permita múltiples accesos simultáneos como servidor). La arquitectura de Windows NT está basada en un PLFURNHUQHO (como Mach), de tal forma que facilita las actualizaciones de partes del sistema operativo sin afectar al resto. Y como es típico en los sistemas basados en PLFURNHUQHOV, dispone de procesos o tareas y de procesos ligeros o WKUHDGV. Las notas sobre planificación que vamos a comentar se aplican tanto a los procesos como a los WKUHDGV de Windows NT en su versión 4.0 Los objetivos de planificación de Windows NT son diferentes a los de Unix. Éste está pensado para dar servicio equitativo y rápido a todos los usuarios del sistema, mientras que Windows NT se diseñó para ser especialmente sensible a las necesidades de un único usuario en un entorno muy interactivo o en el papel de un servidor. El planificador utiliza un esquema de 32 prioridades para determinar el orden de ejecución. Las prioridades están divididas en dos clases: la FODVH YDULDEOH (con las prioridades 0 a 15) y la FODVH GH WLHPSR UHDO (con las prioridades 16 a 31). Un número más alto indica una mayor prioridad. Cuando se crea un proceso se le asigna una “prioridad base”. Las prioridades de la clase variable se suelen utilizar para los procesos de usuario, mientras que las de tiempo real se reservan para las actividades derivadas del servidor. Se utiliza una cola para cada una de estas prioridades, de tal manera que para elegir el siguiente proceso que pasa a ejecución, se recorren todas las colas, de mayor a menor prioridad hasta que se encuentra un proceso preparado. Si no hay ningún proceso preparado, se le cede el control al WKUHDG RFLRVR. La CPU siempre se asigna al proceso de mayor prioridad, aunque las prioridades se gestionan de forma diferente en las dos clases. En la clase de tiempo real todos los procesos mantienen su prioridad base, que no cambia nunca, y la CPU se reparte por turno rotatorio entre todos los procesos de la máxima prioridad que tenga procesos preparados. En la clase de prioridad variable, la prioridad de un proceso parte de su prioridad base y puede subir o bajar (dentro de un cierto margen) a lo largo de la vida del proceso. Así, por cada nivel de prioridad hay una cola FIFO, pero un proceso puede pasar a la cola de otra prioridad dentro de las de prioridad variable. La prioridad de un proceso no puede cambiar a la prioridad de otra clase distinta a la que pertenece. Cuando a un proceso en ejecución se le acaba su porción de tiempo, si pertenece a la clase de tiempo real y hay más procesos preparados de la misma prioridad, se le quita la CPU y pasa al final de la cola de su prioridad, cediendo la CPU al siguiente proceso de esa cola. Si la prioridad del proceso pertenece a la clase variable, se le disminuye la prioridad (hasta cierto límite). De esta manera se tiende a limitar el alto consumo de CPU que realizan los procesos de cálculo (con poca E/S); por otra parte, cuando un proceso que estaba en espera pasa a preparado, se le aumenta su prioridad. Este aumento depende del motivo por el que estaba esperando. Los procesos que esperan por una interrupción de teclado o de ratón son los que 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

consiguen un mayor aumento de prioridad, mientras que los que esperan por la conclusión de una operación con el disco sólo consiguen un ligero aumento. Esta estrategia tiende a ofrecer un buen tiempo de respuesta a los procesos interactivos elevando la prioridad a los procesos que esperan por teclado o ratón, dejando que los procesos con gran carga de procesador se ejecuten en tiempos muertos en segundo plano. Aunque esta planificación expulsora siempre le otorga el procesador al proceso preparado con mayor prioridad, no se puede decir que Windows NT sea un sistema operativo de tiempo real estricto, pues no garantiza el tiempo mínimo que se tarda en darle control a un proceso de alta prioridad que pasa a preparado. 3ODQLILFDFLyQ HQ 6LVWHPDV 0XOWLSURFHVDGRUHV Cuando Windows NT se ejecuta con un único procesador, el proceso preparado de mayor prioridad siempre está en ejecución, y si hay más de un proceso con la mayor prioridad, la CPU se reparte por turno rotatorio entre todos los procesos preparados de esa prioridad. En un sistema multiprocesador con 1 procesadores, siempre se mantiene en ejecución a los 1 procesos de mayor prioridad, ejecutándose de manera exclusiva en los 1 procesadores. El resto de los procesos de menor prioridad comparten el único procesador que queda.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV 

&RPXQLFDFLyQ \ 6LQFURQL]DFLyQ HQWUH 3URFHVRV
Normalmente, los procesos que cooperan en la realización de un trabajo, necesitarán durante su ciclo de vida la sincronización o comunicación entre ellos o con el proceso maestro que les haya creado. Se hace necesario algún sistema de comunicación cuando se requiere el intercambio de información entre dos o más procesos. Por ejemplo, un proceso puede estar produciendo una serie de datos que sirven a su vez de entrada a otro proceso (como ocurre con el SLSH “|” de Unix). En otros casos, como en los momentos en que se accede a estructuras de datos comunes a varios procesos, se requiere algún mecanismo de sincronización para que dos procesos no intenten acceder simultáneamente a dicha estructura para realizar operaciones de lectura/escritura de forma incontrolada. Así pues, en los siguientes apartados trataremos los problemas que pueden darse y algunos mecanismos propuestos para comunicación y sincronización entre procesos cooperantes que comparten el mismo espacio lógico de direcciones. 

&RQGLFLyQ GH &DUUHUD
Como ya hemos dicho anteriormente, un sistema puede estar compuesto de múltiples procesos que se pueden ejecutar en paralelo (simultáneamente) si se dispone de múltiples procesadores. Cuando solamente se dispone de una CPU, el efecto del procesamiento paralelo puede simularse si los procesos se ejecutan turnándose en la posesión del procesador. En otras palabras, el procesador puede compartirse entre varios procesos. Incluso simulando el procesamiento paralelo, resulta útil ver cada proceso como si tuviera su propio procesador virtual dedicado. Muchas de las dificultades que surgen en el verdadero procesamiento paralelo también se producen en el caso simulado. Uno de estos problemas se muestra en el ejemplo del programa superior de la Figura 18. El primer proceso, el 2EVHUYDGRU, es el responsable de observar y contar eventos. El segundo proceso, el 5HSRUWHUR, ocasionalmente imprime informes sobre el número de eventos observados hasta el momento y seguidamente pone el &RQWDGRU de eventos a cero. Cuando ambos procesos se ejecutan concurrentemente, puede producirse la siguiente situación. Supongamos que el reportero acaba de imprimir un 10, y antes de que pueda poner el &RQWDGRU a cero se produce la interrupción de tiempo y se concede el control de la CPU al 2EVHUYDGRU. Éste, entonces, incrementa el &RQWDGRU a 11. A continuación, el 5HSRUWHUR vuelve a tomar posesión del procesador y pone, por fin, el &RQWDGRU a cero, lo cual significa que un evento queda sin ser contabilizado. En general, el 5HSRUWHUR puede fallar al informar de cualquier número de eventos, ya que el incremento de la variable &RQWDGRU puede producirse entre la impresión del valor, y su puesta a cero. En este ejemplo se muestra que los resultados son impredecibles, ya que los procesos se ejecutan con velocidades relativas igualmente impredecibles. Cuando el resultado de un cálculo depende de las velocidades relativas de los procesos, se dice que hay una FRQGLFLyQ GH FDUUHUD. Las condiciones de carrera se producen 
$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

cuando procesos paralelos comparten datos o recursos, como la variable &RQWDGRU del ejemplo.

6LQFURQL]DFLyQ GH 3URFHVRV
SURJUDP Cuenta_Eventos; Contador : INTEGER := 0; SURFHVV Observador; UHSHDW Esperar_Evento; Contador := Contador + 1; IRUHYHU; HQG Observador; SURFHVV Reportero; UHSHDW Imprimir (Contador); Contador := o; IRUHYHU; HQG Reportero; EHJLQ Observador; Reportero; HQG Cuenta_Eventos;

£

6H SLHUGHQ HYHQWRV

6H SURGXFH XQD &RQGLFLyQ GH &DUUHUD (O DFFHVR D OD YDULDEOH QR HV DWyPLFR
process Observador; repeat Esperar_Evento; (QWUDUB5&; Contador := Contador + 1; 6DOLUB5&; forever; end Observador; process Reportero; repeat (QWUDUB5&; Imprimir (Contador); Contador := 0; 6DOLUB5&; forever; end Reportero;
Tv†‡r€ h†ÃPƒr…h‡v‰ ‚†ÃD

62/8&,Ð1 3URSRUFLRQDU ([FOXVLyQ 0XWXD 5HJLyQ &UtWLFD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

'

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV 

([FOXVLyQ 0XWXD \ 5HJLyQ &UtWLFD
¿Cómo evitar las condiciones de carrera? La clave para evitar problemas en las situaciones en que se comparten objetos o recursos es encontrar algún modo de prohibir que haya más de un proceso leyendo o escribiendo el dato compartido al mismo tiempo. En otras palabras, lo que se necesita es H[FOXVLyQ PXWXD, es decir, asegurarse de que si un proceso está accediendo a un dato compartido, el otro o los otros procesos estarán imposibilitados para poder hacerlo también. El problema de nuestro ejemplo es que el proceso 2EVHUYDGRU puede acceder al &RQWDGRU (lo incrementa) antes de que el 5HSRUWHUR haya acabado de realizar las operaciones con la variable (le faltaba ponerla a cero), o sea, se accede a la variable antes de que el proceso que la está modificando la deje en un HVWDGR FRQVLVWHQWH. Y este problema se produce porque las operaciones de acceso a la variable compartida no son indivisibles en su ejecución, es decir, porque no son DWyPLFDV o ininterrumpibles. En la vida de un proceso, parte del tiempo está ocupado con cálculos internos y otro tipo de cosas que no conducen a una condición de carrera. Pero en otras ocasiones, el proceso accede a variables o ficheros compartidos que sí puede conducir a la condición de carrera. La parte del programa en la que se accede a memoria compartida se denomina UHJLyQ FUtWLFD. Si nos las pudiéramos apañar para que dos procesos no estuvieran al mismo tiempo en su región crítica, evitaríamos las condiciones de carrera. 

,PSOHPHQWDFLyQ GH OD ([FOXVLyQ 0XWXD
En la parte inferior de la Figura 18 tenemos nuestro ejemplo transformado de acuerdo a la premisa del acceso a la región crítica. En este programa transformado se muestra una solución abstracta al problema de la exclusión mutua. Podemos ver que la región crítica de cada proceso está encerrada entre sendas sentencias de entrada y salida de la región ((QWUDUB5& y 6DOLUB5&). Estaría bien que estas primitivas de acceso a la región crítica se comportasen como “porteros”, tal que si un proceso intentara entrar en la región crítica ocupada por otro proceso, el primero quedara bloqueado por el portero hasta que el otro proceso saliese de ella. 

&RQGLFLRQHV SDUD HO 6LQFURQLVPR GH 3URFHVRV &RRSHUDQWHV Aunque con la exclusión mutua se evitan las condiciones de carrera, no es condición suficiente para que una serie de procesos paralelos cooperen correcta y eficientemente utilizando datos compartidos. Se requieren las siguientes condiciones para obtener una buena solución: 1. Dos procesos no pueden estar al mismo tiempo dentro de la misma región crítica. 2. No se deben hacer suposiciones sobre el hardware, es decir, sobre la velocidad o el número de procesadores que intervienen. 
$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

3. No se deben hacer suposiciones sobre las velocidades relativas de los procesos. 4. Ningún proceso fuera de su región crítica puede bloquear a otros procesos. 5. Ningún proceso deberá esperar eternamente a entrar en su región crítica. 6. No se debe posponer indefinidamente la decisión de cuál es el siguiente proceso que debe entrar. 

0HFDQLVPRV En este apartado examinaremos, tanto a nivel hardware como software, algunos de los muy diversos métodos de sincronización que existen para resolver el problema de la exclusión mutua. Estos son: • • • • Inhibición de interrupciones Espera activa Semáforos Monitores

Sobre las versiones originales de algunos de estos mecanismos (semáforos y monitores) ha habido diversas modificaciones a lo largo de la historia, por ello aquí vamos a comentar los conceptos básicos o el cometido fundamental que se busca con cada uno de ellos, pues su estudio en profundidad sería más propio de un curso de Programación Concurrente. No obstante, en la bibliografía se citan algunos libros en los que se puede encontrar información adicional sobre este tema. ,QKLELFLyQ GH ,QWHUUXSFLRQHV Si se pretende evitar que mientras un proceso está dentro de una región crítica, otro proceso pueda entrar también, la forma más fácil de conseguirlo es evitando que el proceso que se encuentra dentro de la región pierda el control del procesador antes de abandonarla. Un proceso pierde la posesión de la CPU solamente si realiza una operación de E/S o, si debido a una interrupción, se detecta que se le acabó su porción de tiempo o que otro proceso de mayor prioridad pasa a Preparado y seguidamente se apropia de la CPU. Sabido esto, por una parte se puede hacer que un proceso que se encuentra dentro de una región crítica no realice operaciones de E/S, y por otra parte lo que falta por hacer es inhibir la aceptación de interrupciones por parte del procesador mientras el proceso está dentro de la región. Es decir, que las sentencias Entrar_RC y Salir_RC se podrían corresponder, respectivamente, con las instrucciones máquina DISABLE (inhibir aceptación de interrupciones) y ENABLE (aceptar interrupciones). Así, una vez que un proceso ha inhibido las interrupciones, puede examinar y actualizar la memoria compartida sin miedo a que otro proceso intervenga, pues la secuencia de instrucciones que componen la región crítica se convierte en una única operación atómica o indivisible.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6LQFURQL]DFLyQ

([FOXVLyQ 0XWXD
5HTXLVLWRV SDUD VX ,PSOHPHQWDFLyQ

+ + + + + +

'RV SURFHVRV QR SXHGHQ HVWDU DO PLVPR WLHPSR GHQWUR GH OD PLVPD UHJLyQ FUtWLFD 1R VH GHEHQ KDFHU VXSRVLFLRQHV VREUH HO KDUGZDUH YHORFLGDG R Qž GH SURFHVDGRUHV  1R VH GHEHQ KDFHU VXSRVLFLRQHV VREUH OD YHORFLGDGHV UHODWLYDV GH ORV SURFHVRV 1LQJ~Q SURFHVR IXHUD GH VX UHJLyQ FUtWLFD SXHGH EORTXHDU D RWURV SURFHVRV 1LQJ~Q SURFHVR GHEHUi HVSHUDU HWHUQDPHQWH D HQWUDU HQ VX UHJLyQ FUtWLFD 1R VH GHEH SRVSRQHU LQGHILQLGDPHQWH OD GHFLVLyQ GH FXiO HV HO VLJXLHQWH SURFHVR TXH GHEH HQWUDU

9$5,26 6,67(0$6
Ï ,QKLELFLyQ GH ,QWHUUXSFLRQHV Ï 9DULDEOH&HUURMR (VSHUD $FWLYD Ï 6HPiIRURV Ï 0RQLWRUHV Ï 

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ

( 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

La ventaja de este sistema es su simplicidad. Sin embargo, también da lugar a varios inconvenientes: • La región crítica debe ser corta, pues de lo contrario se podrían perder interrupciones generadas por los dispositivos de E/S si no se tratan a tiempo. • Inhibiendo las interrupciones, no solamente se impide que otro proceso cooperante que desee entrar en la región crítica pueda continuar su ejecución, sino también a procesos cooperantes que no intentan en la región crítica. Y lo que es peor, también se impide que prosigan el resto de los procesos del sistema, que por no ser cooperantes, en ningún momento intentarán acceder a los datos compartidos que se están protegiendo. • Este método sólo es apropiado para sistemas monoprocesador, pues en un entorno con múltiples CPU’s la prohibición de las interrupciones en un procesador no afecta a los demás. Una solución a este problema podría ser el centralizar en un único procesador la gestión de interrupciones, pero no siempre esto es posible. • Resulta peligroso darle al usuario un medio para inhibir las interrupciones, pues podría ocurrir que por un error de programación o por cualquier otro motivo no las volviera a permitir, provocando la consiguiente pérdida de las subsiguientes interrupciones y el acaparamiento en exclusiva de la CPU. Sin embargo, con frecuencia resulta conveniente para el núcleo del sistema operativo la inhibición de interrupciones durante unas pocas instrucciones mientras actualiza estructuras de datos del sistema, por ejemplo, para actualizar la lista de procesos Preparados, pues si se dejase en un estado inconsistente, el sistema se iría al traste. Como conclusión, se puede decir que la inhibición de interrupciones resulta, a veces, una técnica útil o práctica para el núcleo, pero no es apropiada como mecanismo general de exclusión mutua para los procesos de usuario. Acabamos de ver una solución hardware al problema de la exclusión mutua. Pasemos a tratar algunas soluciones basadas en algoritmos software que tratan de evitar la pérdida de interrupciones y la injusticia de que la protección de una región crítica perjudique a todos los procesos del sistema, incluso a aquellos que no tienen ninguna relación con la estructura de datos compartida que se quiere proteger.

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

([FOXVLyQ 0XWXD

,QKLELFLyQ GH ,QWHUUXSFLRQHV
3RVHVLyQ LQGHILQLGD GH OD &38

,QWHUUXSFLRQHV ,QKLELGDV

352%/(0$6
3 6H SXHGHQ SHUGHU LQWHUUXSFLRQHV 3 6H SULYD D 72'26 ORV SURFHVRV GH OD &38 3 3HOLJURVR HQ PDQRV GHO XVXDULR

62/8&,Ð1 (VSHFLILFDU OD 5HJLyQ &UtWLFD ... Entrar_RC (RC_Eventos); ... ... Salir_RC (RC_Eventos); ...

8WLO SDUD ORV Q~FOHRV GH ORV VLVWHPDV RSHUDWLYRV

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ! 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

(VSHUD $FWLYD &HUURMRV Otra posibilidad de impedir el acceso simultáneo de dos procesos a la región crítica es haciendo que una variable actúe como cerrojo o indicador de si la región crítica está ocupada o no. Esto se puede hacer con una variable booleana que tome los valores 0 (libre) y 1 (ocupada). Todos los procesos que deseen acceder a una región crítica deben cumplir un protocolo de acceso y salida de la región. Cuando un proceso llegue a la entrada de la región debe consultar el valor de la variablecerrojo; si el valor es 0, la pone a 1 y entra en la región crítica; si la variable ya estaba a 1, el proceso debe esperar hasta que valga 0. La idea de este método es similar al acceso al lavabo de un avión de pasajeros. Si el cartel indica /LEUH, entramos, cerramos la puerta, y el cartel pasa a indicar 2FXSDGR. En cambio, si al intentar acceder al lavabo, el cartel indica 2FXSDGR, simplemente esperamos a que quede libre. Por desgracia, esta idea contiene el mismo problema que nuestro ejemplo de los procesos Observador y Reportero. Supongamos que un Proceso A lee el cerrojo y ve que está a 0. Antes de que pueda ponerlo a 1, pierde el control de la CPU y lo toma otro Proceso B que también quiere entrar en la región crítica. Este último consulta también el valor del cerrojo (que sigue a 0), lo pone a 1 y entra en la región. Antes de salir de la región crítica, finaliza su porción de tiempo y se le devuelve el control al Proceso A, que continúa lo que estaba haciendo, con lo que pone el cerrojo a 1 (otra vez) y entra en la región crítica, creyendo que él es el único que está dentro, porque ha entrado siguiendo el protocolo de acceso. Como vemos, el problema se debe a que la consulta del cerrojo y su posterior puesta a 1 (ocupado) no se realiza como una acción atómica. Para solucionar esto han surgido diversos algoritmos, entre ellos, el de la panadería (de Lamport); el algoritmo de Decker (para 2 procesos); el de Dijkstra (para n procesos); el de Knuth, Eisemberg y McGuire; y el de Peterson. La descripción de estos algoritmos puede encontrarse en cualquiera de los textos indicados en la bibliografía. Se consigue una buena solución con un poco de ayuda hardware. Los procesadores de propósito general suelen ofrecer la siguiente instrucción máquina (por lo tanto, ininterrumpible en su ejecución): TAS (Cerrojo, Valor) Esta instrucción (7HVW DQG 6HW) actúa de la siguiente manera. Se lee la variable &HUURMR, y en función de su valor, se establecen los IODJV correspondientes en el Registro de Estado del procesador. Por último, a dicha variable se le asigna el contenido del segundo parámetro, 9DORU. De esta forma se consigue realizar las dos acciones de comprobación y asignación del valor “ocupado” sin ninguna interrupción. En la implementación de Entrar_RC y Salir_RC con TAS de la Figura 21 se puede ver que cuando un proceso llega a la entrada de la región crítica, si la

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

([FOXVLyQ 0XWXD

9DULDEOH&HUURMR
TST BNZ MOV RET MOV RET RC_Eventos Entrar_RC 1, RC_Eventos

(QWUDUB5&

6DOLUB5&

0, RC_Eventos

£

(VWDP RV DO SUL FRPR QFLSLR

5&B(YHQWRV DB

0

+D\ 9DULRV $OJRULWPRV TXH OR 6ROXFLRQDQ
à à à à 'HNNHU  SURFHVRV  'LMNVWUD Q SURFHVRV .QXWK (LVHQEHUJ 0F*XLUH $OJRULWPR GH OD 3DQDGHUtD GH /DPSRUW 3HWHUVRQ Entrar_RC TAS BNZ RET MOV RET RC_Eventos,1 Entrar_RC

0HMRU FRQ $\XGD GHO +:

Test and Set

Salir_RC

0,RC_Eventos

+ ´3UREOHPD GH OD ,QYHUVLyQ GH 3ULRULGDGHVµ + £  \ VL KD\ P~OWLSOHV SURFHVDGRUHV "

(O *UDQ 3UREOHPD GH HVWDV 6ROXFLRQHV
(63(5$ $&7,9$
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

£ &RQVXPH 5RGDMDV GH 7LHPSR

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ! 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

variable-cerrojo RC_EVENTOS no tiene el valor 0, todo lo que tiene que hacer es ejecutarse en bucle hasta que la consulta del Registro de Estado indique que la variable tenía el valor 0. Para anunciar la salida de la región crítica, lo único que hay que hacer es simplemente poner el valor 0 en el cerrojo. Un problema que se puede producir aquí es que un proceso cumpla con el protocolo de entrada a la región crítica y acceda a ella, pero que a la salida se le olvide liberarla. El acceso a la región queda bloqueado indefinidamente. Hasta ahora este método funciona porque las acciones de FRPSUREDU \ SRQHU se ejecutan como una sola instrucción ininterrumpible, pero veamos con mayor detalle cómo se ejecuta la instrucción TAS. En primer lugar la CPU toma posesión del bus (direcciones, datos y control) para leer el contenido del cerrojo de su posición de memoria. Una vez traído el dato, el procesador suelta la posesión del bus para analizar el contenido de la variable leída y establecer los IODJV del Registro de Estado de acuerdo a su valor. Por último, vuelve a adueñarse del bus y realiza la escritura del cerrojo con el valor que corresponda. Pues bien, ¿funcionaría esto en un sistema multiprocesador? La respuesta es no. Entre la lectura y la escritura del cerrojo, el bus de acceso a memoria queda libre, con lo que nada impide que otro procesador lea el contenido del cerrojo en ese intervalo y se crea con permiso para entrar en la región crítica. Para solucionar esto, suele disponerse de una instrucción TASL 7HVW DQG 6HW ZLWK /RFN), que mantiene el bus retenido para la CPU durante toda la operación de lectura y escritura del cerrojo. Hemos dicho que “FXDQGR XQ SURFHVR OOHJD D OD HQWUDGD GH OD UHJLyQ FUtWLFD VL OD YDULDEOHFHUURMR QR WLHQH HO YDORU  WRGR OR TXH WLHQH TXH KDFHU HV HMHFXWDUVH HQ EXFOH KDVWD TXH OD FRQVXOWD GHO UHJLVWUR GH HVWDGR LQGLTXH TXH OD YDULDEOH WHQtD HO YDORU ”. Esto es un problema, o al menos, un gasto inútil de CPU. Si el cerrojo tiene el valor 1 y el proceso que desea acceder a la región crítica está comprobando LQLQWHUUXPSLGDPHQWH su valor, está claro que dicho valor no va a cambiar, al menos mientras tal proceso continúe ejecutando la instrucción TAS. Seguramente habrá que esperar a que se acabe su porción de tiempo, tome control el proceso que se encuentra dentro de la región y al finalizar ponga a 0 el cerrojo. Así tenemos que el proceso que quiere entrar gasta inútilmente sus porciones de tiempo esperando a que aparezca el valor 0, cosa que nunca va a suceder mientras él tenga la posesión de la CPU. Por esto, a este método para conseguir la exclusión mutua se le conoce como HVSHUD DFWLYD, pues el proceso espera su turno consumiendo, inútilmente, tiempo de procesador. Cuando la política de planificación de CPU es por prioridades, utilizando mecanismos de sincronización de espera activa, se puede presentar el siguiente escenario, conocido como el problema de la LQYHUVLyQ GH SULRULGDGHV. Supongamos dos procesos cooperantes, P1 con prioridad 1 (alta) que está en espera, y otro proceso P2 con prioridad 2 (baja) que está en ejecución. El proceso P2 entra en la región crítica, y antes de abandonarla, el proceso P1 sale de espera y pasa a Preparado, y debido a su mayor prioridad pasa inmediatamente a Ejecución,
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

por lo que al proceso P2 se le expulsa a Preparados. El proceso P1 se ejecuta hasta llegar a la entrada de la región crítica, pero tras consultar el estado del cerrojo, se dedica a realizar la espera activa hasta que el cerrojo quede libre. Como su prioridad es mayor que la del proceso que se encuentra dentro de la región crítica (P2), nunca va a ceder el procesador, con lo que el proceso P2 no va a continuar ejecutándose y nunca abandonará la región crítica. Los dos procesos quedan bloqueados. 6HPiIRURV En apartados anteriores hemos hablado sobre el ciclo de vida de un proceso, durante el cual se pasa por periodos de instrucciones de CPU y por periodos de espera de E/S. Debido a que las operaciones con recursos externos tardan mucho tiempo en realizarse (incluso puede haber una cola de procesos requiriendo sus servicios), los procesos que solicitan una operación de E/S pasan a estado de Espera y ceden la CPU a otro proceso, no desperdiciando así el tiempo de procesador. E.W. Dijkstra propuso en 1965 el Semáforo como mecanismo de sincronización. Una de sus principales peculiaridades es que evita la espera activa. La idea era tratar las regiones críticas como recursos de acceso exclusivo por los que compiten los procesos, de tal manera que el que consigue el permiso entra en la región crítica, y el resto de los procesos quedan en estado de Espera hasta que les llegue el turno de acceso. Un semáforo es un tipo abstracto de datos con dos operaciones básicas más una de inicialización (Figura 22). A las dos operaciones básicas las llamaremos %DMDU y 6XELU, aunque originalmente se llamaran 3 y 9, y posteriormente hayan recibido otros nombres muy utilizados como (VSHUDU y 6HxDODU :DLW y 6LJQDO . Para cada región crítica se declara una variable de tipo Semáforo que identifica a la región como un recurso compartido. Estas dos operaciones básicas se corresponden con los protocolos de acceso y salida de la región crítica, tal que para entrar en ella hay que ejecutar una operación Bajar sobre el semáforo asociado a esa región, y a la salida debe llamarse a la instrucción Subir sobre el mismo semáforo. Desde un punto de vista abstracto, el comportamiento de estas dos primitivas es el siguiente: %DMDU 6  ZKLOH S ≤ 0 GR Esperar; S := S-1; 6XELU 6  S := S+1; Con esta descripción ya puede empezarse a entender cómo funcionan los semáforos, pues su comportamiento es similar a las acciones realizadas con el mecanismo de espera activa. Pero ya hemos dicho que en este caso, no hay espera activa, así que profundicemos, con ayuda de la Figura 22, en los significados de las operaciones Bajar y Subir. Centrémonos en la acción (VSHUDU que se realiza dentro de la operación Bajar de un semáforo. Esta acción significa: 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

1. Meter al proceso llamante en la cola de espera de los procesos que quieren entrar en la región crítica. 2. Quitarle la CPU, pues no puede continuar la ejecución. 3. Llamar al Planificador para que seleccione un proceso de la cola Preparados y seguidamente se le ceda el control del procesador.

([FOXVLyQ 0 XWXD Package Semaforos is type SEMAFOROS is private; procedure ,QLFLDOL]DU(S : SEMAFOROS; Valor : INTEGER); procedure %DMDU (S: SEMAFOROS); procedure 6XELU (S: SEMAFOROS); end Semaforos;

6HP iIRURV

/ODP DGDV DO 6LVWHP D DWyPLFDV

%$ -$ 5 ⇒ LI 9DORUB6HP iIRUR &HGHUB&38 3DVDUBDB(VSHUD HOVH 

WKHQ

9DORUB6HP iIRUR  9DORUB6HPiIRUR   HQGLI 68 %,5 ⇒ LI 9DORUB6HP iIRUR !  WKHQ 9DORUB6HP iIRUR  9DORUB6HPiIRUR   HOVH LI + D\B$ OJ~QB3URFHVRB(VSHUDQGR WKHQ 3RQHUORB3UHSDUGR 3ODQLILFDGRU HOVH 9DORUB6HP iIRUR   HQGLI HQGLI

T v† ‡r € h † ÃP ƒ r …h ‡v‰ ‚ † ÃD

B r † ‡vy  Ãq r ÃQ … ‚ p r † ‚ † ÃÃ! !

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Nos queda hablar de la inicialización del semáforo. Como ya veremos en las notas sobre su implementación, un semáforo tiene un contador interno asociado, tal que cada vez que un proceso realiza una operación Bajar sobre él, se decrementa en 1, hasta llegar a cero. Por esto, el valor inicial de dicho contador indica el número máximo de procesos que pueden utilizar simultáneamente el recurso asociado. En el caso de que el recurso sea una región crítica, el valor inicial del semáforo deberá ser 1, pues es el número máximo de procesos que pueden acceder simultáneamente a la región. Los valores que puede tomar el contador del semáforo son, entonces, 0 y 1; por esto a un semáforo de este tipo se le denomina VHPiIRUR ELQDULR. Ahora podemos ver, en la Figura 23, la versión con semáforos de nuestro ejemplo del Observador y el Reportero. Obsérvese que el programa Cuenta_Eventos comienza inicializando a 1 el semáforo S, y arrancando a continuación los dos procesos.

6 HP iIRURV 

H Q Q X H V W U R H M H P S O R
Program Cuenta_Eventos; Contador : INTEGER; S : SEMAFOROS; process Observador; repeat Esperar_Evento; %DMDU 6  Contador := Contador 6XELU 6  forever; end Observador; process Reportero; repeat %DMDU 6  Imprimir (Contador); Contador := 0; 6XELU 6  forever; end Reportero; begin ,QLFLDOL]DU 6   Observador; Reportero; end Cuenta_Eventos;

+

1;

T v† ‡ r € h † ÃP ƒ r … h ‡ v‰ ‚ † ÃD

B r † ‡ vy  Ãq r ÃQ … ‚ p r † ‚ † ÃÃ! " 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

En la Figura 24 se muestra una aproximación a la implementación del semáforo. Ciertos detalles concretos pueden variar de un sistema a otro, sobre todo dependiendo de la política de planificación utilizada. Como se puede ver, un Semáforo es un registro con dos campos: el FRQWDGRU indicador del número de procesos que pueden acceder al recurso, y una FROD para los procesos que tengan que esperar su turno. Como comentario adicional a lo mostrado en dicha Figura 24, cabe resaltar el hecho de que las operaciones sobre el semáforo son Llamadas al Sistema y, por lo tanto, desde el punto de vista del usuario, se realizan de forma DWyPLFD, es decir, que las instrucciones sobre la estructura de datos que compone el semáforo se ejecutan siempre en exclusión mutua. La forma de conseguir la exclusión mutua (no incluida en la Figura 24) depende de la implementación concreta de cada sistema operativo. Ya tenemos un mecanismo de sincronización que nos ha resuelto el gran problema de la espera activa, pues ya no se desperdicia el tiempo de la CPU. No obstante, se sigue manteniendo uno de los problemas de los cerrojos, esto es, sigue siendo responsabilidad del programador el uso adecuado de las primitivas de sincronización, o sea, %DMDU para entrar en la región crítica, y 6XELU para salir de ella. Si inadvertidamente no se sigue estrictamente el protocolo de entrada y salida de la región, o no inicializa adecuadamente el semáforo, el sistema falla. 0RQLWRUHV Para evitar el problema de los descuidos del programador a la hora de seguir el protocolo estipulado para acceder y salir de una región crítica, Hoare propuso en 1974 una primitiva de sincronización de más alto nivel denominada PRQLWRU. Brinch Hansen propuso otra versión del monitor en 1975, y posteriormente ha habido otras más, así como también hay diversas políticas de planificación para los procesos que intervienen en un monitor. Básicamente, un monitor es una colección de procedimientos y datos, agrupados en una especie de módulo muy especial conocido como módulo monitor. Los procesos pueden llamar a los procedimientos del monitor siempre que lo deseen, pero no pueden acceder directamente a las estructuras de datos internas del monitor desde procedimientos declarados fuera del monitor. Las estructuras de datos escondidas en el monitor solamente están accesibles por los procedimientos del monitor. En la Figura 25 se muestra un monitor llamado Control_Eventos que esconde una variable interna: Num_Eventos, y que exporta dos procedimientos de acceso a la variable: Incrementa e Imprime. En la parte inferior tenemos una versión de nuestro ejemplo en la que se utiliza el monitor. Los monitores tienen una propiedad especial para conseguir la exclusión mutua: “6RODPHQWH XQ SURFHVR SXHGH HVWDU DFWLYR D OD YH] GHQWUR GH XQ PRQLWRU”. Dicho de otra forma, dado un proceso A que ha llamado a un procedimiento de un monitor, y mientras se está ejecutando dicho procedimiento, toma el control de la CPU otro proceso B, si este proceso B llama a cualquier procedimiento del monitor, el proceso B quedará detenido en la entrada (en estado de Espera) hasta que el proceso A abandone el monitor.
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

6HPiIRURV

,PSOHPHQWDFLyQ

type SEMAFOROS is private; procedure ,QLFLDOL]DU(S : SEMAFOROS; Valor : INTEGER); procedure %DMDU (S : SEMAFOROS); procedure 6XELU (S : SEMAFOROS); private -- Inaccesible al usuario type SEMAFOROS is record Contador : INTEGER; Cola : COLA_PROCESOS; end; -procedure ,QLFLDOL]DU (S : SEMAFOROS; Valor : INTEGER) is begin S.Contador := Valor; end Inicializar; procedure %DMDU (S : SEMAFOROS) is begin if S.Contador < 1 then Encolar (Este_Proceso, S.Cola); Suspender; -- Implica llamada al Planificador else S.Contador := S.Contador - 1; endif; end Bajar; procedure 6XELU (S : SEMAFOROS) is Proceso : ID_PROCESO; begin if s.Cola.Primero /= 0 then -- Si algun proc. Esperando Desencolar (Proceso, S.Cola); Preparar (Proceso); -- Llamada al Planificador else S.Contador := S.Contador + 1; endif; end Subir;

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!# 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

([FOXVLyQ 0XWXD

0RQLWRU
3 $FFHVR &RQFXUUHQWH 3 ,QWHUEORTXHRV

/RV VHPiIRURV VRQ XQ EXHQ PHFDQLVPR SDUD VLQFURQL]DFLyQ GH SURFHVRV SHUR  6L QR VH XVDQ DGHFXDGDPHQWH RUGHQ Q~PHUR YDORU LQLFLDO

8Q 0RQLWRU HV XQ FRQMXQWR GDWRV FRQ VXV SURFHGLPLHQWRV GH DFFHVR HQFHUUDGRV HQ XQ PyGXOR HVSHFLDO 0RQLWRU  6RODPHQWH XQ SURFHVR SXHGH HVWDU DFWLYR HQ XQ PRQLWRU HQ XQ PRPHQWR GDGR (;&/86,Ð1 0878$

Module Monitor Control_Eventos; Num_Eventos : INTEGER; procedure ,QFUHPHQWD is Num_Eventos := Num_Eventos + 1; end Incrementa; procedure ,PSULPH is Imprimir (Num_Eventos); Num_Eventos := 0; end Imprime; process Observador; repeat Esperar_Evento; &RQWUROB(YHQWRV,QFUHPHQWD forever; end Observador; process Reportero; repeat &RQWUROB(YHQWRV,PSULPH Hacer_Otras_Cosas; forever; end Reportero;
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!$

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Los monitores son una construcción de los lenguajes de programación, de tal forma que los compiladores saben que las llamadas a los procedimientos de un monitor se manejan de forma distinta a las llamadas a los procedimientos convencionales. Normalmente, en la llamada de un proceso a un procedimiento de un monitor, las primeras instrucciones del procedimiento son para comprobar si algún otro proceso se encuentra dentro del monitor; si es así, el proceso llamante queda bloqueado hasta que el otro proceso salga del monitor. Si no hay ningún proceso dentro del monitor, el proceso llamante puede entrar y continuar la ejecución. La implementación de la exclusión mutua en las entradas del monitor es labor del compilador. Normalmente suele realizarse con ayuda de un semáforo binario, de tal forma que en el prólogo de un procedimiento de monitor, se incluye una llamada a Bajar(S), y a la terminación del procedimiento se llama a Subir(S), siendo S un semáforo asociado a cada monitor. Ya que es el compilador, no el programador, el que se ocupa de cumplir el protocolo de acceso a la región crítica, es mucho más difícil que algo se haga mal o que se produzca algún olvido. En cualquier caso, la persona que escribe un monitor no tiene por qué saber cómo implementa la exclusión mutua el compilador. Le basta con saber que metiendo las regiones críticas en monitores, nunca habrá más de un proceso dentro de la misma región crítica al mismo tiempo. Puesto que cuando un proceso se encuentra dentro de un monitor, no puede entrar otro proceso, debe evitarse que el proceso que está dentro pueda quedarse bloqueado en estado de Espera, o sea, que no debe ejecutar llamadas al sistema que lo pasen a tal estado. Sin embargo hay situaciones en las que se requiere pasar a Espera. Para ello, existen otras construcciones, para que cuando un proceso dentro de un monitor deba pasar a espera, se permita la entrada a algún otro proceso que esté esperando para entrar. Aunque estas construcciones (las YDULDEOHV FRQGLFLyQ), no vamos a tratarlas en estos apuntes, puede obtenerse una descripción detallada consultando la bibliografía de referencia. 

3DVR GH 0HQVDMHV
Aunque los semáforos y los monitores son buenos mecanismos para la sincronización de procesos todavía tienen algunas pegas: los semáforos son de demasiado bajo nivel, y los monitores solamente están disponibles en unos pocos lenguajes de programación. Otro problema con los monitores y los semáforos es que están diseñados para resolver el problema de la exclusión mutua en sistemas con una o más CPU’s que comparten una memoria común. Pero cuando se trata de un sistema distribuido, formado por múltiples procesadores, cada uno con su propia memoria particular y conectados por una red de área local, estas primitivas se vuelven inservibles, pues ya no hay variables compartidas, y ninguno de estos mecanismos proporciona intercambio de información entre máquinas. Se necesita algo más. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

&RPXQLFDFLyQ GH 3URFHVRV

3DVR GH 0HQVDMHV
&RPXQLFDFLyQ HQWUH 3URFHVRV

0HPRULD &RPSDUWLGD
(O SURJUDPDGRU UHVXHOYH ORV SUREOHPDV GH FRQFXUHQFLD (QYLDU 0HQVDMH

3DVR GH 0HQVDMHV
1R KD\ YDULDEOHV FRPSDUWLGDV 5HFLELU 0HQVDMH

3URF 
5HFLELU 0HQVDMH

3URF 
(QYLDU 0HQVDMH

$/*81$6 &8(67,21(6 8QLGLUHFFLRQDO Ï 0HPRULD &RPSDUWLGD (O (QODFH Ï %XV +DUGZDUH 3XHGH 6HU %LGLUHFFLRQDO Ï 5HG GH &RPXQLFDFLRQHV

+

+ 0RGHORV /yJLFRV

Ï &RPXQLFDFLyQ ',5(&7$ R ,1',5(&7$ Ï &RPXQLFDFLyQ 6,0e75,&$ 2 $6,0e75,&$

+ &DSDFLGDG GHO %X]yQ +
7DPDxR GHO 0HQVDMH Ï )LMR Ï 9DULDEOH
Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!%

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Ese algo más es el SDVR GH PHQVDMHV. La función del paso de mensajes es permitir que dos procesos se comuniquen sin necesidad de utilizar variables compartidas. Este método de comunicación entre procesos ofrece, al menos, dos primitivas: (QYLDU y 5HFLELU, que, a diferencia de los monitores, no son construcciones del lenguaje de programación, sino Llamadas al Sistema, por lo que para utilizarlas basta con llamar a los correspondientes procedimientos de biblioteca. Mediante (QYLDU se expide un mensaje a un proceso destino, mientras que con 5HFLELU se indica el deseo de recibir un mensaje de algún proceso fuente. Si no hay ningún mensaje disponible, el proceso receptor puede quedarse bloqueado hasta que llegue uno. El paso de mensajes no es de uso exclusivo de sistemas con múltiples procesadores (con o sin memoria común), sino que es válido para cualquier sistema multiproceso, ya sea con una o más CPU’s, o con memoria compartida o local a cada procesador, pues su semántica solamente indica el paso de información de un proceso a otro. Esta independencia del hardware subyacente hace que los programas que utilizan paso de mensajes como mecanismo de sincronización y comunicación sean más portables entre distintas máquinas, pues sólo requieren que dispongan del mismo sistema operativo. (Obsérvese que esto no quiere decir que para que dos procesos que se ejecutan en máquinas distintas puedan comunicarse, tengan que ejecutarse sobre el mismo sistema operativo; simplemente tienen que utilizar el mismo protocolo de comunicación). Si dos procesos $ y % quieren comunicarse, deben enviarse y recibir mensajes, por lo que debe establecerse un HQODFH GH FRPXQLFDFLyQ entre ellos. Este enlace puede implementase de distintas maneras. Aquí no vamos a tratar la implementación física del enlace (memoria compartida, un bus o una red), que es más propia de los cursos de comunicación de datos, sino que vamos a preocuparnos de los aspectos lógicos de la implementación. Así, estudiaremos cuestiones relacionadas con los siguientes puntos: • ¿Cuál es el tamaño de los mensajes? ¿El tamaño es fijo o puede ser variable? • ¿Un enlace puede ser unidireccional o bidireccional? Es decir ¿los mensajes solamente pueden viajar en un sentido, o en ambos? • Modelos de comunicación: comunicación directa o indirecta, simétrica o asimétrica. • La información se puede enviar por copia o por referencia. En cuanto al tamaño de los mensajes que se envían los procesos, pueden ser de longitud fija o variable. Si sólo se permiten mensajes de longitud fija, la implementación del sistema es más fácil, pero tal restricción dificulta la tarea del programador. Veamos el resto de las cuestiones enumeradas en los siguientes apartados. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV 

0RGHORV GH &RPXQLFDFLyQ Primero debemos decir que los procesos reciben mensajes en EX]RQHV. Es decir, que cuando un proceso envía mensajes, estos van a parar a buzones, y los procesos que quieren recibirlos tendrán que sacarlos de esos buzones. Los procesos que desean comunicarse deben disponer de una manera explícita de indicar el destino del mensaje que se envía, o el remitente del mensaje que se quiere recibir, y esto depende de que la comunicación sea 'LUHFWD o ,QGLUHFWD. &RPXQLFDFLyQ 'LUHFWD En la comunicación directa de envío de mensajes, tanto el emisor como el receptor deben indicar explícitamente el proceso destino o remitente del mensaje. Así, las primitivas de envío y recepción tendrán el siguiente aspecto: (QYLDU 3URFHVRB'HVWLQR 0HQVDMH  5HFLELU 3URFHVRB2ULJHQ 0HQVDMH  Como se puede apreciar en el esquema superior de la Figura 27, cada proceso tiene su propio buzón de recepción de mensajes. Una comunicación de este tipo tiene las siguientes características: • Automáticamente se establece un enlace entre cada par de procesos que se quieren comunicar. • Cada uno de ellos necesita saber la identidad del otro proceso con el que se quiere comunicar. • Un enlace asocia únicamente a dos procesos. • Entre cada par de procesos solamente existe un enlace. • El enlace o comunicación puede ser unidireccional o bidireccional. En la Figura 27 también tenemos a nuestros dos procesos, el Observador y el Reportero, comunicándose por mensajes. Tal comunicación es directa, unidireccional (el Observador sólo envía, y el Reportero solamente recibe) y VLPpWULFD, pues tanto el emisor como el receptor necesita conocer el nombre del otro proceso. Una variante dentro de esta comunicación directa, es que el modelo sea DVLPpWULFR (esquema inferior de la Figura 27), es decir, que puede haber múltiples procesos enviando mensajes a un único receptor, en cuyo caso el proceso receptor no tiene que indicar de qué proceso quiere recibir mensajes. En la comunicación asimétrica, la llamada al sistema para enviar mensajes permanece invariable, mientras que la de recepción, queda así: 5HFLELU ,GB3URFHVR 0HQVDMH  Donde ambos parámetros son de salida. ,GB3URFHVR contendrá el identificador del proceso que envió el 0HQVDMH recibido.
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

3DVR GH 0HQVDMHV

&RPXQLFDFLyQ 'LUHFWD

3 &DGD SURFHVR WLHQH VX SURSLR EX]yQ 3 &DGD SURFHVR LPSOLFDGR GHEH LQGLFDU H[SOtFLWDPHQWH HO QRPEUH GHO UHFHSWRU R HPLVRU (QYLDU 3 0HQVDMH 5HFLELU 3 0HQVDMH

3URF 
5HFLELU 3 0HQVDMH

3URF 
(QYLDU 3 0HQVDMH

(VTXHPD 6,0e75,&2

2EVHUYDGRU
repeat . . . Esperar_Evento . . . (QYLDU 5HSRUWHUR0HQVDMH forever

5HSRUWHUR
repeat . . . 5HFLELU 2EVHUYDGRU0HQVDMH . . . Imprimir_Evento forever

2EV  2EV  2EV 

(QYLDU 5HSRUWHUR 0HQVDMH 

(QYLDU 5HSRUWHUR 0HQVDMH 

5HS
5HFLELU 5HPLWHQWH 0HQVDMH 

(QYLDU 5HSRUWHUR 0HQVDMH 

(VTXHPD $6,0e75,&2 3HJD GH OD &RPXQLFDFLyQ 'LUHFWD
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

6L FDPELD HO QRPEUH GH XQ SURFHVR KD\ TXH UHYLVDU WRGDV ODV UHIHUHQFLDV D pO
Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!& 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

La desventaja que presenta este modelo de comunicación directa (tanto el simétrico como el asimétrico), es el problema que se plantea con el mantenimiento de los nombres de proceso. Es decir, en un programa, que puede estar formado por muchos módulos, si se cambia el identificador de un proceso hay que revisar todos los módulos para comprobar y modificar todas las referencias a tal proceso, para que indiquen el nuevo identificador. &RPXQLFDFLyQ ,QGLUHFWD Con la comunicación indirecta, los mensajes se envían a buzones, no a procesos, y, análogamente, el receptor debe indicar el buzón del que quiere recibir un mensaje, no de qué proceso. Véase el croquis superior de la Figura 28. Un buzón se puede ver como un objeto en el que se pueden poner y retirar mensajes. Cada buzón tiene un identificador único. Según este esquema, un proceso puede comunicarse con otros procesos mediante distintos buzones. Las primitivas de envío y recepción de mensajes quedan así: (QYLDU %X]yQ 0HQVDMH  5HFLELU %X]yQ 0HQVDMH  siendo %X]yQ el identificador del buzón al que se envía o del que se desea recibir un mensaje. Observando el citado croquis de la Figura 28, puede verse que, ahora, un enlace de comunicaciones tiene las siguientes propiedades: • Dos procesos solamente pueden comunicarse entre ellos si comparten un buzón. • Un enlace de comunicaciones puede estar asociado a más de dos procesos. • Entre cada pareja de procesos comunicantes puede haber varios enlaces, donde cada enlace corresponde a un buzón. • Un enlace puede ser unidireccional o bidireccional. Este modelo de comunicación indirecta ya no adolece del problema del mantenimiento de los nombres o identificadores de procesos que se producía en la comunicación directa, pues ahora nunca se nombra el proceso destino u origen, sino un buzón común. Este esquema de comunicaciones es similar al servicio de $SDUWDGRV GH &RUUHRV que ofrecen las compañías postales. La comunicación mediante un apartado de correos, es independiente de la dirección o domicilio real de la persona o entidad a quien se dirige la correspondencia, ya que ésta se le envía indirectamente, vía un apartado de correos, y aunque el destinatario cambie de domicilio, basta con que siga yendo a recoger la correspondencia al cajetín del apartado de correos para que la comunicación siga siendo efectiva. Obviamente, la comunicación se mantiene en tanto en cuanto se mantenga invariable el nombre del buzón o apartado de correos común. Pero mientras que los cambios de domicilio

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

3DVR GH 0HQVDMHV

&RPXQLFDFLyQ ,QGLUHFWD
/RV %X]RQHV 6RQ &RPSDUWLGRV
%X]yQB
Recibir (Buzón_1, Mensaje);

2EV 
Enviar (Buzón_1, Mensaje)

2EV 
Enviar (Buzón_1, Mensaje) Enviar (Buzón_2, Mensaje)

%X]yQB

5HS 
Recibir (Buzón_2, Mensaje);

2EV 
Enviar (Buzón_2, Mensaje)

5HS 
Recibir (Buzón_2, Mensaje);

/RV PHQVDMHV VH HQYtDQ \ UHFLEHQ DGH EX]RQHV QR D SURFHVRV 
5HSB \ 5HSB HMHFXWDQ Recibir (Buzón_2, Mensaje)  2EVB HQYtD XQ PHQVDMH DO %X]yQB + ¢ 4Xp SURFHVR UHFLEH HO PHQVDMH GH 2EVB " (O 6LVWHPD 2SHUDWLYR RIUHFH VHUYLFLRV SDUD
Procedure &UHDUB%X]RQ (Nombre : in Buzon Nombres; : out Buzones); Nombres;

procedure &RQHFWDUB%X]RQ (Nombre : in Buzon procedure (QYLDU (Buzon

: out Buzones);

: in Buzones;

Mensaje : in Mensajes); procedure 5HFLELU (Buzon : in Buzones; Mensaje : out Mensajes); procedure 'HVWUXLUB%X]RQ (Buzon : in out Buzones);
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!' 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

son previsibles, no hay razón para no seguir manteniendo el mismo apartado de correos, y así nadie se ve afectado por el cambio de dirección. Cuando la comunicación es indirecta, se pueden tener varios buzones de comunicación entre dos procesos, con lo que se puede enviar mensajes a uno u otro buzón, dependiendo del motivo o importancia de cada mensaje. Obsérvese que, debido a la flexibilidad que ofrece este esquema, se puede tener cualquier combinación numérica de procesos productores y consumidores de mensajes: • Un productor- un consumidor • Varios productores - un consumidor • Un productor - varios consumidores • Varios productores - varios consumidores Las primitivas de gestión de buzones y mensajes varían según el sistema operativo. No obstante, en el cuadro inferior de la Figura 28 podemos ver las primitivas que se suelen ofrecer para estos servicios: • • • • Crear un buzón. Conectarse a un buzón. Enviar y recibir mensajes de un buzón. Destruir un buzón.

Para crear un buzón, se llama a la primitiva correspondiente, indicando como parámetro de entrada el nombre del buzón, esto es, una tira preestablecida de caracteres (al igual que los nombres de ficheros), y el sistema crea el buzón devolviendo como parámetro de salida el LGHQWLILFDGRU GHO EX]yQ creado. Este identificador es el que se debe utilizar en el resto de las operaciones que se realicen con ese buzón. Cuando varios procesos vayan a comunicarse mediante un buzón, uno de ellos (el propietario) lo debe crear y, posteriormente, el resto debe conectarse a él, pues conocen de antemano el nombre del buzón a compartir. Seguidamente ya pueden realizar las operaciones de envío y recepción de mensajes utilizando el identificador de buzón. El proceso propietario del buzón debe ocuparse de destruir el buzón cuando no se requieran más sus servicios, para liberar la memoria y recursos del sistema que se utilizan en la gestión del buzón. 

&DSDFLGDG GHO %X]yQ Un buzón tiene una capacidad que determina el número de mensajes que puede tener almacenados temporalmente. Este almacén se puede ver como una cola de mensajes asociada al buzón. Básicamente hay tres posibilidades sobre el tamaño del buzón:
$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

• &DSDFLGDG /LPLWDGD La cola tiene una longitud máxima finita (Q mensajes), lo que quiere decir que, como mucho, podrá haber Q mensajes en el buzón esperando a ser recibidos por uno o varios procesos. Así, si la cola no está llena, cuando un proceso envía un mensaje, éste se encola en el buzón, y el emisor puede continuar la ejecución sin ninguna espera. El proceso receptor podría estar esperando a recibir un mensaje, con lo que ahora ya podría recibirlo y continuar también la ejecución; pero también es posible que no hubiera todavía ningún proceso esperando por el mensaje, en cuyo caso, el mensaje simplemente queda encolado en el buzón hasta que un proceso quiera recibirlo. No obstante, ya que el tamaño del buzón es limitado, si al enviar un mensaje a un buzón, éste está lleno, entonces hay dos alternativas: - El proceso emisor queda bloqueado en espera de que haya espacio libre en el buzón. - Como parámetro de salida en la llamada a (QYLDU, se le indica un VWDWXV de error indicativo del llenado del buzón. En este caso, el proceso emisor no se bloquea, y se deja en sus manos la decisión de reenvío o no del mensaje. La técnica habitual de implementar estos buzones es mediante un buffer circular. • 6LQ /tPLWH GH &DSDFLGDG La cola de mensajes tiene una longitud potencialmente infinita, por lo que puede albergar cualquier número de mensajes, y por lo tanto, el emisor nunca queda bloqueado. Los buzones de capacidad ilimitada suelen implementarse como una lista encadenada de mensajes, por lo que la limitación sólo está en la cantidad de memoria que el proceso tiene disponible. • &DSDFLGDG 1XOD La longitud máxima de la cola de mensajes es cero, por lo que no puede haber mensajes en el buzón esperando a ser recibidos. En este caso, el emisor o remitente que quiera enviar un mensaje debe esperar hasta que el destinatario reciba el mensaje. Así, los dos procesos deben ponerse de acuerdo en el momento de realizar el envío/recepción del mensaje para que la transferencia tenga lugar. En este caso se dice que la comunicación es VtQFURQD. A esta comunicación síncrona también se le conoce con el nombre de UHQGH]YRXV (cita). Se debe hacer notar que cuando la capacidad del buzón no es cero, el proceso emisor no sabe cuándo un mensaje enviado ha llegado a su destino, pues no tiene que esperar a que el proceso destino lo reciba (comunicación DVtQFURQD), y esto puede ser crucial para el normal desarrollo del programa. En este caso, el receptor debería comunicarse explícitamente con el emisor para hacerle saber que ha recibido el mensaje. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

3DVR GH 0HQVDMHV

&DSDFLGDG GHO %X]yQ

+ &DSDFLGDG /LPLWDGD Q PHQVDMHV
6L KD\ HVSDFLR ⇒ (O HPLVRU FRQWLQ~D OD HMHFXFLyQ GHVSXpV GHO HQYtR 6L HVWi OOHQR ⇒ 3 (O HPLVRU TXHGD EORTXHDGR KDVWD TXH KD\D HVSDFLR HQ HO EX]yQ SDUD GHMDU XQ PHQVDMH 3 6H GHYXHOYH XQ VWDWXV OOHQR

+ &DSDFLGDG ,OLPLWDGD
(O HPLVRU QXQFD VH EORTXHD HQ HO HQYtR GH PHQVDMHV

+ &DSDFLGDG 1XOD
(O HPLVRU TXHGD EORTXHDGR KDVWD TXH HO UHFHSWRU HVWi OLVWR SDUD UHFLELU HO PHQVDMH &RPXQLFDFLyQ 6tQFURQD 5(1'(=9286

(Q ORV EX]RQHV FRQ FDSDFLGDG !  ¢&yPR VDEH HO HPLVRU TXH HO PHQVDMH KD OOHJDGR D VX GHVWLQR" PROCESO P1: Enviar (P2, Mensaje); Recibir (P2, Mensaje); PROCESO P2: Recibir (P1, Mensaje); Enviar (P1, Mensaje);

+D\ TXH IRU]DU HO VLQFURQLVPR

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ!(

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV 

7KUHDGV
Vamos a comentar ahora un nuevo tipo de procesos que en los últimos años a surgido con fuerza entre los sistemas operativos y que se adapta especialmente bien a la estructura de los sistemas con múltiples procesadores: los WKUHDGV o procesos ligeros. Para que un programa pueda ejecutarse (convertirse en proceso) se requieren dos elementos: • Un procesador. • Un entorno de ejecución. El entorno de ejecución se refiere al resto de los recursos (además del procesador) que necesita un programa para ejecutarse. Así, por ejemplo, sabemos que se necesita un área de memoria para acoger el código del programa, un área de memoria para ubicar las variables globales, otro área de memoria, denominado KHDS, de donde se sirven las peticiones dinámicas de memoria, y por último también se necesita un área de memoria para albergar la pila de trabajo. Una vez que el proceso está cargado en memoria puede comenzar su ejecución. Con memoria virtual, el comienzo de la ejecución va a implicar que todas las primeras referencias a memoria generen una falta de página, tanto en la caché como en memoria principal, por lo que se deberá dedicar un tiempo a la carga de páginas iniciales hasta que se consiga el conjunto de trabajo estable. También es normal que un proceso haga operaciones de E/S con ficheros, por lo que será necesario abrir los ficheros con los que se vaya a trabajar, y durante la ejecución se tendrán EXIIHUV de E/S asociados con cada dispositivo o fichero. Como nos podemos imaginar se requiere cierto tiempo para conseguir un entorno de ejecución estable. Los procesos tradicionales (como los de Unix) se crean de tal forma que comparten el procesador (en un entorno monoprocesador) y a cada uno se le asigna un entorno de ejecución diferente, es decir, cada uno tiene sus áreas de memoria, sus tablas de páginas, sus descriptores de los ficheros que maneja, sus EXIIHUV de E/S, semáforos, etc. Y esto, que parece razonable, se hace para todos los procesos del sistema, es decir, se trata a todos los procesos del sistema como si fueran totalmente disjuntos y que lo único que comparten es el procesador. Ahora bien, hay situaciones en las que un trabajo laborioso, puede descomponerse en varias subtareas o subprocesos, de tal forma que todos ellos cooperan en la consecución de un mismo fin. En estos trabajos es normal que haya mucha comunicación y compartimiento de datos entre los subprocesos componentes. El mecanismo normal de comunicación en estos casos son los mensajes, que no deja de ser un mecanismo costoso en tiempo. La comunicación entre procesos por memoria compartida, aunque rápida, es peligrosa, pues un proceso malintencionado podría machacar áreas de memoria de otro proceso con el que comparte memoria, sin embargo esto no es normal en procesos cooperantes. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV

7KUHDGV
3DUD HMHFXWDU XQ SURJUDPD VH UHTXLHUH 0&  &RQWDGRU GH SURJUDPD 3XQWHUR GH SLOD 5HJLVWUR GH HVWDGR 5HJLVWURV JHQHUDOHV  (QWRUQR GH (MHFXFLyQ (VSDFLR GH GLUHFFLRQHV 9DULDEOHV JOREDOHV )LFKHURV DELHUWRV 7HPSRUL]DGRUHV 3URFHVRV KLMRV 6HxDOHV 6HPiIRURV &RQWDELOLGDG

&DPELR GH FRQWH[WR

3 &DPELR HQ HO SURFHVDGRU 3 &DPELR GH HQWRUQR GH HMHFXFLyQ  )DOWDV GH SiJLQD  )DOWDV GH FDFKp  $EULU ILFKHURV  /OHQDU EXIIHUV GH (6 SLOD SLOD FRG 3 SLOD SLOD

1HFHVDULR FRQ 3URFHVRV 'LVMXQWRV 3(52 

3URFHVRV &RRSHUDQWHV 38('(1 &203$57,5 5(&85626

GDWRV FRG 3

GDWRV FyGLJR 3 3

3 &UHDFLyQ 5iSLGD GH 3URFHVRV 3 &DPELR 5iSLGR GH &RQWH[WR

Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD

Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ"

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

Hemos visto que la creación de un proceso puede ser un tanto costosa, pues crea un entorno de trabajo totalmente diferente para cada uno. Sin embargo, para procesos cooperantes parece que no se requieren entornos totalmente distintos, pues es muy posible que prefieran áreas de memoria comunes para compartir datos (a su propio riesgo) y comunicarse rápidamente. Es más, seguramente prefieren compartir las memorias caché, y los EXIIHUV de E/S, pues parte de los datos que manejan van dirigidos o provienen de las mismas fuentes. Dos o más procesos gemelos cooperantes podrían compartir incluso el área de código. Según esto, la creación de procesos cooperantes requeriría un entorno de trabajo muy reducido: la pila de trabajo y, en caso de procesos no gemelos, un área de memoria para el código. Esto traería ventajas por dos vertientes:
• •

Creación rápida de procesos Cambio rápido de contexto

Debemos darnos cuenta de que, en este escenario, la conmutación del entorno de trabajo entre dos procesos cooperantes puede ser muy rápida, pues solamente hay que cambiar los registros del procesador (lo cual implica un cambio de pila de trabajo y de contador de programa). El proceso que asume la posesión del procesador va a seguir utilizando las mismas áreas de memoria para datos estáticos, código (si los procesos son gemelos), ficheros, EXIIHUV de E/S. El compartimiento de memoria va a implicar, además, que al cambiar de contexto no se van a vaciar las cachés y no se van a producir faltas de página en las primeras referencias a memoria, con lo que se evitan más pérdidas de tiempo. Por lo visto hasta ahora, parece que sería interesante que los sistemas operativos ofrecieran dos tipos de procesos (cooperantes y no cooperantes), con sus correspondientes primitivas de creación, gestión, comunicación y sincronización. Prácticamente todos los núcleos de sistemas operativos para sistemas distribuidos ofrecen los dos tipos de procesos, y estos son los nombres que les han dado: .HUQHO GH 62 $PRHED &KRUXV 0DFK 9 6\VWHP SURFHVRV FRRSHUDQWHV 7KUHDG 7KUHDG 7KUHDG Proceso 3URFHVRV QR FRRSHUDQWHV Proceso Actor Tarea Equipo (7HDP)

Aunque los distintos sistemas operativos no se han puesto totalmente de acuerdo, los nombres más extendidos son los proceso, tarea o proceso pesado para los procesos tradicionales (los que tienen un entorno de trabajo totalmente diferente de los demás procesos), y WKUHDG o SURFHVR OLJHUR para los procesos cooperantes que quieren compartir el entorno de trabajo. Windows/NT, OS/2 y Solaris (Unix de Sun) son algunos ejemplos de sistemas operativos comerciales que disponen de WKUHDGV. 

$SXQWHV GH 62 ,

*HVWLyQ GH 3URFHVRV 

7KUHDGV
.HUQHO GH 62 $PRHED &KRUXV 0DFK 9 6\VWHP 3URF &RRSHUDQWHV 7KUHDG 7KUHDG 7KUHDG 3URFHVR 7KUHDG R 3URFHVR /LJHUR 0D\RU 1~PHUR GH 3URFHVRV &RRSHUDQWHV 3URF 1R &RRSHUDQWHV 3URFHVR $FWRU 7DUHD (TXLSR 7HDP 3URFHVR R 3URFHVR 3HVDGR

0HMRU DSURYHFKDPLHQWR GH ORV 7KUHDGV
WKUHDG UHSDUWLGRU 5$0 FRPSDUWLGD

/RV 6' VH SUHVWDQ D WHQHU DSOLFDFLRQHV IRUPDGDV SRU PXFKRV SURFHVRV FRRSHUDQWHV

WKUHDGV GH VHUYLFLR

FDFKp

SHWLFLyQ 62 8QL[ 7RSD] &UHDU SURFHVRWKUHDG  PV  PV

EX]yQ

&DPELR FRQWH[WR  PV  PV

6REUH XQ SURFHVDGRU &9$; GH ',*,7$/
Tv†‡r€h†ÃPƒr…h‡v‰‚†ÃD Br†‡vyÃqrÃQ…‚pr†‚†ÃÃ"

$SXQWHV GH 62 , 

*HVWLyQ GH 3URFHVRV

A los programas con WKUHDGV se les saca más provecho en aplicaciones compuestas de múltiples procesos cooperantes, y esto es algo que se suele dar mucho en los sistemas distribuidos, en los que por su filosofía cliente-servidor se prestan mucho a este tipo de aplicaciones. Debido a la premura de tiempo no vamos a profundizar en esta justificación, no obstante, se recomienda echar un vistazo a los capítulos dedicados a WKUHDGV de los textos indicados en la bibliografía, en los cuales pueden encontrarse numerosos ejemplos de situaciones de programas en las que se muestran beneficios de los WKUHDGV frente a los procesos convencionales. Algunos datos sobre los tiempos creación de procesos nos pueden ayudar a convencernos de las ventajas de los WKUHDGV. La creación de un proceso Unix sobre un procesador CVAX de DIGITAL requiere 11 milisegundos, mientras que la creación de un WKUHDG en un kernel llamado Topaz, sobre el mismo procesador solamente necesita 1 milisegundo. Los tiempos de cambio de contexto entre procesos Unix oscilan alrededor de 1,8 milisegundos, siendo solamente 0,4 ( y en algunos casos 0,004) entre WKUHDGV de Topaz. A estos datos habría que añadir los beneficios que se ganan a largo plazo, es decir, el tiempo que no se pierde en cargar de nuevo las páginas de memoria virtual, de la caché, creación de semáforos, apertura y cierre de ficheros, llenado de EXIIHUV de E/S, etc. 

$SXQWHV GH 62 ,

You're Reading a Free Preview

Descarga
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->