LICENCIATURA
EN SISTEMAS DE INFORMACIÓN
SISTEMAS
OPERATIVOS
MONOGRAFÍA GRUPO Nº 1
TEMA:
SOPORTE DEL SISTEMA
OPERATIVO
Alumnos integrantes:
¨
Barrios Mayra L.U.
Nº 34.102
¨
Cemborain Juan Martín L.U.
Nº 34.079
¨
Zamparo Fabio L.U.
Nº 33.708
¨
Altamirano Romina L.U.
Nº 33.109
¨
Billordo Rosa Adriana L.U.
Nº 32.701
¨
Valenzuela Juan Alberto L.U. Nº 31.003
¨
Montenegro Carmenia L.U.
Nº 30.658
¨
De los Reyes Leonardo L.U.
Nº 30.279
¨
Acosta Germán L.U.
Nº 30.011
¨
Leguisamón Miguel Adolfo L.U. Nº 29.209
¨
Cemborain Guillermo L.U.
Nº 26.913
ÍNDICE
ü
Nivel del Sistema Operativo
ü
Protección
ü
Procesos e Hilos
ü
Creación de un proceso nuevo
ü
Hilos
ü Arquitecturas para servidores multi-hilo
ü
Hilos dentro de los clientes
ü
Tiempos de vida de los hilos
ü
Planificación de hilos
ü
Primitivas de sincronización
ü
Prestaciones de la invocación
ü
Elección del protocolo
ü
Operación Asíncrona
ü
Arquitectura del Sistema Operativo
ü Algunas aproximaciones híbridas
Middlewere y Sistemas Operativos en Red.
En realidad, no se emplea ningún sistema
operativo distribuido, sino solo sistemas operativos en red del tipo de UNÍX,
MacOS y diferentes variantes de
Windows.
Esta situación tiende a mantenerse, por dos
razones:
✔
La
primera es que los usuarios ya han realizados grandes inversiones en su
software de aplicación, que normalmente resuelve sus problemas; por lo que no
cambiaran a un nuevo sistema operativo que es incapaz de ejecutar sus
aplicaciones, por muchas ventajas que ofrezca.
✔
La
segunda razón en contra, es que los usuarios prefieren tener autonomía en la
gestión de sus propias máquinas, incluso en organizaciones fuertemente
cohesionadas, para conseguir buenas prestaciones.
La combinación de middlewere y sistema
operativo en red proporciona un equilibrio aceptable entre los requisitos de
autonomía, por un lado, y la transparencia de red en el acceso a recursos, por
el otro.
¨
Los
sistemas operativos en red permiten a los usuarios ejecutar su procesador de
textos junto con otro tipo de aplicaciones (independiente).
¨
El
middlewere les permite acceder a los servicios que aparecen como disponibles en
el sistema distribuido.
El Nivel de Sistema
Operativo.
El middlewere se ejecuta en múltiples
combinaciones hardware/ sistema operativo, es decir, en múltiples plataformas
en los nodos de un sistema distribuido. El sistema operativo que se ejecuta en
un cierto nodo (un núcleo junto con los servicios asociados de nivel de
usuario, por ej., bibliotecas) proporciona dentro de ese nodo su propia imagen
sobre las abstracciones de los recursos hardware locales de procesamiento, de
almacenamiento y de comunicación.
El middlewere utiliza una combinación de esos
recursos locales para implementar los mecanismos de invocación remota entre
objetos o procesos en los nodos.

Computador
y hardware de red Procesos, hilos, comunicaciones,... Procesos, hilos, comunicaciones,... Computador
y hardware de red
Middlewere
Aplicaciones, servicios
OS1
OS2
![]()
![]()
Nodo 1 Nodo2
La figura, muestra cómo el nivel de sistema
operativo en cada uno de los dos nodos soporta un nivel de middlewere común
para proporcionar una infraestructura distribuida para aplicaciones y
servicios.
Los núcleos y los procesos cliente y servidor
que se ejecutan son los principales componentes de la arquitectura sobre los
que trataremos.
Los núcleos y el proceso servidor son los
componentes que gestionan los recursos y los presentan a los clientes a través
de una interfaz de recursos. Esta debe tener las siguientes características:
R
Encapsulamiento: debe proporcionar un servicio de
interfaz útil sobre los recursos, conjunto de operaciones que cubra las
necesidades. Los detalles del tipo gestión de la memoria o dispositivos
utilizados para implementar los recursos deben ocultarse a los clientes.
R
Protección: los recursos deben protegerse de
los accesos no permitidos.
R
Procesamiento concurrente: los clientes pueden compartir
múltiples recursos y acceder a ellos concurrentemente. Los gestores de recursos
son los responsables de conseguir transparencia en la concurrencia.
Los clientes acceden a los recursos mediante,
por ejemplo, invocaciones a un método remoto de un objeto que reside en un
cierto servidor o bien mediante llamadas al sistema en el núcleo. Los
mecanismos de acceso a un recurso encapsulado se denominan mecanismo de invocación. Una combinación de bibliotecas, núcleos y servidores puede utilizarse
para realizar las siguientes tareas de invocación:
R
Comunicación:
los parámetros de operación y los resultados deben pasarse hacia y desde los
gestores de recursos, utilizando una red o bien dentro del computador.
R
Planificación:
cuando se invoca una cierta operación, su procesamiento debe planificarse
dentro del núcleo o del servidor.

![]()
Funcionalidad básica del sistema
operativo
La figura muestra la funcionalidad básica
del sistema operativo la cual está relacionada con. La gestión de procesos e
hilos, la gestión de la memoria, y la comunicación entre procesos en el mismo
computador (las divisiones horizontales indican dependencia). El núcleo
proporciona gran parte de esta funcionalidad.
El software del S.O. se diseña para
ser portable entre las diferentes arquitecturas de computadores, se codifica en
e un lenguaje de alto nivel, ya sea C, C++ o Modula-3, y que sus servicios se
organizan por niveles de forma que los componentes dependientes de la máquina
se reducen a un único nivel inferior.
Multiprocesadores
de memoria compartida
Los computadores multiprocesador de
memoria compartida se componen de varios procesadores que comparten uno o más
módulos de memoria (RAM). Los procesadores pueden tener también su propia
memoria privada. Se pueden construir de diferentes formas:
# Los más
simples y menos costosos están construidos incorporando una tarjeta que
contiene de 2 a 8 procesadores en un computador personal.
Los multiprocesadores en los
sistemas distribuidos son particularmente muy utilizados para la implementación
de servidores de alta prestaciones ya que el servidor puede ejecutar un único
programa con varios hilos los cuales gestionan varias solicitudes llegadas de
diferentes clientes de forma simultánea.
Los principales componentes de un sistema operativo son los siguientes:
✔ Gestor de procesos: gestiona la creación y las diferentes operaciones sobre procesos
(unidad de gestión de recursos que incluye un espacio de direcciones y uno o
más hilos).
✔ Gestor de hilos: incluye la creación, sincronización y planificación de hilos (son
actividades planificables asociadas a procesos).
✔ Gestor de las comunicaciones: comunicaciones entre hilos asociados a
diferentes procesos en un mismo computador. Algunos núcleos soportan
comunicación entre hilos asociados a procesos remotos. Otros no, de forma que
deben añadirse servicios adicionales para las comunicaciones externas.
✔ Gestor de memoria: gestión de memoria física y virtual.
✔ Supervisor: se ocupa de la resolución de interrupciones, interrupciones internas de
llamadas al sistema y otras, control de la unidad de gestión de memoria y de
las ante memoria (caché) hardware; manipulación de registros del procesador y
la unidad en punto flotante. A todo esto se llama Nivel de Abstracción del
hardware en Windows NT.
Protección:
Los
recursos necesitan protección contra los accesos no permitidos. Hay que tener
en cuenta que las amenazas a la integridad de un sistema no previenen
únicamente de código ideado de forma maliciosa. También un código bien
intencionado puede contener un error o puede tener un comportamiento no
esperado, provocando que parte del sistema se comporte a su vez de forma
incorrecta.
Para
comprender lo que se quiere decir con acceso ilegitimo a un recurso,
consideremos un archivo abierto para lectura y escritura. La protección del
archivo se puede descomponer en dos sub-problemas. El primero consiste a
asegurar que cada una de las dos operaciones sobre el archivo solo puede ser
realizada por clientes. Por ejemplo Gonzáles, que es el propietario del
archivo, tiene los derechos de lectura y escritura sobre el. Pérez solo
necesita acceder a la operación de lectura. En este caso se producirá un acceso
ilegitimo si Pérez intentara realizar una operación de escritura sobre el
archivo.
El otro
tipo de acceso ilegitimo, ocurre cuando un proceso se comporta de forma
errónea, esquivando operaciones que se exportan sobre un recurso. En nuestro ejemplo
esto ocurriría si Gonzáles o Pérez, de alguna forma, ejecutaran una operación
que no fuera lectura o escritura.
Podemos
proteger, los recursos, de invocaciones ilegitimas del tipo SET FILE POINT
ERRAND ONLY.
Una
posibilidad insiste en utilizar un lenguaje de programación con sistema de
tipos seguro como Java o Modula-3. Estos lenguajes no permiten que un modulo
acceda a otro modulo objeto a no ser que previamente obtenga una referencia a
este ultimo. Por el contrario, en C++ un programador puede realizar
asignaciones a un puntero a voluntad, realizando de esta forma invocaciones de
tipo inseguras
El concepto tradicional en los sistemas
operativos de que un proceso ejecuta una única actividad, ya se comprobó, en la
década de los ochenta, que era poco adecuado para las especificaciones de los
sistemas distribuidos; y también para ciertas aplicaciones sobre un solo
computador que necesitan concurrencia interna. El problema es que los procesos
realizan la comparición entre actividades
relacionadas de una forma difícil y cara.
La solución consistió en ampliar el concepto de proceso de forma que
pudiera asociarse a múltiples actividades. En la actualidad un proceso consiste
en un entorno de ejecución formado por uno o más hilos. Un hilo es una
abstracción del sistema operativo asociada a una actividad. Un Entorno de
ejecución equivale a una unidad de gestión de recursos: una colección de
recursos locales gestionados por el núcleo sobre los que tienen acceso los
hilos.
Un entorno de ejecución consiste básicamente de
los siguientes elementos:
-
Un
espacio de direcciones
-
Recursos
de comunicación y sincronización de hilos, como semáforos e interfaces de
comunicación.
-
Recursos
de alto nivel, como archivos abiertos y ventanas.
Los entornos de ejecución son caros en cuanto a
su creación y gestión, aunque sin embargo pueden ser compartidos por más de un
hilo, es decir, estos pueden compartir todos los recursos accesibles dentro de
cada entorno. Entonces, un entorno de ejecución representa el dominio de
protección en el que se ejecutan los hilos.
Los hilos pueden crearse y destruirse en forma
dinámica. El principal propósito para la existencia de múltiples hilos es
maximizar el grado de ejecución concurrente entre las diferentes operaciones,
permitiendo así habilitar el solapamiento de la computación con la entrada-
salida y el procesamiento concurrente en los multiprocesadores. Esto es
particularmente útil en los servidores
en los que el procesamiento concurrente de las solicitudes de los clientes
pueden reducir la tendencia de los servidores a convertirse en cuellos de botella.
Un entorno de ejecución proporciona protección
contra los hilos externos de forma que los datos y otros recursos contenidos en
el sean inaccesibles para los hilos residentes en otros entornos de ejecución.
Sin embargo ciertos núcleos permiten compartir en forma controlada recursos
entre entornos de ejecución diferentes residentes en el mismo computador.
Es una unidad de gestión de memoria virtual de
un proceso. Es grande y esta formado por una o mas regiones, separadas por
áreas de memoria virtual inaccesibles.
Una región es una zona de memoria virtual
contigua accesible por los hilos del proceso propietario. Las regiones no se
solapan. Hay que resaltar la distinción entre regiones y sus contenidos. Cada
región se caracteriza por las siguientes propiedades:
-
Su
tamaño
-
Los
permisos de lectura/ escritura/ ejecución para los hilos del proceso.
-
Una indicación
de crecimiento hacia arriba o hacia abajo.
Este modelo esta orientado a páginas. Las
regiones podrían eventualmente solaparse si su tamaño se extendiera. Entre las
regiones se dejan huecos para permitir
su crecimiento. Esta representación de un espacio de direcciones como un
conjunto disperso de regiones disjuntas es una generalización del espacio de
direcciones de UNÍX, el cual esta formado por tres regiones: una región de
texto de tamaño fijo y no modificable, que contiene el código del programa; un
montón (heap), parte del cual se inicializa con los valores almacenados en el
archivo binario con el programa, y que es ampliable hacia direcciones virtuales
crecientes; y una pila, que crecerá hacia direcciones virtuales decrecientes.
La existencia de un número determinado de
regiones tiene su razón de ser en varios factores. Uno de ellos es la necesidad
de que haya pilas separadas para cada hilo. La existencia de regiones de pila
distintas para cada hilo permite detectar los intentos de exceder el límite de
la pila y controlar el crecimiento de cada una de ellas. La memoria virtual no
utilizase halla debajo de cada región de pila y los intentos de acceder a esa
región generan excepciones. Una alternativa consiste en asignar la pila de cada
hilo en el montón, sin embargo en este caso ase hace difícil detectar cuando un
hilo excede el limite de su pila.
La necesidad de compartir memoria entre
procesos, o entre procesos y núcleo, es otro factor que deriva en la necesidad
de regiones adicionales en el espacio de direcciones. Una región de memoria
compartida es aquella en la que se asocia la misma memoria física a una o más
regiones pertenecientes a otros espacios de direcciones. Por lo tanto los
procesos acceden a los mismos
contenidos de memoria en las regiones compartidas mientras que sus regiones no
compartidas permanecen protegidas. Algunos usos de las regiones compartidas son
las siguientes:
-
bibliotecas: el código de las bibliotecas puede
llegar a ser muy grande y se desperdiciaría una cantidad considerable de
memoria si se cargaran de forma separada en cada proceso que las utilizase. Por
el contrario, varios procesos pueden compartir una sola copia del código de las
bibliotecas empleando una región compartida del espacio de direcciones.
-
Núcleo: frecuentemente el código y los
datos de los núcleos corresponden dentro del espacio de direcciones en las
mismas posiciones. Cuando un proceso realice una llamada al sistema, o bien
cuando se genere una excepción, no habrá necesidad de conmutar a un nuevo
conjunto de direcciones.
-
Compartir
datos y comunicación:
entre dos procesos, o bien entre un proceso y el núcleo, se puede necesitar
compartir datos para cooperar en la realización de cierta tarea. Es más
eficiente utilizar regiones de direcciones compartidas en lugar de intercambiar
los datos mediante mensaje.
Para un sistema distribuido el diseño de mecanismo de creación de un
proceso debe tener en cuenta la utilización de múltiples computadoras, de esta
forma la infraestructura de gestión de procesos se divide en servicios de
sistemas separados.
La creación de un proceso nuevo pude separarse
en dos aspectos:
La elección del computador destino: el nodo puede elegirse entre varios
de un grupo de computadoras que actúan como servidores, la elección del nodo
donde residirá el nuevo proceso es una cuestión política, los cuales se
distinguen las siguientes categorías de políticas para compartir el uso de la
carga.
A su vez estas políticas pueden ser estáticas o
adaptativos, los primeros operan sin tener una consideración del estado actual
del sistema, se basaron en análisis matemáticos orientados a la optimización de
ciertos parámetros, mientras que los segundos aplican reglas heurísticas para
tomar las decisiones de ubicación basándose en factores de tiempo de ejecución
no predecibles.
Los sistemas para compartir la carga pueden ser
centralizados, jerárquicos o descentralizados. En el primer caso existe un
gestor de carga, en el segundo existen varios.
En un sistema de uso compartido de carga
descentralizado los nodos intercambian información entre ellos directamente
para tomar las decisiones de localización.
En los algoritmos de uso compartido de la carga
iniciados por el emisor el nodo que solicita la creación del proceso es
responsable de iniciar la decisión de transferencia, en cambio en lo que son
iniciados por el receptor un nodo cuya carga esta por debajo de cierto umbral advierte sobre su
existencia a otros nodos con cargas
relativamente altas para que inicien las transferencia.
El otro aspecto que hay que tener encuentra en
la creación de un proceso nuevo es la creación de su entorno. Este esta
formado por un espacio de direcciones iniciados con una serie de contenidos.
Existen dos aproximaciones en las definiciones del espacio de direcciones, una
forma seria con un formato definirlo de forma estáticamente o bien definirlo
respecto de un entorno de ejecución existente, en cuyo caso cada región del
proceso puede ser heredado por el de su
hijo.
Una región heredada puede, o bien ser
compartida, o copiarse desde la región del padre. En el primer caso los marcos
de páginas pertenecientes a la región del padre concuerdan simultáneamente con
las correspondientes del hijo.
En el segundo caso, la región es copiada por
defecto, no se realiza copia física. Los marcos de página que componen la
región heredada se comparten entre los dos espacios de direcciones. Una
página de la región es copiada
físicamente únicamente cuando uno de los dos procesos intente modificarla.
Es un aspecto
importante de los procesos, debido, entre otras cuestiones, porque define la
productividad máxima del servidor medida en solicitudes de cliente manejadas
por segundo.
Este número estará en
función del número de hilos que el servidor disponga.
Por ejemplo,
supongamos que en un computador servidor con un solo procesador cada solicitud
de cliente necesita 2 mlseg. de proceso y 8 mlseg. de entrada-salida sin caché
a disco.
Si solo dispone de un
hilo para realizar todo el proceso, el tiempo de retorno para una solicitud es
2+8 = 10 mlseg. promedio, o sea que
puede atender a 100 clientes/seg. Cualquier mensaje de solicitud que llegue
mientras el servidor está manejando una solicitud es insertado en la cola del
puerto del servidor.
Si en cambio dispone
de dos hilos que se manejen en forma independiente, es decir, cada uno se puede
planificar cuando el otro pasa a estado bloqueado por operaciones de E/S, se
incrementa la productividad del servidor. Si todas las solicitudes al disco se
envían en serie a 8 mlseg. por proceso, la productividad es 1.000/8 = 125
solicitudes/seg.
Si agregamos la
existencia de una caché de disco, el servidor mantiene los bloques leídos en
búfferes dentro de su espacio de direcciones; el hilo encargado de obtener
datos examina previamente la caché compartida evitándose el acceso a disco si
los datos están allí. Considerando una tasa de aciertos del 75%, el tiempo de
E/S por solicitud se reduce a 2 mlseg., incrementándose la productividad
teórica a 500 solicitudes/seg. Considerando que el tiempo de uso del procesador
se incrementa 2,5 mlseg. por búsquedas de datos en la caché, el procesador
puede gestionar 1.000/2,5 = 400 solic/seg.
La productividad se puede
incrementar por medio del uso de multiprocesadores de memoria compartida con
múltiples hilos planificados para procesadores múltiples.
Si el servidor del
ejemplo anterior se ejecuta en un multiprocesador con dos procesadores, con
hilos planificados independientemente sobre los procesadores, se podrán
procesar solicitudes en paralelo hasta un máximo de dos hilos. La productividad
aumenta en este caso a 444 solic/seg.
Arquitecturas para servidores
multi-hilo
Para vincular
solicitudes a hilos en un servidor se resume un informe de Schmidt de 1.998,
describiendo las arquitecturas basadas en hilos de diferentes implementaciones
del Agente de Solicitud de Objetos de CORBA llamado ORB, Object Request Broker.
Cada ORB procesa
solicitudes que llegan a través de un conjunto de sockets activos.
(La figura muestra
una de las posibles arquitecturas basadas en hilos, la Arquitectura de
Asociación de Trabajadores).
En la Arquitectura de
Asociación de Trabajadores, en su forma más simple, el servidor durante la inicialización,
crea un conjunto fijo de hilos de trabajadores para procesar solicitudes.
El módulo receptor y
gestor de cola se implementa normalmente como un hilo de E/S que recibe
solicitudes de un grupo de sockets o puertos y las sitúa en una cola para ser
recuperadas por los trabajadores. Puede que en ciertos casos sea necesario
manejar jerarquía de solicitudes, por ejemplo según el cliente que envíe la
solicitud. Esto se puede gestionar mediante múltiples colas, de forma que el
trabajador pueda examinar las colas en orden de prioridad.
Las desventajas de
esta arquitectura son su escasa flexibilidad y el alto nivel de conmutaciones
entre la E/S y los hilos de trabajo al
manejar la cola compartida.
En la Arquitectura de
Hilo-por-Solicitud, el hilo de E/S genera un nuevo hilo de trabajo para cada
solicitud y ese trabajador se elimina a sí mismo cuando ha procesado la
solicitud asociada a un objeto remoto. Esta arquitectura tiene la ventaja de
que los hilos no compiten por acceder a una cola compartida y la productividad
se maximiza dado que el hilo de E/S puede generar tantos trabajadores como
solicitudes tenga. Su desventaja es la sobrecarga debido a las operaciones de
creación y destrucción de hilos.
La Arquitectura de
Hilo-por-Conexión asocia un hilo por conexión. El servidor crea un hilo
trabajador cuando un cliente realiza una conexión y lo destruye cuando se
cierra la misma. En el intervalo, el cliente puede realizar múltiples
solicitudes sobre la conexión, cuyos destinos pueden ser uno o más objetos remotos.
La Arquitectura de
Hilo-por-Objeto asocia un hilo a cada objeto remoto. Un hilo de E/S recibe las
solicitudes y las inserta en las colas para los trabajadores, con la diferencia
de que en este caso existe una cola por cada objeto.
En cada una de las
dos últimas arquitecturas el servidor se beneficia de pequeñas sobrecargas en
la gestión de hilos en comparación con la de hilo-por-solicitud.
Los hilos pueden ser tan útiles para los
clientes como para los servidores. Proceso
cliente con dos hilos: el primer hilo genera resultados que se van a enviar al
servidor mediante una invocación a método remoto, no necesitando, sin embargo
una respuesta. Las invocaciones a métodos remotos normalmente bloquean al que
invoca, incluso aunque no sea estrictamente preciso esperar. Este proceso
cliente puede añadir un segundo hilo, el cual realiza las invocaciones a los
métodos remotos y se bloque mientras el primer hilo puede continuar computando
nuevos resultados. El primer hilo deposita sus resultados en búferes que son
vaciados por el segundo hilo. Únicamente se bloquea cuando todos los búferes
estén llenos.
La cuestión de clientes multihilo es evidente
también en el ejemplo de los navegadores Web. El usuario sufre retardos
significativos mientras se cargan las paginas; es por lo tanto esencial para
los navegadores la gestión de múltiples solicitudes concurrentes a paginas Web.
HILOS FRENTE A MULTIPLES PROCESOS
La utilidad de los hilos permite que la
computación se solape con la entrada-salida y, para el caso de un
multiprocesador, con otros cómputos. Se puede obtener el mismo solapamiento
mediante la utilización de múltiples procesos mono-hilo. La razón por la cual
se prefiere el proceso multihilo es: la creación y gestión de los hilos es mas
barata que la de procesos y la de uso
compartido de recursos se puede conseguir de forma más eficiente entre hilos
que entre procesos ya que los hilos comparten entornos de ejecución.
Algunos de los principales componentes del estado
que deben gestionarse para entornos de ejecución e hilos: un entorno de
ejecución tiene un espacio de direcciones, interfaces de comunicación,
recu7rsos de alto nivel del tipo de archivos abiertos y objetos para la
sincronización de hilos como los semáforos; además debe mantener una relación
de los hilos que se asocian a dicho entorno. Un hilo tiene una prioridad de
planificación, un estado de ejecución (como bloqueado o preparado), los valores
almacenados correspondientes a los registros del procesador cuando el hilo esta
bloqueado y el estado relacionado con la gestión de interrupciones software del
hilo. Una interrupción software es un evento que provoca la interrupción del
hilo. Si el hilo tiene asignado un procedimiento de gestión se le transfiere el
control. Las señales en UNÍS son ejemplos de interrupciones software.
El entorno de ejecución y los hilos se asocian
con páginas que pertenecen al espacio de direcciones mantenido en memoria
principal, mientras que los datos e instrucciones se almacenan en el caché
hardware.
Comparación entre procesos e hilos:
-
la
creación de un nuevo hilo dentro de un proceso existente es mas barata que la
creación de un proceso.
-
La
conmutación a hilo diferente dentro del mismo proceso es mas barata que la
conmutación entre hilos de diferentes procesos.
-
Los
hilos dentro de un proceso pueden compartir datos y otros recursos de forma más
adecuada y eficiente que con procesos separados.
-
Sin
embargo, los hilos dentro de un proceso no están protegidos entre ellos.
Considérese el coste de creación de un nuevo
hilo dentro de un entorno de ejecución existente. La principal tarea consiste
en asignar una región para la pila y proporcionar los valores iniciales de los
registros del procesador y de al prioridad
y estado de ejecución del hilo. Debido a la existencia de un entorno de
ejecución solo se debe colocar un identificador para el en el registro que
describe al hilo. La sobrecarga asociada a la creación de un proceso es
considerablemente mayor que la asociada a la creación de un nuevo hilo. Es
preciso crear en primer lugar un entorno de ejecución, incluyendo las tablas
del espacio de direcciones. Anderson y
otro citan valores alrededor de 11 milisegundos para la creación de un proceso
UNÍS y sobre 1 milisegundo para la creación de un hilo sobre la misma
arquitectura de procesador CVAX ejecutando un núcleo Topaz; en cada caso el
tiempo medido supone que la entidad creada realiza exclusivamente una
invocación a un procedimiento vacío antes de terminar.
Cuando la nueva entidad realiza una tarea
significativa en lugar de la invocación al procedimiento nulo, se producen
costes a largo plazo que tienden a ser mayores para un nuevo proceso que para
un nuevo hilo dentro de un proceso ya existente. En un núcleo que soporte memoria
virtual, el nuevo proceso generara faltas de páginas según vaya accediendo por primera vez a datos e
instrucciones. Por otro lado para el caso de la ejecución de un hilo las
sobrecargas a largo plazo también pueden ocurrir, pero tienden a ser menores.
Cuando el hilo accede al código y a los datos que han sido utilizados
recientemente por otros hilos del mismo proceso, automáticamente se aprovecha
del hecho de que dichos datos ya residen en cada caché hardware o bien en la memoria principal.
La segunda ventaja de prestaciones de los hilos
se refiere a la conmutación entre hilos, es decir la sustitución de un hilo por
otro en un cierto procesador. Esto puede generarse varias veces durante la vida
del hilo. La conmutación entre hilos que comparten el mismo entorno de
ejecución es mas barata que la de los hilos que pertenecen a diferentes procesos. Las sobrecargas asociadas a la
conmutación de hilos corresponden a la planificación y al cambio de contexto.
Un contexto de procesador esta formado por los valores
de los registros del procesador como el contador del programa y el dominio de
protección actual del hardware: el espacio de direcciones y el modo de
protección del procesador. El cambio de contexto es la transición entre
contextos que ocurre cuando se conmuta entre hilos o cuando un único hilo
realiza una llamada al sistema o genera otro tipo de excepción. Supone realizar
las siguientes tareas:
-
almacenamiento
del registro de estado original del procesador y carga del nuevo estado.
-
En
algunas situaciones se realiza una transferencia a un nuevo dominio de
protección: a esto se lo llama transición de dominio
La conmutación al núcleo o a otro hilo que
pertenece al mismo entorno de ejecución a través del núcleo, supone la
realización de una transición de dominio. El coste es así mayor aunque, si el
núcleo esta vinculado al espacio de direcciones del cliente, es aun
relativamente bajo. Cuando se conmuta entre hilos que pertenecen a diferentes
entornos de ejecución se generan mayores sobrecargas. Los costes a largo plazo
debidos a la ocupación de las entradas del caché hardware y de las páginas de
memoria principal tienden a aplicarse cuando ocurre la mencionada transición de
dominio. Los valores presentados por Anderson
y otros son de 1.8 milisegundos para realizar una conmutación entre
procesos UNÍS y de 0.4 milisegundos para la conmutación entre hilos
pertenecientes al mismo entorno de ejecución realizada en el núcleo Topaz.
Del proceso clientes con dos hilos, el primer
hilo genera los datos y se los pasa al segundo hilo el cual genera una
invocación a un método remoto o bien una llamada a procedimiento remoto. Ambos
hilos pueden acceder a datos a través de variables compartidas. La ventaja esta
en la comodidad y eficiencia del uso compartido de datos. Los hilos que
comparten un espacio de direcciones y que no han sido codificados en un
lenguaje de tipos seguros no están protegidos entre ellos. Un hilo erróneo
puede modificar de forma arbitraria los datos de otro hilo, provocando que este
falle. Si se requiere protección, o bien se utiliza un lenguaje de tipos seguro
o bien es preferible utilizar múltiples procesos en lugar de múltiples hilos.
La programación de hilos
equivale a la programación concurrente, tal y como ha sido estudiada
tradicionalmente, por ejemplo, en el ámbito de los sistemas operativos. La
mayor parte de la programación de hilos se realiza en lenguajes de programación
convencionales como C aumentados con bibliotecas de hilos. Un ejemplo es el
paquete de Hilos para C (C Threads) desarrollado para el sistema operativo
Mach. Algunos lenguajes proporcionan un soporte directo para hilos, como Ada95,
Modula-3 y, de forma más reciente, Java (Oaks y Wong 1999). A continuación
explicaremos someramente los hilos de Java.
De la misma forma que
en cualquier implementación de hilos, Java proporciona métodos para la
creación, destrucción y sincronización de hilos. La clase de Java Thread
incluye el constructor y los métodos de gestión mostrados en la Figura 6.8. Los
métodos de sincronización Thready Object están en la Figura 6.9.
thread.join(int milisegundos)
Bloquea el hilo invocador durante el tiempo especificado hasta que el hilo haya terminado.
thread.interrup()
Interrumpe el hilo: le obliga a volver desde una llamada a método bloqueante como sleep().
objet.wait(long
milisegundos, int nanosegundos)
Bloquea el hilo invocador hasta que una llamada realizada a notify() o notifyAll() en el objeto despierte el hilo, o bien el hilo sea interrumpido, o bien el tiempo especificado sa haya cumplido.
objet.notify(),
objet.notifyAll()
Despierta, respectivamente, uno o todos los hilos que han invocado a wait() en el objeto.
Métodos constructor y de gestión hilos en Java.
Cuando tenemos varios
hilos, muchas veces deseamos que éstos pueden compartir datos, por lo tanto, es
indispensable saber sincronizar sus actividades.
En muchas situaciones,
hilos que se ejecutan concurrentemente comparten información y deben considerar
el estado de las actividades de los demás hilos. Un modelo muy común de tales
conjuntos de hilos es conocido como escenarios de productor/consumidor, donde
el productor genera un flujo de datos que es consumido por un consumidor.
La programación de un
proceso multi-hilo debe realizarse de forma cuidadosa. La principal dificultad
consiste en el uso compartido de objetos y en las técnicas utilizadas para la
coordinación y cooperación de los hilos. Las variables locales de cada hilo en
sus métodos son privadas del hilo, es decir, los hilos tienen pilas privadas.
Los segmentos de
código dentro de un programa que accedan el mismo objeto desde hilos separados
(concurrentes) se llaman regiones críticas. Java provee algunos métodos más
para coordinar las actividades de los hilos, como notifyAll, wait, etc.
Suponga, por ejemplo,
las colas compartidas descritas previamente en esta sección, las cuales tienen
hilos de E/S e hilos de trabajo utilizados para transferir las solicitudes en
arquitecturas de servidores basadas en hilos. Pueden aparecer condiciones de
competencia (race conditions) cuando los hilos manipulan concurrentemente
estructuras de datos del tipo de colas. Las solicitudes que residen en las
colas pueden perderse o duplicarse. A no ser que los punteros de manipulación
de los hilos hayan sido cuidadosamente coordinados.
Java proporciona a
programadores la palabra clave synchronized para designar un monitor, que es un
recurso de sincronización de hilos muy conocido. Los programadores designan
métodos completos o bien bloques de código de tamaño arbitrario como
pertenecientes a un monitor asociado a un objeto individual. La garantía de un
monitor viene del hecho de que como máximo un hilo puede ejecutarse dentro de
un monitor en cualquier instante. Podríamos seriar las acciones de los hilos de
E/S y trabajadores en nuestro ejemplo designando los métodos añadirA() y eliminarDe() en la clase Cola como métodos synchronized. Todos los
accesos a variables dentro de dichos métodos se realizan con exclusión mutua
respecto a las invocaciones de estos métodos.
Java permite bloquear
y despertar hilos a través de objetos arbitrarios que actúan como variables de
condición. Un hilo que necesita bloquearse en espera de una cierta condición
invoca un método wait(). Todos los
objetos implementan este método, ya que pertenecen a la clase raíz de Java
llamada Objet. Otro hilo invocara notify()
para desbloquear como máximo un hilo, o
bien invocará a notifyAll() para desbloquear
todos los hilos en espera sobre el mismo objeto. Ambos métodos de
notificación pertenecen también a la clase Objet.
Como ejemplo, cuando
un hilo trabajador descubre que ya no hay mas solicitudes parar procesar,
invoca wait() en la instancia Cola.
Cuando posteriormente el hilo de E/S añada una solicitud a la cola, invocará el
método notify() de gestión de colas,
para despertar al trabajador.
Los métodos de
sincronización de Java se muestran en la Figura 6.9. Además de las primitivas
de sincronización mencionadas, el método join()
bloquea al que invoca hasta la terminación del hilo destino. El método interrupt() es útil para despertar
prematuramente un hilo en espera. Todas las primitivas estándar de
sincronización, como tos semáforos, pueden implementarse en Java. Sin embargo
es preciso hacerlo cuidadosamente ya que la garantía del monitor de Java se
aplica única mente a código de objetos declarado como synchronized: una clase
tendrá una mezcla de métodos synchronized y no-synchronized. Además el monitor
implementado en un objeto Java tiene una única variable de condición implícita
mientras que en general un monitor puede tener varias variables de condición.
thread.join(int milisegundos)
Bloquea el hilo invocador durante el tiempo especificado hasta que el hilo haya terminado.
thread.interrup()
Interrumpe el hilo: le obliga a volver desde una llamada a método bloqueante como sleep().
objet.wait(long milisegundos, int
nanosegundos)
Bloquea el hilo invocador hasta que una llamada realizada a notify() o notifyAll() en el objeto despierte el hilo, o bien el hilo sea interrumpido, o bien el tiempo especificado sa haya cumplido.
objet.notify(), objet.notifyAll()
Despierta, respectivamente, uno o
todos los hilos que han invocado a wait() en
el objeto.
Llamadas de sincronización de hilos en Java.
Cada nuevo hilo se
crea en la misma máquina virtual Java (JVM. Java Virtual Machine) que su
creador y en estado SUSPENDIDO. Una vez que ha pasado a estado PREPARADO con el
método start(). Ejecuta el método run() de un objeto designado en su
constructor. JVM y los hilos que hay sobre él se ejecutan en un proceso sobre el
sistema operativo subyacente. Los hilos pueden tener asignada una prioridad de
forma que las implementaciones de Java que soportan prioridades ejecutarán cada
hilo de forma preferente al resto de hilos con menor prioridad. Un hilo
finaliza su vida cuando vuelve del método run(),
o bien cuando se invoca el método destroy().
Los programas pueden
gestionar los hilos en grupos. Cada hilo pertenece a un grupo, al que se le
asigna en el momento de su creación. Los grupos de hilos son útiles cuando
varias aplicaciones coexisten en la misma JVM. Un ejemplo de su uso es la
seguridad: por defecto un hilo en un cierto grupo no puede gestionar
operaciones sobre un hilo en otro grupo. De esta forma un hilo de una cierta
aplicación no puede, de forma maliciosa, interrumpir un hilo del entorno de
ventanas del sistema (AWT).
Los grupos de hilos
también facilitan el control de las prioridades relativas de los hilos (en las
implementaciones de Java que soporten prioridades). Esto es útil para
visualizadores que ejecuten applets y para los servidores Web que ejecuten los
programas llamados servlets, los cuales crean páginas Web de forma dinámica. Un
hilo no privilegiado dentro de un applet o servlet únicamente puede crear un
nuevo hilo que pertenezca a su propio grupo, o a un grupo de menor prioridad
creado dentro del suyo: las restricciones exactas dependen del administrador de
seguridad (Securitv Manager) que esté activo. Los visualizadores y los
servidores pueden asignar hilos pertenecientes a diferentes applets o servlets a
diferentes grupos y establecer la prioridad máxima de cada grupo en su conjunto
(incluyendo los grupos descendientes). Para un hilo de applet o de servlet no
existe forma de ignorar las prioridades de grupo impuestas por el gestor de
hilos, ya que no pueden ser modificadas mediante llamadas a setPriority().


Planificación de hilos
Planificación apropiativa:
un hilo puede suspenderse en cualquier punto para dejar paso a otro hilo,
incluso aunque el hilo pueda seguir en ejecución.
Planificación no
apropiativa: un hilo se ejecuta hasta él mismo realiza una invocación al
sistema de gestión de hilos, siendo en ese momento cuando el sistema puede
desalojarle para planificar otro hilo.
La ventaja de la
planificación no apropiativa es que cualquier sección de código que no contenga
una llamada al sistema de gestión de hilos es automáticamente una sección crítica.
Así se pueden evitar cómodamente las condiciones de competencia. Por otro lado,
los hilos planificados de forma no apropiativa no pueden aprovechar los
sistemas multiprocesador, ya que se ejecutan de forma exclusiva. Es preciso
tener cuidado con las secciones de código grandes que no contengan llamadas al
sistema de gestión de hilos. El programador puede necesitar insertar
invocaciones que permitan que otros hilos puedan planificarse y progresar en su
trabajo. Los hilos planificados de forma no apropiativa no son aptos para su
uso en aplicaciones en tiempo real, ya que en éstas los eventos llevan
asociados tiempos absolutos en los que deben procesarse.
Implementación de hilos
En general cada
dominio de tiempo real tiene sus propios requisitos de planificación de hilos.
Es por lo tanto deseable que a veces las aplicaciones implementen sus propias
políticas de planificación.
Muchos núcleos dan
soporte para procesos multihilo de forma nativa. Estos núcleos proporcionan las
llamadas al sistema de creación y gestión de hilos, y planifican de forma
individual los hilos. Otros núcleos disponen únicamente de la abstracción de
procesos monohilo. Los procesos multihilo deben entonces implementarse en una
biblioteca de procedimientos enlazada a los programas de aplicación. En estos
casos el núcleo no conoce estos hilos de nivel de usuario y por lo tanto no
puede planificarlos independientemente. Una biblioteca en tiempo de ejecución
de hilos organiza su planificación. Un
hilo podría bloquear al proceso si se realiza una llamada bloqueante al
sistema, de forma que debe usarse la entrada - salida asíncrona del núcleo
subyacente. Análogamente la implementación puede utilizar los temporizadores
proporcionados por el núcleo y las posibilidades de interrupciones software
para realizar el uso compartido de los tiempos entre hilos.
Cuando el núcleo no
tiene soporte para procesos multihilo, las implementaciones al nivel de usuario
de los hilos adolecen de estos problemas: Los hilos de un cierto proceso no
pueden aprovecharse de la existencia de un multiprocesador. Un hilo que genera
una falta de página bloquea el proceso completo y todos los hilos dentro de él.
Los hilos de diferentes procesos no pueden planificarse de acuerdo a un único
criterio de prioridad relativa.
Sin embargo las
implementaciones de hilos del nivel de usuario tienen ventajas significativas
sobre las implementaciones al nivel núcleo: Algunas operaciones sobre hilos son
bastante más baratas. Por ejemplo la conmutación entre hilos pertenecientes al
mismo proceso no supone necesariamente una llamada al sistema, es decir, una
interrupción interna que es relativamente cara. Debido a que el módulo de
planificación de hilos se implementa fuera del núcleo, puede personalizarse de
forma que se adapte a los requisitos particulares de una cierta aplicación.
Pueden soportarse muchos más hilos de nivel de usuario de los que el núcleo
puede proporcionar por defecto.
Es posible
combinar las ventajas de las
implementaciones de hilos de nivel usuario y de nivel de núcleo. Una posible
aproximación es la de permitir al código de nivel de usuario proporcionar
indicaciones de planificación al planificador de hilos del núcleo. Otra
posibilidad es un tipo de planificación jerárquica. Cada proceso crea uno a más
hilos de nivel de núcleo. También soporta hilos de nivel de usuario. Un
planificado de nivel de usuario asigna cada hilo de nivel de usuario a un hilo
de nivel de núcleo. Este esquema puede explotar los multiprocesadores y se
beneficia del hecho de que algunas operaciones de creación y conmutación de
hilos se realizan al nivel de usuario. La desventaja de éste esquema es su
falta de flexibilidad: si un hilo se bloquea en el núcleo entonces a todos los
hilos de nivel de usuario asignados a él se les impide la ejecución,
independientemente de si tienen o no la posibilidad de ejecutarse.
Varios proyectos de
investigación han desarrollado esquemas de planificación jerárquica más
avanzados para obtener mayor eficiencia y flexibilidad. La idea conductora de
estos diseños es que un planificador de nivel de usuario no sólo necesita del
núcleo simplemente un conjunto de hilos soportados ya por el núcleo sobre los
que se puedan vincular hilos de nivel de usuario. El planificado de nivel de
usuario también necesita que el núcleo le notifique los eventos relevantes en
sus decisiones de planificación.
Diseño de
activaciones del planificador: Es una implementación de un sistema de
planificación jerárquico basado en eventos. Considera que los principales
componentes del sistema son un núcleo ejecutándose en un computador con uno o
más procesadores y un conjunto de programas de aplicación ejecutándose sobre
él. Cada proceso de aplicación contiene un planificador de nivel de usuario que
se encarga de gestionar los hilos dentro del proceso. El núcleo es responsable
de la asignación de procesadores virtuales de procesos. El número de
procesadores virtuales asignados a un proceso depende de diferentes factores
como los requisitos de la aplicación, sus prioridades relativas y la demanda
total en los procesadores. Se llaman procesadores virtuales porque el núcleo
puede asignar procesadores físicos diferentes a cada proceso a lo largo del
tiempo, mientras se garantice el número de procesadores asignados.
El número de procesadores
virtuales asignados a un proceso puede variar. Los procesos pueden devolver un
procesador virtual que han dejado de necesitar; además pueden solicitar
procesadores virtuales extra.
Una
activación del planificador es una llamada desde el núcleo a un proceso que
sirve para notificar al planificador del proceso la ocurrencia de un evento. El
núcleo crea una activación del planificador cargando los registros físicos del
procesador con un contexto que provoca la ejecución de código en el proceso, en
una dirección de procedimiento designada por el planificador de nivel de
usuario. Una activación del planificador puede de esta forma considerarse como
una unidad de asignación de tiempo en un procesador virtual. El planificador de
nivel de usuario tiene la tarea de asignar sus hilos preparados al conjunto de
activaciones del planificador que en
ese momento se están ejecutando en él. El número de activaciones del
planificador es como máximo el número de procesadores virtuales que el núcleo
ha asignado al proceso.
En cada uno de estos eventos, el núcleo esta notificando de estos eventos
al SA de notificación. Para crear un SA de notificación, el núcleo puede
asignar a un procesador virtual nuevo al proceso o bien apropiarse de otro SA
en mismo proceso, en el segundo caso la apropiación debe ser notificada para
así volver a recalcular las asignaciones correspondientes de hilos a SA.
El esquema de planificación jerárquica es más flexible ya que el
planificador de proceso de nivel de usuario puede asignar hilos a SA mediante
cualquier política de conjunto de eventos de bajo nivel. En tanto el núcleo
sigue con su comportamiento normal, ya que no influye en nada el comportamiento
del planificador de nivel de usuario, pero ayuda al planificador mediante la
notificación de eventos y proporcionando el estado de los registros de los
hilos bloqueados y desalojados.
En este punto nos concentraremos en la comunicación
como parte de la implementación de lo que hemos llamado una invocación, es
decir, construcción del tipo de las invocaciones remotas (llamadas a
procedimientos remotos o notificación de eventos) cuyo propósito es el de
efectuar una operación sobre un recurso en un espacio de direcciones
diferentes.
Ahora trataremos cuestiones importantes de diseño y
conceptuales de los sistemas operativos:
· Primitivas
de sincronización: Algunos núcleos diseñados para sistemas
distribuidos han proporcionado primitivas de comunicación, similares a los
diferentes tipos de invocación conocidos. La inserción de funcionalidad de
comunicación relativamente de alto nivel en el núcleo tiene la ventaja de la
eficiencia. Otro punto importante es el ahorro en la sobrecarga de las llamadas
al sistema tiende a ser mayor con la comunicación en grupo.
En la práctica, es el middleware y no el núcleo el
que proporciona la mayor parte de los recursos de comunicación de alto nivel
que aparece en los sistemas actuales, incluyendo RPC/RMI, notificación de
eventos y comunicación de grupos. El desarrollo de este software complejo es
más sencillo a nivel de usuario que desarrollarlo para el núcleo. Los
programadores normalmente implementan el middleware sobre los sockets proporcionando acceso a los protocolos estándar
de Internet, (TCP y UDP - protocolos de capa de transporte). Las principales
razones de utilizar sockets son la portabilidad e interoperabilidad que posee.
A pesar del amplio uso de sockets TCP y UDP proporcionado por los núcleos más
comunes, aun se sigue investigando para conseguir primitivas de comunicación
con menores costes sobre núcleos experimentales.
· Protocolos
y apertura: uno de los principales requisitos de los sistemas
operativos es el de proporcionar protocolos estándar que permitan la
intercomunicación entre implementaciones middleware sobre diferentes
plataformas. Algunos núcleos de investigación en la década de los ochenta (80’)
incorporaban sus propios protocolos de red ajustados para las interacciones con
RPC, sin embargo estos protocolos no fueron ampliamente usados fuera de sus
entornos de investigación nativos, y por ello los programadores decidieron
dejar la elección de los protocolos de red como una cuestión abierta. Estos núcleos proporcionan un sistema de
paso de mensajes únicamente entre procesos locales y dejan el procesamiento del
protocolo de red a un servidor que se ejecuta sobre el núcleo.
Dado los requisitos diarios de acceso a Internet, es
necesario que los sistemas operativos sean compatibles al nivel TCP y UDP para
todo, excepto para los dispositivos de red más pequeños. Además el sistema
operativo debe habilitar al middleware
para que pueda sacar partido de los nuevos protocolos de bajo nivel.
Los protocolos se organizan normalmente en una pila de
niveles, donde muchos de los sistemas operativos permiten la integración
estática de nuevos niveles, mediante la inclusión de un nivel como manejador
(Driver) de protocolo instalado permanentemente, por lo contrario se lo realiza
por la composición dinámica de protocolos, donde se ajusta de manera
automática. El soporte para la composición de protocolos apareció en el diseño
de los Streams de UNÍS (1984).
PRESTACIONES DE LA INVOCACION:
Las prestaciones de la invocación
son un factor crítico en el diseño de sistemas distribuidos. Cuanto más separan
los diseñadores de la funcionalidad entre espacios de direcciones, mas
invocaciones remotas se necesitan. Los clientes y servidores pueden realizar
muchos millones de operaciones asociadas a invocaciones a lo largo de su vida, de forma que pequeñas
fracciones de milisegundos son relevantes en los costes de invocación. Las
tecnologías de red continúan mejorando pero los tiempos de invocación no han
crecido en proporción al incremento del ancho de banda de las redes. Las
sobrecargas de software predominan a menudo sobre las cargas de la red en los
tiempos de invocación. Esto no ocurre en una invocación remota sobre Internet,
por ejemplo para solicitar un recurso Web. El ancho de banda es a menudo bajo y
la carga del servidor muchas veces predomina sobre los costes de procesamiento
para cada solicitud. Las implementaciones de RPC y RMI han sido un tema de
estudio debido a la amplia aceptación de estos mecanismos para el procesamiento
cliente-servidor de propósito general.
Elección del protocolo.
El retardo que sufre un cliente
durante las interacciones solicitud-respuesta sobre TCP no es peor que sobre
UDP en ocasiones es menor. El comportamiento del almacenamiento en TCP puede
impedir la obtención de buenas prestaciones, y sus sobrecargas de conexión son
una desventaja en comparación con UDP. Las sobrecargas de conexión de TCP son
particularmente evidentes en las invocaciones Web, debido a que HTTP 1.0
realiza una conexión TCP diferente en cada invocación. Además que en muchos
casos el algoritmo de arranque lento de TCP afecta retrasando la transferencia
de datos HTTP de forma innecesaria. Nielson encontró que la desactivación del
almacenamiento por defecto proporcionado por el sistema operativo podría tener
un impacto significativo en el retardo de invocación. Por esta razón el sistema
operativo no envía los datos sobre la red inmediatamente después de la llamada
de sockets write(). Nielson llego a la conclusión de que para el caso de HTTP
1.1 el comportamiento del almacenamiento por defecto del sistema operativo
podría causar significativos retardos innecesarios debidos a los tiempos
límites. Pare eliminar estos retardos la configuración del TCP en el núcleo
para forzar el envió a la red de cada solicitud HTTP de forma individual.
Invocación
dentro de un computador.
Bershad realizo un estudio de una
instalación examinada donde, la mayor parte de las invocaciones entre espacios
de direcciones se realizaban dentro de un computador y no, como en una
instalación cliente-servidor, entre diferentes computadores. En figura sugiere que
una invocación a un espacio de direcciones diferente se implementa dentro de un
mismo computador de la misma forma que entre computadores diferentes, excepto
en que el sistema de paso de mensajes subyacente actúa de forma local, este ha
sido a menudo el modelo implementado. Bershad desarrollo un mecanismo de
invocación más diferente, llamado RPC de peso ligero (LRPC, light weight RPC),
para el caso de dos procesos en la misma maquina. Se dieron cuenta que debería
ser más eficiente la utilización de regiones de memoria compartida para la
comunicación cliente-servidor, con una región diferente entre el servidor y
cada uno de sus clientes, esta
región contiene una o más pila A (de Argumento: vease la Figura). En LRPC, los
argumentos se copian una sola vez: cuando son empaquetados en la pila A. En un
RPC equivalente, son copiados cuatro veces: desde la pila del resguardo del
cliente hacia un mensaje; desde el mensaje al búfer del núcleo; desde el núcleo
al mensaje del servidor; desde el mensaje del servidor a la pila del resguardo
del cliente. Puede haber varias pilas A en una región compartida, debido a que
varios hilos en el mismo cliente pueden invocar al servidor al mismo tiempo. En
la figura se muestra una invocación, un hilo cliente entra en el entorno de
ejecución del servidor realizando una interrupción software hacia el núcleo y presentando al núcleo una
capacidad. El núcleo lo comprueba y permite un
ámbito de contexto hacia un procedimiento valido del servidor: si es
valido, el núcleo cambia el contexto del hilo para llamar al procedimiento en
el entorno de ejecución del servidor. Cuando el procedimiento en el servidor
termina, el hilo vuelve al núcleo, el cual cambia el hilo hacia atrás, hacia el
entorno de ejecución del cliente. Hay que resaltar que tanto los clientes como
el servidor emplean procedimientos resguardo pare ocultar a los programadores
de aplicaciones los detalles descritos.

Discusión
de LRPC.
Hay pocas dudas acerca de que LRPC es
más eficiente que RPC en el caso local, mientras se realicen suficientes
invocaciones. Bershad obtuvo valores de retardo pare LRPC menores en un factor
de tres que los valores de los RPC ejecutados de forma local. La transparencia
de ubicación no se sacrifica en la implementación de Bershad. Un resguardo del
cliente examina un bit actualizado durante el enlace que indica si el servidor
es local o remoto, y utiliza LRPC RPC
respectivamente. Las mejoras se refieren en su mayor parte a la eliminación de
interrupciones software hacia el núcleo y a la planificación de procesadores de
forma que se eliminen transiciones de dominio innecesarias. Por ejemplo si un
procesador esta ocioso en el contexto de gestión de memoria del servidor,
entonces el hilo debe transferirse a ese procesador, al mismo tiempo el
procesador del cliente puede ser usado por otro hilo en el cliente.
OPERACION ASINCRONICA
Hemos discutido como el sistema
operativo puede ayudar al nivel de middleware a proporcionar mecanismos de
invocación remota eficientes. Sin embargo, hemos observado que en el entorno de
Internet los efectos de las elevadas latencias, bajos anchos de banda y
elevadas cargas del servidor pueden superar cualquier beneficio que el sistema
operativo pueda proporcionar. A esto se le puede añadir el fenómeno de de
desconexión y reconexión de la red, que puede considerarse como el causante de
latencias de comunicación extremadamente elevadas. Los usuarios de computación
móvil no están conectados a la red todo el tiempo. Incluso si tienen acceso a
una red de área global sin hilos estarán obligatoriamente desconectados cuando,
por ejemplo, su tren entre en un túnel.
Una técnica muy utilizada para
vencer las latencias muy elevadas es la operación asíncrona, la cual aparece en
dos modelos de programación: invocaciones concurrentes e invocaciones
asíncronas.
Un buen ejemplo de este tipo de
aplicaciones son los navegadores Web. Una página Web normalmente contiene
varias imágenes. El navegador debe pedir cada una de estas imágenes en
solicitudes individuales de tipo HTTP GET (ya que los servidores Web HTTO 1.0
estándar únicamente soportan solicitudes para recursos individuales). El
navegador no necesita obtener las imágenes en una secuencia en particular, de
forma que realiza solicitudes concurrentes, normalmente hasta 4 a la vez. De
esta forma el tiempo empleado para completar todas las solicitudes de imágenes
es normalmente menor que el retardo en hacer las mismas solicitudes en serie.
Pero no solo se reduce el retardo de comunicación total ya que, en general, el
navegador puede solapar las actividades de computación de tipo de
representación de imágenes con la comunicación.
Una invocación asíncrona es aquella que
se realiza de forma asíncrona respecto al invocador. Es decir, se realiza con
una llamada no bloqueante, la cual retorna tan pronto como el mensaje de
solicitud de invocación ha sido creado y esta preparado para ser enviado.
Algunas veces el cliente no necesita
respuesta (excepto posiblemente una indicación de fallo si el nodo destino no
puede ser alcanzado). Por ejemplo, las invocaciones de una dirección de CORBA
tienen semántica pudiera. En caso contrario el cliente utiliza una llamada
separada para obtener los resultados de la invocación. Por ejemplo, el sistema
de comunicación Mercurio soporta invocaciones asíncronas. Una operación
asíncrona devuelve un objeto llamado promesa. Finalmente, cuando la invocación
tiene éxito o bien se considera que ha fallado, el sistema Mercury pone el
estado y cualquier valor de retorno en la promesa. El que invoca utiliza la
operación reclamación para obtener los resultados desde la promesa. La
operación reclamación se bloquea hasta que la promesa esta preparada, con lo
que devuelve los resultados o las excepciones desde la llamada. La operación
preparado esta disponible para comprobar una promesa sin necesidad de
bloquearse: devuelve cierto o falso de si la promesa esta preparada o
bloqueada.
INVOCACIONES ASINCRONAS
PERSISTENTES.
Los mecanismos de invocación
asíncrona tradicionales como las invocaciones Mercury y las invocaciones de una
dirección de CORBA son implementadas mediante streams TCP y fallan sin un
streams, es decir, si el enlace de red esta fuera de servicio o el noto destino
deja de funcionar.
Sin embargo, un modelo de invocación
asíncrona mas desarrollado, al que llamaremos invocación asíncrona persistente,
esta resultando cada vez más relevante debido a la operación desconectada. Este
modelo es similar a Mercury respecto a las operaciones de programación que
proporciona, pero la diferencia estriba en la semántica de fallos. Un mecanismo
de invocación convencional (síncrono o asíncrono) esta diseñado para fallar
después de que han ocurrido un cierto numero de timeouts. Sin embargo, a menudo
estos timeouts a corto plazo no son apropiados cuando se generan desconexiones
o latencias muy elevadas.
Un sistema de invocación asíncrona
persistente intenta realizar la invocación indefinidamente, hasta que puede
determinar que ha tenido éxito o ha fracasado, o hasta que la aplicación
cancela la invocación. Un ejemplo es QRPC (RPC en colas) en el conjunto de
herramientas Rover para acceso a información móvil.
Tal y como el nombre sugiere, QRPC
inserta en colas, realizando un registro estable, las solicitudes de
invocaciones salientes mientras no exista conexión de red y planifica las
operaciones que son enviadas a los servidores a través de la red cuando existe
conexión. De forma similar en colas en el servidor los resultados de las
invocaciones en lo que se puede considerar como el buzón de invocaciones del
cliente, hasta que el cliente vuelva a conectarse y los obtenga. Las
solicitudes y los resultados pueden comprimirse al insertarse en las colas,
antes de ser transmitidos sobre una red de pequeños anchos de banda.
Arquitectura del sistema operativo:
Sistema
distribuidos
Un sistema distribuido abierto
debería posibilitar lo siguiente:
La separación entre los mecanismos de gestión de
recursos fijos y la política de gestión de recursos, las cuales varían
entre diferente aplicaciones y entre diferente servicios, ha sido durante mucho
tiempo un principio guía en el diseño de los sistemas operativos.
Núcleo
monolítico y micro núcleo
En el diseño de los núcleos existen: la aproximación monolítica y el
micro núcleo. Estos diseños difieren básicamente en la decisión sobre que
funcionalidad pertenece al núcleo y que se deja al proceso servidor que puede
ser cargado dinámicamente para ejecutarse sobre él. A pesar de que el micro
núcleos no está extendidos. Es instructivo entender sus ventajase
inconvenientes comparándolos con los núcleos típicos existentes actualmente.
Un núcleo monolítico puede contener
algunos procesos servidores que se ejecutan dentro de su espacio de direcciones,
incluyendo servidores de archivos y de red. El código que ejecutan estos
procesos es parte de la configuración estándar del núcleo.
Monolítico: (Chambers), pilar o una columna
o una simple piedra: Cualquier cosa que recuerde la uniformidad de monolito, carácter masivo e inflexibilidad
Para el diseño del micro núcleo, el
núcleo proporciona únicamente las abstracciones más básicas, principalmente
espacio de direcciones, hilos y comunicación local entre procesos: el resto de servicio del sistema vienen dado por
servidores que se cargan dinámicamente, precisamente en aquellos computadores
del sistema distribuido que lo requieran.
Los clientes acceden a esos servicios del sistema utilizando los
mecanismos de innovación basados en mensajes proporcionados por el núcleo.
Además la extensibilidad, los
diseñadores de micro núcleos tienen otros objetivos: La emulación binaria de
sistemas operativos estándar como el Unix.
El micronúcleo aparece como un nivel
entre el hardware el que forman
los principales componentes del
sistema, llamados subsistemas. Si las prestaciones son el principal objetivo,
en lugar de la portabilidad, entonces el middleware puede utilizar directamente
los servicios del micronúcleo. En otro caso, utiliza un lenguaje con un subsistema
de soporte en tiempo de ejecución, o bien una interfaz de sistema
operativo de alto nivel proporcionado
por un subsistema de emulación de sistema operativo. Cada uno de ello se
implementa mediante una combinación de procedimiento de biblioteca enlazada
dentro de las aplicaciones y un conjunto de servidores ejecutándose sobre el
micro núcleo.
Puede existir más de una interfaz de llamadas a los sistemas (más
de unos sistemas operativos) a disposición del programador en la misma
plataforma. Esta situación es una reminiscencia de la arquitectura de la IBM
370, cuyo sistema VM puede presentar varias maquinas virtuales
completas a diferentes programas que se
ejecutan el mismo computador (monoprocesador).
Las principales
ventajas de un sistema operativo basado en micronúcleo son su extensibilidad y
su capacidad para hacer cumplir la modularidad por encima de los límites de
protección de memoria. La ventaja de un diseño monolítico es la eficiencia
relativa con que se invocan las operaciones. Las llamadas al sistema pueden ser
más caras que los procedimientos convencionales, e incluso utilizando algunas
técnicas, una invocación a un espacio de direcciones de nivel de usuario
separado en el mismo nodo es todavía más costosa.
La falta de estructura
en los diseños monolíticos puede evitarse utilizando ingeniería de Software
como ser el diseño por niveles o el diseño orientado a objetos. Windows NT
utiliza una combinación de ambos y sin embargo, sigue siendo masivo y la mayor
parte de su funcionalidad no está diseñada para ser reemplazada en forma
rutinaria. Incluso, un núcleo grande modularizado puede ser difícil de mantener
y proporciona un soporte muy limitado para un sistema distribuido abierto.
Mientras los módulos se ejecuten dentro de un espacio de direcciones utilizando
un lenguaje del tipo C o C++, que genera código con el objetivo de la
eficiencia pero permite acceso a datos de forma arbitraria, es posible un
abandono de la modularidad por parte de programadores que busquen implementaciones eficientes, y que un error
corrompa los datos de otro.
ALGUNAS APROXIMACIONES HÍBRIDAS
Dos de los
micronúcleos originales, Mach y Chorus, comenzaron su evolución ejecutando los
servidores únicamente como procesos de usuario, lo que aseguraba modularidad
por el hardware mediante los espacios de direcciones. Cuando los servidores
necesiten acceso directo al hardware se proporcionan llamadas especiales al
sistema para esos procesos privilegiados, las cuales vincularán registros de
dispositivos y bufferes sobre sus espacios de direcciones. El núcleo convierte
las interrupciones en mensajes que permiten el manejo de interrupciones a los
servidores de nivel usuario. Debido a problemas en las prestaciones, Mach y
Chorus cambiaron permitiendo a los servidores cargarse dinámicamente sobre el
espacio de direcciones del núcleo o sobre el espacio de direcciones de nivel
usuario. Los clientes interactúan con los servidores utilizando las mismas
llamadas de comunicación entre procesos. Un problema es que la depuración por
parte de un programador de un servidor a nivel de usuario, permitiéndole
ejecutarse dentro del espacio de direcciones del núcleo, amenaza la integridad
del sistema por cualquier error de programación.
El diseño del sistema
operativo SPIN, en cambio, afronta el problema de ceder eficiencia por
protección, mediante el empleo de servicios de protección en el lenguaje. El
núcleo y todos los módulos cargados dinámicamente al núcleo se ejecutan en un
único espacio de direcciones. Para estar mutuamente protegidos, todos ellos se
escriben en un lenguaje de tipos seguro como Modula-3 . Ningún módulo insertado
al núcleo puede acceder a un recurso amenos que fuera gestionada una referencia
a él y, Modula-3 fuerza el hecho de que una referencia sólo se puede utilizar
para operaciones permitidas por el programador. Para minimizar las dependencias
entre módulos, los diseñadores de SPIN eligen un modelo basado en eventos como
interacción entre módulos insertados en el espacio de direcciones del núcleo,
definiendo eventos centrales como ser llegada de un paquete a la red,
interrupciones del temporizador, faltas de página y cambio de estado en los
hilos. Los componentes se registran a sí mismos como manejadores de los eventos que los afectan. Por ejemplo,
un planificador se registrará como gestor de eventos del sistema de
activaciones del planificador.
Los sistemas
operativos del tipo Némesis explotan el hecho de que incluso a nivel de
hardware, un espacio de direcciones no es necesariamente un único dominio de
protección. Gracias a la llegada de procesadores de 64 bits que soportan
espacios de direcciones muy grandes, se emplea un único gran espacio de
direcciones donde coexisten módulos de sistema y aplicaciones cargados en
tiempo de ejecución, configurando
regiones individuales protegidas, con acceso completo a sus propias regiones y
compartido en forma selectiva a las demás.
Algunos diseños más
recientes como L4 y ExoKernel basados en micronúcleos contienen excesiva
política en relación con mecanismos. L4 obliga a los módulos a ejecutarse en
espacios de direcciones de nivel usuario pero optimiza la comunicación entre
procesos. ExoKernel, en cambio, se basa en el empleo de bibliotecas de nivel
usuario para generar las extensiones funcionales. Proporciona asignación protegida
de recursos esperando que las demás gestiones se realice mediante el enlace de
bibliotecas en las aplicaciones.
La cuestión todavía
pendiente estriba en cómo generar una arquitectura de sistema operativo lo
suficientemente extensible con buenas prestaciones en comparación con los
diseños monolíticos.

![]()
Número de visitantes actuales disponible desde el 14/07/2002:
Autor: lrmdavid@exa.unne.edu.ar
Ó FACENA - http://exa.unne.edu.ar
Servicios WEB: webmaster@exa.unne.edu.ar