Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Sistemas Operativos
Sistemas Operativos
Esta obra de Jesús Torres está bajo una Licencia Creative Commons
Atribución 4.0 Internacional. ISBN 978-84-695-9610-4
Índice de contenido
1. Introducción 1
1.1. ¿Qué hace un sistema operativo?..............................................................................................1
1.2. Tipos de sistemas operativos.....................................................................................................4
1.3. Historia de los sistemas operativos.........................................................................................10
3. Gestión de procesos 41
3.1. Procesos..................................................................................................................................41
3.2. Procesos cooperativos.............................................................................................................50
3.3. Hilos........................................................................................................................................67
3.4. Planificación de la CPU..........................................................................................................77
iii
Índices
iv
1. Introducción
Un sistema informático cualquiera puede ser dividido en cuatro componentes (véase la Figura 1.1):
el hardware, el sistema operativo, los programas de aplicación y los usuarios.
● El hardware –la CPU, la memoria, los dispositivos de entrada salida, etc.– proporcionan los
recursos computaciones del sistema.
● El sistema operativo controla y coordina el uso de hardware por parte de las diversas
aplicaciones para los diferentes usuarios del sistema. Un sistema operativo no hace trabajo
útil. Simplemente proporciona un entorno adecuado para que otros programas puedan
hacerlo.
Con el fin de entender cuáles son las funciones de un sistema operativo; se puede explorar su papel
desde dos puntos de vista: el del sistema informático y el del usuario.
Sistemas Operativos - 2014/2015 1. Introducción
sistema operativo
hardware
2. Programa encargado del control de la ejecución de los programas de usuario y del acceso a
los dispositivos de E/S.
Un sistema informático tiene múltiples recursos tanto hardware como software –tiempo de CPU,
espacio de memoria, espacio de almacenamiento de archivos, dispositivos de E/S, servicios de red,
etc.–. El sistema operativo, como gestor de estos recursos, los asigna a los diferentes programas,
resolviendo los conflictos en las peticiones y haciendo que el sistema opere eficientemente y
resuelva los problemas de los usuarios.
Además, como un programa encargado del control de la ejecución de los programas de los usuarios,
el sistema operativo tiene la tarea de prevenir errores y el uso inadecuado del ordenador.
1-2
1.1. Funciones del sistema operativo Sistemas Operativos - 2014/2015
(véase el apartado 1.3.2) disponen de monitor, teclado, ratón y una unidad central. Estos sistemas se
diseñan buscando la máxima productividad en equipos donde un usuario monopoliza todos los
recursos; por lo que el sistema operativo se diseña considerando fundamentalmente la facilidad de
uso, poniendo algo de atención en el rendimiento y nada en el aprovechamiento de los recursos.
Otro ejemplo son los sistemas de mano (véase el apartado 1.3.5), por ejemplo tablets y teléfonos
móviles. A causa de las limitaciones de la interfaz, en el diseño del sistema operativo debe primar la
usabilidad2, aunque el rendimiento por tiempo de vida de la batería también es importante.
Una definición mucho más común es que el sistema operativo es aquel programa que se ejecuta
continuamente en el ordenador –lo que denominamos comúnmente kernel o núcleo– siendo todo lo
demás programas del sistema y aplicaciones. Sin embargo, es indudable que en algunos casos ésta
definición no incluye como parte del sistema operativo algunas características que intuitivamente
solemos considerar dentro del mismo. Por ejemplo, si aplicamos esta definición a los sistemas
operativos de estructura microkernel (véase el apartado 2.3.3), no podríamos decir que servicios
como la comunicación en red, la gestión del sistema de archivos y la gestión de la memoria (véanse
1 Los terminales son sistemas informáticos utilizados para la conexión de los usuarios a un mainframe. Sólo suelen
disponer de los recursos necesarios para realizar esa tarea.
2 La usabilidad es la medida de la facilidad de uso de un producto o servicio, típicamente una aplicación software o un
aparato. Más información en http://es.wikipedia.org/wiki/Usabilidad.
1-3
Sistemas Operativos - 2014/2015 1. Introducción
el apartado 2.1.2) son proporcionados por el sistema operativo. Aunque pueda parecer lo contrario,
la cuestión de que incluye y que no incluye un sistema operativo no carece de importancia, como se
demostró durante el caso del Departamento de Justicia de los Estados Unidos contra Microsoft por
la excesiva inclusión de funcionalidades en sus sistemas operativos3.
Parece evidente que un sistema operativo se define mejor por lo que «hace» –es decir, sus
funciones– que por lo que «es». Sin embargo, ésta primera manera de definirlo también tiene sus
dificultades. Por ejemplo, el principal objetivo de los sistemas operativos de escritorio es la
facilidad de uso, mientras que en los mainframe el objetivo fundamental es la eficiencia en el
aprovechamiento de los recursos. Puesto que ambos objetivos pueden ser en ocasiones
contradictorios, resulta obvio que lo que tiene que «hacer» un sistema operativo para alcanzar esos
objetivos puede ser diferente en cada caso, lo que dificulta el obtener una definición única.
De lo que no hay duda es de que los sistemas operativos existen porque es más fácil hacer un
sistema informático usable con ellos que sin ellos. El objetivo fundamental de las computadoras es
ejecutar programas para resolver fácilmente los problemas de los usuario, por lo que con ese
objetivo se construye el hardware de los ordenadores. Puesto que el hardware por si sólo resulta
difícil de utilizar, es necesario desarrollar programas de aplicación para que sean utilizados por los
usuarios. Sin embargo, estas aplicaciones necesitan realizar operaciones comunes, como controlar
los dispositivos de E/S o reservar porciones de la memoria. Esas funciones comunes de control y
asignación de recursos, que se corresponden con las funciones del sistema operativo desde el punto
de vista del sistema informático vistas en el tema 1.1.1, son la labor del sistema operativo.
1.3.1. Mainframe
Los ordenadores centrales o mainframes fueron los primeros computadores utilizados en muchas
aplicaciones comerciales y científicas. Se caracterizan no tanto por la potencia de su CPU 4 como
por: su gran capacidad de memoria, su gran capacidad de almacenamiento secundario, la gran
1-4
1.3. Tipos de sistemas operativos Sistemas Operativos - 2014/2015
sistema operativo
área de los
programas de usuario
cantidad de dispositivos de E/S y la rapidez de estos, así como por su alta fiabilidad. Estas máquinas
pueden funcionar durante años sin problemas ni interrupciones y las reparaciones se realizan sin
detener su funcionamiento.
● La única tarea del sistema operativo era transferir automáticamente el control de un trabajo
al siguiente.
● El mayor inconveniente de éste tipo de sistemas era que la CPU permanecía mucho tiempo
desocupada porque era y es varios ordenes de magnitud más rápida que la E/S. Los programas
necesitan realizar operaciones de E/S para obtener los datos requeridos para sus cálculos –por
ejemplo guardados en tarjetas perforadas– por lo que se pierde mucho tiempo esperando a que
estén disponibles dichos datos.
1-5
Sistemas Operativos - 2014/2015 1. Introducción
b) Sistemas multiprogramados
Con la aparición de la tecnología de los discos magnéticos se pudo mantener todos los trabajos en el
disco y no en tarjetas perforadas sobre la mesa del operador. Esto permitió que el sistema operativo
pudiera encargarse de escoger el orden de ejecución de los trabajos.
3. En disco se almacena una cola con todos los trabajos que deben ser ejecutados.
4. El sistema operativo mantiene varios trabajos en memoria del conjunto de trabajos en la cola
en disco (véase la Figura 1.3).
7. Cuando un programa en la CPU termina, un hueco queda libre en la memoria. Por lo tanto es
necesario que el sistema operativo escoja un trabajo de la cola en disco y lo cargue en la
memoria.
Para seguir un esquema como el anterior es necesario que el sistema operativo realice tres tareas
esenciales:
● La planificación de la CPU. Se encarga de elegir el siguiente trabajo que debe ser ejecutado
en la CPU de entre los disponibles en la memoria (véase el apartado 3.4).
● La gestión de la memoria. Es necesaria puesto que la memoria tiene que ser repartida entre
los trabajos que deben ser alojados en la misma (véase el apartado 2.1.2).
Un ejemplo de este tipo de sistemas operativos es el IBM OS/360 que fue liberado en 1966 para
utilizarlo en los mainframes IBM System/360 (véase el apartado 1.4.3).
1-6
1.3. Tipos de sistemas operativos Sistemas Operativos - 2014/2015
Utilizando esta estrategia un sistema de tiempo compartido puede disponer de varios terminales de
forma que múltiples usuarios puedan utilizar la máquina simultáneamente 6. Los usuarios comparten
la CPU y los otros recursos del sistema, sin embargo, la sensación para cada uno es la de que el
sistema completo está dedicado a él en exclusiva. Realmente el sistema conmuta de un usuario a
otro –o para ser exactos de un programa a otro, pudiendo ser de usuarios distintos– pero debido a la
lentitud de la E/S interactiva7 los usuarios no perciben demora alguna.
Los sistemas de tiempo compartido significaron un salto importante en complejidad por diversas
razones:
● Varios trabajos deben estar en memoria al mismo tiempo el sistema operativo requiere
mecanismos de gestión de la memoria y protección (véase el apartado 2.1.2).
● Para tener un tiempo de respuesta razonable los trabajos en memoria deben poder ser
guardados o recuperados desde el disco que sirve como almacenamiento de respaldo el
sistema operativo puede utilizar técnicas de memoria virtual (véase el apartado 4.5.1) para
poder ejecutar trabajos que no están completamente cargados en memoria.
● La CPU debe ser compartida entre los trabajos el sistema operativo requiere mecanismos
de planificación de la CPU (véase el apartado 3.4).
● La ejecución de los trabajos debe ser ordenada el sistema operativo debe proporcionar
6 A los sistemas que tienen esta funcionalidad se los denomina sistemas multiusuario.
7 La E/S interactiva incluye la salida de datos por pantalla y la entrada de datos utilizando dispositivos como el
teclado, el ratón, etc. La velocidad de este tipo de E/S viene limitada por las capacidades humanas, por lo que hay
que tener en cuenta que lo que para los humanos es rápido para una CPU resulta sumamente lento.
1-7
Sistemas Operativos - 2014/2015 1. Introducción
● El sistema debe disponer de un sistema de archivos (véase el tema 5), que a su vez debe
residir en un conjunto de discos el sistema operativo requiere mecanismos de gestión de
discos.
Las primeras versiones de UNIX –liberado por primera vez en 1970– el sistema operativo VMS
–desarrollado en 1978– para los VAX de Digital Equipment Corportation y el IBM OS/400
–introducido en 1988– utilizado en los minicomputadores AS/400, son algunos ejemplos de
sistemas operativos de tiempo compartido (véase el apartado 1.4.4).
Pese a estas diferencias los sistemas operativos de escritorio se han beneficiado del desarrollo de
los sistemas operativos para mainframes. Por ejemplo, en un sistema diseñado para ser utilizado
por un único usuario no tiene sentido implementar un sistema de archivos con permisos. Por eso los
primeros sistemas operativos de escritorio carecían de esta característica, que ya existía en los
mainframe de la época. Sin embargo, hoy en día los sistemas de escritorio son multiusuario e
incluyen sistemas de archivos con permisos como medida de protección de los datos de los
usuarios.
Los ejemplos de este tipo de sistemas operativos van desde CP/M –lanzado en 1977– hasta los
actuales GNU/Linux, Microsoft Windows 7 y Apple Mac OS X, pasando por MS-DOS, IBM OS/2
y las diversas versiones de Microsoft Windows (véase el apartado 1.4.5).
8 El tiempo de respuesta al usuario se puede considerar como el intervalo de tiempo entre un comando de un usuario
–por ejemplo un click– y la respuesta del sistema a dicho comando. En ocasiones este tiempo se minimiza a costa de
un uso menos eficiente de los recursos del sistema por lo que no es un objetivo deseable para diseñar un mainframe.
Mas información en el tema 3.4.3.
1-8
1.3. Tipos de sistemas operativos Sistemas Operativos - 2014/2015
● En los sistemas cliente-servidor existen ordenadores que actúan como servidores encargados
de satisfacer las peticiones generadas por otros ordenadores que actúan como clientes. Este
tipo de sistemas ha ido sustituyendo a los terminales conectados a mainframes debido a que
los sistemas de escritorio son cada vez más potentes y más baratos. Concretamente, los
terminales han sido sustituidos por los sistemas de escritorio que, al disponer de más recursos,
son capaces de realizar muchas de las funcionalidades que anteriormente eran manejadas
directamente por los mainframes. Al mismo tiempo estos mainframes se han reemplazado por
servidores, no muy diferentes a los sistemas de escritorios, pero preparados para atender las
peticiones de sus clientes. Ejemplos de este este tipo de sistemas son los servidores de base de
datos, que responden a las consultas SQL de los clientes, o los servidores de archivos, que
proporcionan una interfaz de sistema de archivos con la que los clientes pueden crear, leer,
escribir y borrar archivos en el servidor.
9 Un servidor puede ser el cuello de botella no solo por su potencia sino también por el ancho de banda de su
conexión a la red. La potencia del servidor es lo de menos cuando se intenta distribuir en Internet archivos de gran
tamaño –por ejemplo imágenes de CD o DVD– pues el problema es que varias descarga simultaneas pueden
consumir todo el ancho de banda del servidor durante largos periodos de tiempo.
1-9
Sistemas Operativos - 2014/2015 1. Introducción
● Los sistemas operativos de red ofrecen a las aplicaciones que corren sobre ellos servicios de
acceso a redes de ordenadores. Por ejemplo, implementan algún mecanismo que permita a
diferentes procesos en diferentes ordenadores intercambiar mensajes. Además suelen
incorporar la opción de proporcionar algunos servicios de red, como la compartición de
archivos y dispositivos. Los ordenadores con sistemas operativos de red son autónomos,
aunque conocen la existencia de la red y están en disposición de comunicarse con otros
ordenadores de la misma. Este tipo de sistemas operativos son los más utilizados en los tipos
de sistemas distribuidos comentados anteriormente.
Los sistema de tiempo real están muy relacionados con los sistemas empotrados. Estos sistemas
están tanto en el motor de los automóviles y los robots que los fabrican, como en reproductores de
10 Amoeba es un sistema operativo de investigación distribuido de estructura microkernel (véase el apartado 2.3.3)
escrito por Andrew S. Tanenbaum en Vrije Universiteit. Más información en http://www.cs.vu.nl/pub/amoeba/.
1-10
1.3. Tipos de sistemas operativos Sistemas Operativos - 2014/2015
DVD, microondas, etc. Los sistemas empotrado realizan tareas muy específicas, sus sistemas
operativos tienen características muy limitadas y no suelen tener interfaz de usuario.
Los sistemas de tiempo real pueden ser clasificados en sistemas de tiempo real estricto y sistemas
de tiempo real flexible:
● Los sistemas de tiempo real estricto o hard real-time garantizan que las tareas serán
realizadas dentro de unos márgenes estrictos de tiempo. Para ello todos los imprevistos que
puedan ocasionar retardos en el funcionamiento del sistema operativo deben estar
perfectamente limitados en tiempo. Por lo tanto, la memoria virtual y otras facilidades que
abstraen del funcionamiento real del hardware no están presentes en este tipo de sistemas
porque introducen impredecibilidad. Los sistemas de tiempo real estricto no son compatibles
con los sistemas de tiempo compartido.
● Los sistemas de tiempo real flexible o soft real-time son útiles cuando hay tareas que tienen
mayor importancia que el resto por lo que deben ser realizadas con mayor prioridad y esta
prioridad debe ser conservada hasta que terminan. El tiempo real flexible no sirve cuando se
tienen tareas con limitaciones precisas de tiempo porque no hay manera de garantizar que
dichas restricciones se van a cumplir. Sin embargo si es útil para tareas relacionadas con la
multimedia, la realidad virtual, etc. Este tipo de tiempo real está disponible en la mayor parte
de los sistemas operativos de propósito general pues es compatible con la memoria virtual y
otras facilidades propias de los sistemas de tiempo compartido.
1-11
Sistemas Operativos - 2014/2015 1. Introducción
a) Características
● Sin sistema operativo.
b) Ejemplos
● Mainframe IBM 701 y 704.
a) Características
● Sistemas operativos de procesamiento por lotes.
b) Ejemplos
● El primer sistema operativo fue desarrollado por General Motors Research Laboratory en 1956
para su mainframe IBM 701 (véase la Figura 1.4) con el fin de automatizar la carga de los
trabajos.
a) Características
● Sistemas operativos multiprogramados.
b) Ejemplos
● IBM OS/360. Desarrollado por IBM para su mainframe System/360.
1-12
1.4. Historia de los sistemas operativos Sistemas Operativos - 2014/2015
○ Anunciado en 1964, fue liberado en 1966 con un año de retraso. Los motivos
fundamentales fueron ciertos problemas de organización interna de la compañía y la
falta de experiencia en proyectos de tal envergadura, pues las previsiones iniciales eran
de 1 millón de líneas de código y miles de componentes de software. La experiencia
negativa del desarrollo del IBM OS/360 condujo al nacimiento de la ingeniería del
software.
1.4.4. 4ª Generación
Esta generación abarca desde mediados de los años 60 hasta finales de la década de los 70.
a) Características
● Sistemas operativos de tiempo compartido.
1-13
Sistemas Operativos - 2014/2015 1. Introducción
Figura 1.5: Mainframe GE-6180 con sistema operativo MULTICS (MIT ca. 1976)
b) Ejemplos
● MULTICS. Fue anunciado en 1964 como el primer sistema operativo de propósito general
fruto de la colaboración entre el MIT, General Electrics y Bell Labs (véase la Figura 1.5).
1-14
1.4. Historia de los sistemas operativos Sistemas Operativos - 2014/2015
1-15
Sistemas Operativos - 2014/2015 1. Introducción
● UNIX. Desarrollado originalmente por Bell Labs en 1970 para los sistemas PDP-11/20.
○ Una de las más importantes versiones de UNIX fue desarrollada por la Universidad de
California en Berkeley. Esta versión implementaba el estándar de comunicaciones
TCP/IP, el cual permitió convertir la cerrada ARPANET en la abierta Internet.
○ En la actualidad se puede considerar que hay dos grandes familias de UNIX. Por un lado
AT&T UNIX System V, del que derivan sistemas tales como SCO OpenServer,
Oracle/Sun Microsystems Solaris Operating Environment y SCO UnixWare. Y por el
otro, BSD11 del que derivan FreeBSD, NetBSD, OpenBSD, Darwin y DragonFly BSD,
entre muchos otros.
● IBM OS/400. Es un sistema utilizado en la familia IBM AS/400 –ahora llamada iSeries–.
1-16
1.4. Historia de los sistemas operativos Sistemas Operativos - 2014/2015
hace referencia a máquinas multiusuario de rango medio, entre los mainframes y los
sistemas de escritorio.
a) Características
● Sistemas operativos de escritorio y ordenadores personales (PC)12.
b) Ejemplos
● CP/M. Sistema operativo estándar para la primera generación de microcomputadores13.
○ Creado por Digital Research, Inc., fundada por Gary Kildall, para ser el sistema
operativo de los microordenadores basados en Intel 8080/85 y Zilog Z80.
○ La combinación del CP/M junto al bus S-100 en el MITS Altair 8800 14 fue el primer
estándar industrial.
○ Fue el primer sistema operativo del IBM PC –lanzado en 1981– y durante mucho tiempo
fue ampliamente utilizado en la plataforma PC compatible. No era ni multitarea ni
multiusuario.
○ MS-DOS fue creado por Seattle Computer Products con el nombre de 86-DOS, pero era
comúnmente conocido como QDOS (Quick and Dirty Operating System). Microsoft
adquirió el sistema y lo vendió a IBM con el nombre de MS-DOS.
○ Tanto IBM como Microsoft lanzaron versiones de DOS, aunque originalmente IBM
12 Se puede observar una muestra de la interfaz gráfica de usuario de algunos estos sistemas en http://goo.gl/0fFLN
13 Una microcomputadora es un ordenador que tiene un microprocesador. La primera generación de
microcomputadoras también fue conocida como computadoras domésticas.
14 El MITS Altair 8800 fue un microcomputador diseñado en 1975 basado en el procesador Intel 8080A. Hoy en día es
considerado el primer ordenador personal de la historia. Su bus de sistema, el S-100, se convirtió en un estándar de
facto y su primer lenguaje de programación fue el producto que ayudó a fundar Microsoft, el Altair BASIC.
1-17
Sistemas Operativos - 2014/2015 1. Introducción
● OS/2. Sistema operativo creado por Microsoft e IBM y posteriormente desarrollado por IBM
en exclusiva. Se creó como el sistema operativo predilecto para la segunda generación de
ordenadores personales de IBM, equipados con procesador Intel 80286.
○ OS/2 fue pensado como un sucesor con operación en modo dual (véase el apartado
2.2.1) de MS-DOS y Microsoft Windows 2.0.
○ OS/2 1.0 fue anunciado en abril y liberado en diciembre de 1987 como un sistema
operativo en modo texto. La interfaz gráfica de usuario prometida –denominada
Presentation Manager– se introdujo en la versión 1.1 en noviembre de 1988.
○ OS/2 Warp 4, fue liberado en 1996. Poco después de su lanzamiento IBM anunció que
OS/2 desaparecería.
● Windows 3.x. La familia Windows 3.x de Microsoft Windows fue desarrollada desde 1990
hasta 1994. La 3.0 fue la primera versión de éxito de Windows, permitiendo a Microsoft
competir con el Macintosh de Apple Computer y el Commodore Amiga.
○ Windows 3.x requería una instalación previa de MS-DOS y era iniciado como un
programa más, que podía ser terminado en cualquier momento devolviendo al usuario a
1-18
1.4. Historia de los sistemas operativos Sistemas Operativos - 2014/2015
● Windows 95, 98, Me. Sistemas operativos híbridos gráficos de 16-bit/32-bit sucesores de
Windows 3.x.
○ Windows 95, liberado en 1995, fue el primer Windows unido a una versión de MS-DOS
específica; aunque este hecho se intentaba mantener oculto. Entre las características de
Windows 95 se pueden destacar: mejoras significativas en la interfaz de usuario,
nombres de archivo de hasta 256 caracteres con conservación de mayúsculas y
minúsculas y multitarea expropiativa (véase el apartado 3.4.1) para las aplicaciones de
32-bit.
○ Su desarrollo empezó en 1988 con el nombre de OS/2 3.0. Cuando Windows 3.0 fue
liberado en mayo de 1990 tuvo tanto éxito que Microsoft decidió cambiar la API 15 del
aún en desarrollo NT OS/2 –como era conocido en la época– pasando de ser una versión
extendida de la API de OS/2 a una versión extendida de la API de Windows. Esta
decisión causó tensión entre Microsoft e IBM y provocó que finalmente la colaboración
terminara.
15 Una interfaz de programación de aplicaciones o API (del inglés application programming interface) es el conjunto
de funciones, procedimientos o métodos que ofrece el sistema operativo para ser utilizado por las aplicaciones.
1-19
Sistemas Operativos - 2014/2015 1. Introducción
crear Windows NT, por lo que muchos de sus elementos reflejan la experiencia anterior
de DEC en VMS.
○ Las API soportadas por Windows NT –por ejemplo Win32, POSIX y OS/2 2.1– son
implementadas como subsistemas encima de un API nativo públicamente no
documentado. Esta estructura en subsistemas fue lo que permitió la adopción tardía de la
API de Windows, tal y como hemos comentado anteriormente.
○ Windows NT 3.1 –la primera versión de Windows NT, liberada el 13 de julio de 1993–
era un sistema operativo microkernel (véase el apartado 2.3.3) multiplataforma que
corría sobre procesadores Intel IA-32, DEC Alpha, MIPS R4000 y PowerPC.
○ Windows NT 4.0 fue la última versión en soportar plataformas distintas a Intel IA-32.
Aunque el desarrollo de Windows 2000 para Alpha continuó hasta 1999, cuando
Compaq dejó de soportar Windows NT en esa arquitectura. Además Windows NT 4.0
integró en el núcleo más funciones –por ejemplo parte del subsistema gráfico– para
obtener mayor rendimiento.
● GNU/Linux. Se trata del más famoso ejemplo de software libre y de desarrollo de fuente
abierta.
○ El proyecto GNU se inició en 1983 con el fin de desarrollar un sistema operativo estilo
UNIX, incluyendo herramientas de desarrollo de software y aplicaciones de usuario,
hecho enteramente de software libre.
○ El núcleo Linux fue inicialmente escrito como hobby por el estudiante universitario finés
1-20
1.4. Historia de los sistemas operativos Sistemas Operativos - 2014/2015
○ En 1991, cuando se liberó la primera versión del núcleo Linux, el proyecto GNU había
desarrollado todos los componentes necesarios del sistema excepto el núcleo. Torvalds y
otros desarrolladores rápidamente adaptaron Linux para que funcionara con los
componentes de GNU, creando un sistema operativo completamente funcional.
○ El núcleo fue licenciado bajo la GNU General Public License (GPL) pero no es parte del
proyecto GNU. El proyecto GNU tiene su propio kernel denominado Hurd, pero sigue
en desarrollo.
○ En algún momento se pensó que Mach podría dominar el universo de los sistema
operativos debido a las ventajas de los sistemas microkernel. El mayor esfuerzo para
conseguirlo hasta la fecha es GNU/Hurd pero lleva más de una década de retraso. Sin
embargo, otros sistemas operativos microkernel han tenido más éxito, como es el caso de
QNX.
○ Apple Computers seleccionó OpenStep como base para el sucesor de su clásico Mac OS.
OpenStep es realmente una versión actualizada de NeXTSTEP, que era un sistema
basado en un núcleo Mach 2.5 con porciones del sistema BSD de la Universidad de
Berkeley. Por lo tanto, la mezcla de Mach con BSD16 de OpenStep es la base del sistema
operativo Mac OS X de Apple.
16 A la base del sistema operativo Mac OS X se la denomina Darwin. Concretamente se trata de un sistema FreeBSD
portado para correr sobre el núcleo Mach.
1-21
1956 1976 1991 2001
1952 Linux
Primer sistema operativo. CP/M GNU Hurd El núcleo libre Windows XP
Mainframe General Motors Research S.O. de la 1ª generación Núcleo del más utilizado con Su versión Home
IBM 701 Laboratory. Para IBM 701. de micro ordenadores. proyecto GNU. el proyecto GNU. extinguió la
familia de
Windows 9x.
1964 1966 1988
1945 1995
Multics IBM OS/360 OS/2
Primer sistema de Nace la ingeniería del Sistema de 16bits Windows 95
propósito general. software. pensado como Familia de sistemas
sucesor de MS-DOS operativos híbridos
1970 1978
de 16/32bits.
1955 1964 1985
Digital VMS 1994
UNIX
Para VAX. Mach
Núcleo microkernel OS/2 3.0
de la CMU. Sistemas operativo
de IBM de 32bits.
1965 1983
1993
UNIX System V Proyecto GNU
1ª Generación Proyecto de Windows NT 3.1
UNIX BSD software libre. Llamado NT OS/2
Sin sistema operativos
ni lenguajes de programación 2ª Generación hasta que IBM
Sistemas operativos de 1981 abandonó el
1968 proyecto al Microsoft
procesamiento por lotes
4ª Generación MS-DOS sustituir la API OS/2
Uso de lenguajes por la API Win32.
de programación
S.O. del IBM PC.
Sistemas operativos de
tiempo compartido
Hay programas interactivos
y máquinas virtuales 1980
3ª Generación 5ª Generación
Sistemas operativos Sistemas de escritorio
multiprogramados
Monousuario y multiusuario, multitarea, sistemas distribuidos,
Más lenguajes de programación, sistemas en cluster, sistemas de tiempo real, etc.
multiprogramación
2. Estructura de los sistemas operativos
1. Los componentes del sistema operativo y sus interconexiones (véase el apartado 2.1.2).
2. Los servicios que el sistema operativo proporciona a través del funcionamiento coordinado de
dichos componentes (véase la Figura 2.1).
El estudio de los componentes del sistema operativo lo dejaremos para más adelante, tras ver la
forma usual en la que los programas acceden a los servicios del sistema operativo y, por tanto, en la
que se comunican indirectamente con dichos componentes. Respecto a los servicios que el sistema
operativo proporciona, no entraremos en ello puesto que cada uno ofrece servicios diferentes,
aunque siempre es posible identificar unos pocos tipos comunes a todos.
aplicaciones
servicio de servicio de
servicio de servicio de
operaciones con manipulación de
ejecución de programas operaciones de E/S
la memoria archivos
gestor del
gestor del sistema
gestor de procesos gestor de memoria gestor de E/S almacenamiento
de archivos
secundario
hardware
entorno debe proporcionar ciertos servicios que pueden ser accedidos por los programas a través de
una interfaz de programación de aplicaciones o API (Application Programming Interface).
Algunas de las APIs disponibles para los desarrolladores de aplicaciones son la API Win32 –en
sistemas Microsoft Windows– y la API POSIX para sistemas compatibles POSIX 17 –como es el
caso de los diferentes UNIX, Linux y Mac OS X–.
Las librerías estándar necesitan acceder a los servicios del sistema operativo para, a su vez, dar
servicio a los programas que las usan. Es decir, cuando un programa invoca alguna función o
método de la librería estándar que lo acompaña, es muy probable que ésta necesite invocar uno o
más servicios del sistema operativo para atender la petición convenientemente. Para ello las
17 POSIX (Portable Operating System Interface for Unix) es el nombre de una familia de estándares que definen una
interfaz de programación de aplicaciones para sistemas operativos. Esto permite que un mismo programa pueda ser
ejecutado en distintas plataformas, siempre que sean compatibles con POSIX. La práctica totalidad de los sistemas
UNIX modernos son compatibles POSIX ya que la especificación deriva de la interfaz típica de ese tipo de sistemas.
2-24
2.1. Organización de los sistemas operativos Sistemas Operativos - 2014/2015
librerías estándar utilizan la librería del sistema –o librerías del sistema, en el caso de que hayan
varias– que acompaña al sistema operativo. La librería del sistema si forma parte del sistema
operativo y contiene un conjunto de clases y/o funciones –generalmente más primitivas que las de
la librería estándar de los lenguajes de programación– que los programas deben utilizar para
acceder a los servicios del sistema operativo. Es decir, la librería del sistema constituye la interfaz
de programación de aplicaciones del sistema operativo. Es muy común que esta interfaz esté
implementada para ser usarla con programas en lenguaje C, lo que permite que tanto los programas
en C como en C++ la puedan utilizar directamente. Sin embargo con otros lenguajes de
programación esto no suele ser posible, por lo que no queda más remedio que acceder a los
servicios del sistema operativo a través de la librería estándar del lenguaje en cuestión.
Algunos de los servicios ofrecidos pueden ser implementados en la propia librería del sistema pero
en la mayor parte de los casos ésta debe solicitar dichos servicios al resto del sistema operativo. La
librería del sistema, al igual que la estándar y otras librerías utilizadas por el programa, se cargan
dentro de la región de memoria asignada al proceso donde se ejecuta el programa que las utiliza.
Por lo tanto, la invocación de sus métodos y funciones se realiza como si fueran cualquier otro
método o función del programa. Sin embargo el código del núcleo del sistema operativo suele estar
en una ubicación diferente que, desde el punto de vista de los programas, no es conocida y
generalmente está protegida frente a accesos indebidos (véase el apartado 2.2.2). Eso significa que
#
# Fragmento de código para escribir SIZE bytes desde la dirección BUFFER al
# archivo con el descriptor FILEDES.
#
# Prototipo en C de la llamada al sistema write()
#
# ssize_t write (int FILEDES, const void *BUFFER, size_t SIZE)
#
# ...
lw $a0,FILEDES # cargar FILEDES
la $a1,BUFFER # cargar BUFFER
lw $a2,SIZE # cargar SIZE
li $v0,4 # cargar id. de la llamada write()
syscall # llamar al sistema
# v0 contiene el valor de retorno
# que es el número de bytes escritos
# ...
2-25
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
para que la librería del sistema invoque los servicios que necesita hace falta un procedimiento
diferente, al que se le denomina llamada al sistema.
Las llamadas al sistema proporcionan una interfaz con la que los procesos pueden invocar los
servicios que el sistema operativo ofrece. Estas llamadas están habitualmente disponibles como
instrucciones en lenguaje ensamblador (véase la Figura 2.2) pero generalmente los programas no las
utilizan directamente sino que emplean la interfaz ofrecida por la librería del sistema, que su vez se
implementa mediante invocaciones a las llamadas al sistema.
En la Figura 2.3 se ilustra el papel de todos los elementos comentados con el ejemplo de un
programa en C++ que invoca el método std::ofstream::open():
2. La librería estándar utiliza la librería de sistema, de la que invoca a varias funciones, para
realizar la tarea encomendada. Entre las funciones llamadas está fopen(), que se utiliza para
abrir el archivo indicado.
sistema operativo
llamada al sistema
fopen()
std::ofstream::open()
ofstream ofs;
ofs.open(filename); programa en C++
proceso
2-26
2.1. Organización de los sistemas operativos Sistemas Operativos - 2014/2015
3. La librería del sistema utiliza los servicios del sistema operativo, expuestos mediante la
interfaz de llamadas al sistema, para realizar la tarea encomendada por la invocación de
fopen(). Entre las llamadas al sistema utilizadas está open, que le dice al sistema operativo
4. Al realizar la llamada el sistema operativo toma el control deteniendo la ejecución del proceso
que la solicita. Entonces se realiza la tarea mediante el funcionamiento coordinado de los
diferentes componentes del sistema (véase el apartado 2.1.2).
Sin embargo, una llamada al sistema suele requerir más información que simplemente la identidad
de la llamada. Si por ejemplo se quisiera leer un bloque de datos desde un almacenamiento
secundario, al menos se debería indicar el archivo o dispositivo desde el que se desea realizar la
lectura, así como la dirección y tamaño de la región de la memoria donde se quiere que los datos
sean copiados. En concreto hay tres métodos para pasar parámetros a una llamada al sistema:
18 Una excepción es una interrupción generada por software, que puede ser debida a un error –por ejemplo una división
por cero o un acceso no válido a memoria– o a una llamada al sistema de un proceso para que se ejecute un servicio
del sistema operativo.
19 En GNU/Linux se puede conocer el número correspondiente a cada llamada al sistema soportada por el núcleo
consultado el listado del archivo /usr/include/asm/unistd.h.
20 IA-32 (Intel Architecture, 32-bit), conocida en la actualidad de manera genérica como x86 o i386, es la arquitectura
del conjunto de instrucciones de los procesadores Intel de 32 bits. Concretamente es una extensión de 32 bits,
implementada por primera vez en el Intel 80386, para la arquitectura x86 original de 16 bits.
2-27
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
sistema en una tabla en memoria, de manera que la dirección de dicha tabla debe ser cargada
en un registro de la CPU antes de la llamada al sistema. Evidentemente no limita el número de
parámetros que pueden ser pasados a una llamada al sistema. Por ejemplo, es utilizado en
Linux IA-32, cuando la llamada al sistema tiene más de cinco parámetros, y en Microsoft
Windows.
En cualquier caso, sea cual sea el método utilizado, el sistema operativo debe comprobar de
manera estricta los parámetros pasados en la llamada al sistema antes de realizar cualquier
operación, puesto que nunca debe confiar en que los procesos hagan su trabajo correctamente. A fin
de cuentas una de las funciones del sistema operativo es el control de dichos procesos.
a) Gestión de procesos
La gestión de los procesos es un elemento central de todo sistema operativo ya que el proceso es la
unidad de trabajo en cualquier sistema operativo moderno:
● Un proceso puede ser considerado como un programa en ejecución, es decir, cuando las
instrucciones del programa son ejecutadas por una CPU. Un proceso es un entidad activa que
necesita recursos –CPU, memoria, archivos, E/S– que se le asignan cuando es creado o cuando
lo solicita durante la ejecución. Cuando el proceso termina el sistema operativo reclama de
estos recursos aquellos que sean reutilizables.
2-28
2.1. Organización de los sistemas operativos Sistemas Operativos - 2014/2015
ningún tipo de trabajo a menos que sus instrucciones sean ejecutadas por una CPU pero si eso
ocurre, ya no sería un programa sino un proceso.
● La CPU ejecuta las instrucciones de cada proceso una detrás de otra, de manera que para
conocer la siguiente instrucción a ejecutar cada proceso tiene un contador de programa que se
lo indica a la CPU. Por tanto, aunque dos procesos estén asociados al mismo programa no
pueden ser considerados el mismo proceso, ya que la secuencia de ejecución de instrucciones
puede ser distinta al tener cada uno un contador de programa independiente.
Por el momento estamos considerando que proceso y trabajo (véase el apartado 1.3.1) hacen
referencia al mismo concepto. Sin embargo más adelante veremos que el segundo es mucho más
general que el primero puesto que un proceso puede colaborar con otros procesos para desarrollar
un trabajo determinado (véase el apartado 3.1.7).
2-29
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
● Decidir que procesos añadir o extraer de la memoria cuando hay o falta espacio en la misma.
21 El término primitivas hace referencia a funciones que realizan operaciones muy básicas. Estas operaciones básicas
pueden ser combinadas para realizar operaciones más complejas.
2-30
2.1. Organización de los sistemas operativos Sistemas Operativos - 2014/2015
● Una interfaz genérica de acceso a los controladores de dispositivo. Esta interfaz genérica hace
que el acceso de los procesos a los dispositivos sea a través de una interfaz similar, sin
importar las particularidades de cada dispositivo. Por ejemplo, una característica de los
sistemas UNIX es que cada dispositivo de E/S se representa como un archivo en el sistema de
archivos. Esto permite que los procesos utilicen para acceder a los dispositivos de E/S las
mismas primitivas que emplean para manipular los archivos.
● Controladores de dispositivo que son quiénes conocen las peculiaridades específicas del
dispositivo para el que ha sido creado.
22 El buffering o uso de memoria intermedia es una estrategia para leer datos desde un dispositivo de E/S. La CPU
instruye al dispositivo para que escriba bloques de datos en la memoria de forma que la operación se realiza
mientras la CPU está ocupada procesando los bloques leídos anteriormente desde el dispositivo. Al escribir en un
dispositivo de E/S el proceso es análogo.
23 En el caching el sistema mantiene en la memoria principal una copia de los datos almacenados en los dispositivos de
E/S del sistema como, por ejemplo, en los discos. Esto mejora la eficiencia del sistema puesto que el acceso a la
memoria principal es más rápido que el acceso a los dispositivos de E/S. La memoria principal es de tamaño
limitado, por lo que sólo se mantiene copia de los datos utilizados con mayor frecuencia.
24 El spooling se utiliza en dispositivos que no admiten el acceso simultaneo de varias aplicaciones a vez, como es el
caso de impresoras y unidades de cinta. Cuando varias aplicaciones intentan enviar un trabajo a una impresora el
sistema operativo lo intercepta para copiar los datos enviados a un archivo distinto para cada aplicación. Cuando una
aplicación termina de enviar el trabajo el archivo correspondiente es encolado para su impresión. Así los archivos
son impresos de uno en uno.
2-31
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
f) Gestión de red
El componente de red se responsabiliza de la comunicación entre los procesadores en sistemas
interconectados mediante una red de ordenadores –por ejemplo en Internet o la red de área local de
una oficina–.
g) Protección y seguridad
Protección es cualquier mecanismo para controlar el acceso de los procesos y usuarios a los
recursos definidos por el sistema. Estos son necesarios cuando un sistema informático tiene
múltiples usuarios y permite la ejecución concurrente de varios procesos, pues así sólo pueden
utilizar los recursos aquellos procesos que hayan obtenido la autorización del sistema operativo.
Además la protección también permite mejorar la fiabilidad al permitir detectar los elementos del
sistema que no operan correctamente. Un recurso desprotegido no puede defenderse contra el uso
–o mal uso– de un usuario no autorizado o incompetente.
En todo caso, un sistema puede tener la protección adecuada pero estar expuesto a fallos y permitir
accesos inapropiados. Por eso es necesario disponer de mecanismos de seguridad que se encarguen
de defender el sistema frente a ataques internos y externos. Eso incluye a virus y gusanos, ataques
2-32
2.1. Organización de los sistemas operativos Sistemas Operativos - 2014/2015
de denegación de servicio25, robo de identidad y uso no autorizado del sistema, entre muchos otros
tipos de ataque.
● Interfaz de línea de comandos o intérprete de comandos, que permite que los usuarios
introduzcan directamente los comandos que el sistema operativo debe ejecutar. En algunos
sistemas este tipo de interfaz se incluye dentro del núcleo, pero en la mayor parte –como
MSDOS y UNIX– se trata de un programa especial denominado shell que se ejecuta cuando
un usuario inicia una sesión.
● Interfaz de proceso por lotes, en la que los comandos y directivas para controlar dichos
comandos se listan en archivos que posteriormente pueden ser ejecutados. Este tipo de interfaz
es la utilizada en sistemas no interactivos, como los de procesamiento por lotes y los
multiprogramados. También suele estar disponible en los sistemas de tiempo compartido, junto
con algún otro tipo de interfaz de usuario, como es el caso de la shell de los sistemas UNIX.
● Interfaz gráfica de usuario o GUI (Graphical User Interface) que permite a los usuarios
utilizar un sistema de ventanas y menús controlable mediante el ratón.
Puesto que la interfaz de usuario puede variar de un sistema a otro, y de un usuario a otro dentro del
mismo sistema, no se suele incluir como un componente básico del sistema operativo, pero si como
un servicio útil para los usuarios.
A parte de la interfaz de usuario, cualquier sistema operativo moderno incluye una colección de
programas del sistema. El papel de estos programas del sistema es proporcionar un entorno
conveniente para la ejecución y desarrollo de programas. Entre los programas del sistema se suelen
incluir aplicaciones para manipular archivos y directorios, programas para obtener información
sobre el estado del sistema –como la fecha y hora o la memoria y el espacio en disco disponible–,
25 En los ataques de denegación de servicio se intentan utilizar todos los recursos de sistema para evitar que éste pueda
dar servició a los usuarios legítimos.
2-33
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
Además, muchos sistemas operativos disponen de programas que son útiles para resolver los
problemas más comunes de los usuarios. Entre estos programas se suelen incluir: editores de
archivos de texto y procesadores de texto, hojas de cálculo, sistemas de base de datos, juegos, etc.
Ha esta colección de aplicaciones se la suele conocer con el término de utilidades del sistema o
programas de aplicación.
● Si no hay ningún proceso que ejecutar ni ningún dispositivo de E/S pide la atención del
sistema, el sistema operativo debe permanecer inactivo esperado a que algo ocurra.
● Los sucesos que requieren la activación del sistema casi siempre se indican mediante una
interrupción:
○ Cuando un proceso comente un error –como una división por cero o un acceso a
memoria no válido– o un programa solicita un servicio al sistema operativo a través de
una llamada al sistema lo que se genera es una excepción –que no es más que una
interrupción generada por software– que despierta al sistema operativo para que haga lo
que sea más conveniente.
○ Cuando los dispositivos de E/S requieren la atención del sistema operativo –por ejemplo
porque se ha completado una transferencia de datos– se genera una interrupción que
despierta al sistema operativo.
Dado que el sistema operativo y los procesos de usuarios comparten los recursos del sistema
informático, necesitamos estar seguros de que un error que se produzca en un programa sólo afecte
al proceso que lo ejecuta. Por ejemplo, en los sistemas de tiempo compartido –y en cualquier otro
tipo de sistema operativo donde los programas tengan que compartir la memoria, como es el caso de
los sistema microprogramados– un programa erróneo puede modificar el código de otro programa,
los datos de otro programa o el propio sistema operativo. Por eso es necesario establecer
mecanismos de protección frente a los errores en los programas que se ejecutan en el sistema.
2-34
2.2. Operación del sistema operativo Sistemas Operativos - 2014/2015
● En el modo usuario se ejecuta el código de las tareas de los usuarios. Si se hace un intento de
ejecutar una instrucción privilegiada en este modo, el hardware la trata como ilegal y genera
una excepción que es interceptada por el sistema operativo, en lugar de ejecutar la instrucción.
● En el modo privilegiado –también denominado modo supervisor, modo del sistema o modo
kernel– se ejecuta el código de las tareas del sistema operativo. El hardware es el encargado
de garantizar que las instrucciones privilegiadas sólo pueden ser ejecutadas en este modo.
El modo actual de operación puede venir indicado por un bit de modo que se añade al hardware de
la computadora, de forma que si por ejemplo el bit está a 0, el código en ejecución opera en modo
privilegiado mientras que si el bit está a 1, el código en ejecución opera en modo usuario.
2. El sistema operativo debe cambiar al modo usuario –poniendo el bit de modo a 1– antes de
ceder el control a un proceso de usuario. Esto ocurre cuando es necesario que un proceso de
usuario continúe o inicie su ejecución (véase el apartado 3.4.2).
2-35
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
3. El hardware conmuta a modo privilegiado cuando ocurre una interrupción o una excepción
–poniendo el bit de modo a 0– antes de pasar el control al código del sistema operativo que se
encargará de tratarlas.
Esto último es importante pues, como ya hemos comentado, los sistemas operativos están
controlados mediante interrupciones. Al activarse el modo privilegiado cada vez que ocurre una
interrupción podemos estar seguros de que las tareas del sistema operativo se ejecutará en modo
privilegiado.
Cuando se dispone de la protección del modo dual el hardware se encarga de detectar los errores de
ejecución y de notificarlo al sistema operativo mediante excepciones, siendo responsabilidad de este
último realizar un tratamiento adecuado de los mismos. Por lo general, si un programa falla de
alguna forma, como por ejemplo intentando utilizar una instrucciones ilegal o de acceder a una zona
de memoria inválida, el sistema operativo lo hace terminar de manera anormal.
1. La primera parte sirve para albergar el sistema operativo residente 26. El sistema operativo
puede estar localizado tanto en la parte baja como en la parte alta de la memoria. El factor
determinante en la elección es la localización del vector de interrupciones. Puesto que en la
mayor parte de las arquitecturas éste reside en la parte baja de la memoria, normalmente el
sistema operativo también se aloja en la parte baja.
Sin embargo en los sistemas operativos modernos los procesos no tienen acceso libre a toda
memoria física con el objeto de proteger a los procesos en ejecución y al sistema operativo de
posibles errores en cualquiera de ellos:
● El sistema operativo proporciona a cada proceso una «vista» privada de la memoria similar a
la que tendrían si cada uno de ellos se estuviera ejecutando en solitario (véase la Figura 2.4).
● A esa «vista» que tiene cada proceso de la memoria es a lo que se denomina espacio de
26 El termino sistema operativo residente hace referencias a los componentes del sistema operativo que deben estar
permanentemente en la memoria. Comúnmente dicho conjunto de elementos componen el núcleo del sistema.
2-36
2.2. Operación del sistema operativo Sistemas Operativos - 2014/2015
sistema operativo
proceso 2
proceso 1
sistema operativo
proceso 2
0x00000000 0x00000000
memoria física espacio de direcciones
del proceso 2
direcciones virtual del proceso y está formado por el conjunto de direcciones que puede
generar la CPU para un proceso dado.
● Durante los accesos a la memoria principal en tiempo de ejecución estas direcciones virtuales
son convertidas en direcciones físicas antes de ser enviadas a la memoria principal. Por tanto
las direcciones físicas son las direcciones reales que ve la memoria, mientras que el espacio
de direcciones físico es el conjunto de direcciones físicas que corresponden a un espacio de
direcciones virtual dado.
● Permite el aislamiento de los procesos, creando para cada uno la ilusión de que toda la
memoria es para él y evitando que un proceso pueda acceder a la memoria de otros procesos.
● Permite marcar los modos de acceso autorizados en las diferentes regiones de la memoria
–como por ejemplo lectura, escritura y ejecución– evitando que el código ejecutado en modo
usuario tenga acceso a zonas a las que no debería tenerlo. El acceso a la memoria en un modo
no autorizado se considera una instrucción privilegiada, por lo que ese tipo de acceso desde el
modo usuario siempre genera una excepción.
2-37
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
2.2.3. El temporizador
El temporizador se utiliza para poder estar seguros de que el sistema operativo es capaz de
mantener el control de la CPU, puesto que lo que no puede ocurrir es que un proceso entre en un
bucle infinito de manera que nunca devuelva el control al sistema operativo.
El temporizador se configura durante el arranque del sistema para interrumpir a la CPU a intervalos
regulares. Así cuando el temporizador interrumpe el control se transfiere automáticamente al
sistema operativo. Entonces este puede: conceder más tiempo al proceso en ejecución, detenerlo y
darle más tiempo de CPU en el futuro o tratar la interrupción como un error y terminar de manera
anormal el programa. Indudablemente las instrucciones que pueden modificar el contenido del
temporizador son instrucciones privilegiadas.
aplicaciones
hardware
2-38
2.3. Sistemas operativos por su estructura Sistemas Operativos - 2014/2015
Por ejemplo, en MSDOS los programas de aplicación podían acceder directamente a la BIOS o al
hardware para hace acceder a cualquier dispositivo (véase la Figura 2.5). Disponiendo de esa
libertad un programa erróneo cualquiera podía corromper el sistema completo. Como el Intel 8086
para el que fue escrito MSDOS no proporcionaba un modo dual de operación, los diseñadores del
sistema no tuvieron más opción que dejar accesible el hardware a los programas de usuario.
Tanto MSDOS como UNIX eran originalmente sistemas pequeños y simples, limitados por la
aplicaciones
intérpretes de comando
compiladores e intérpretes
modo librerías del sistema
usuario
modo
privilegiado llamadas al sistema
planificador de la
gestión de señales sistema de ficheros CPU
del terminal reemplazo de
sistema de E/S de
sistema de E/S de bloques páginas
caracteres paginación bajo
drivers de disco y
drivers de terminal cinta demanda
memoria virtual
hardware
Figura 2.6: Ejemplo de sistema operativo con estructura sencilla (UNIX original).
2-39
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
funcionalidades del hardware de su época, que fueron creciendo más allá de las previsiones
originales. Lo cierto es que con mejor soporte del hardware se puede dividir el sistema operativo en
piezas más pequeñas y apropiadas que las del MSDOS y UNIX original.
authentication
pakage
modo
privilegiado
executive
I/O manager
security virtual local
object process plug and
reference memory procedue window
file system manager manager play manager
monitor manager call facility manager
cache
manager
graphic
device device
driver kernel
drivers
I/O manager
network
drivers
hardware abstraction layer
hardware
2-40
2.3. Sistemas operativos por su estructura Sistemas Operativos - 2014/2015
es lo que hacen y como utilizar. Por lo tanto cada capa tiene la responsabilidad de ocultar la
existencia de estructuras de datos, operaciones y hardware a las capas de nivel superior. Este tipo de
sistemas son los que se denominan con estructura en capas.
Los sistemas con estructura en capas siguen concentrado la mayor parte de la funcionalidad en el
núcleo, por lo que también son sistemas monolíticos aunque el núcleo es más modular. Ejemplos de
este tipo de sistemas operativos son el IBM OS/2 y Microsoft Windows (véase la Figura 2.7).
Sin embargo esta forma de dividir los componentes del sistema operativo no está libre de
inconvenientes:
● La mayor dificultad con los sistemas con estructura en capas es definirlas. Esto debe ser
planificado cuidadosamente debido a la restricción, comentada anteriormente, de que un capa
sólo puede utilizar los servicios de las capas inferiores. Por ejemplo, el planificador de CPU
suele tener información de los procesos que están en la memoria y parte de esa información
puede ser intercambiada con el disco para aumentar la memoria principal disponible. Este
planteamiento nos lleva a pensar que la gestión del almacenamiento secundario debe ir en una
capa inferior a la del planificador de la CPU. Sin embargo el planificador debe replanificar la
CPU cuando el proceso que actualmente la ocupa solicita alguna operación de E/S, por lo que
la gestión del almacenamiento secundario debe estar encima del planificador de la CPU para
que le pueda decir que replanifique. Al final la solución de compromiso es tender hacia
sistemas con pocas capas donde cada una tiene mucha funcionalidad.
● Esta estrategia es sin duda mucho menos eficiente que la de los sistemas de estructura
sencilla. En cada capa los parámetros son modificados y los datos necesarios deben de ser
transferidos, por lo que cada una añade cierto nivel de sobrecarga al funcionamiento del
sistema.
2-41
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
2.3.3. Microkernel
Los sistemas microkernel eliminan todos los componentes no esenciales del núcleo y los
implementa como programas de nivel de usuario. Aunque hay poco consenso, en general un núcleo
microkernel proporciona funciones mínimas de gestión de procesos y memoria, junto a algún
mecanismo de comunicación. En estos sistemas la función principal del núcleo es precisamente
proporcionar dicho mecanismo de comunicación entre el programa cliente y los diversos servicios
del sistema. Generalmente esta comunicación se implementa mediante paso de mensajes (véase el
apartado 3.2).
● Facilidad a la hora de añadir nuevas funcionalidades. Los nuevos servicios son añadidos
como aplicaciones de nivel de usuario, por lo que no es necesario hacer modificaciones en el
núcleo.
● Más seguridad y fiabilidad. Puesto que los servicios se ejecutan a nivel de usuario en procesos
separados, un servicio que falla no puede afectar a otros ni puede ser utilizado para ganar
acceso a otros servicios o al núcleo.
27 La RPC (Remote Procedure Call) es una mecanismo de llamada a procedimiento diseñado para ser utilizado entre
sistemas conectados por redes de ordenadores, permitiendo que un proceso cliente llame a un procedimiento en un
proceso servidor, aunque ambos estén en equipos diferentes, y ocultado los detalles de la comunicación que
permiten que la llamada tenga lugar.
2-42
2.3. Sistemas operativos por su estructura Sistemas Operativos - 2014/2015
aplicaciones aplicaciones
Hurd POSIX
glibc
(1)
servidores Hurd
sistema de
autenticación contraseña
ficheros
modo
usuario (1)
modo (1)
privilegiado
GNU Mach
controladores gestor de
tareas
de dispositivo
hardware
NT– tiene una arquitectura más monolítica que microkernel 28 ya que aunque muchos servicios
siguen siendo proporcionados por procesos de usuario, esto sólo ocurre con aquellos donde el
rendimiento no es un factor crítico.
Sin embargo varios sistemas operativos siguen utilizando núcleos microkernel, como Tru64 UNIX
y GNU/Hurd (véase la Figura 2.8). Ambos proporcionan una interfaz UNIX implementada sobre un
microkernel Mach. Otro ejemplo es QNX, un sistema operativo de tiempo real con una gran
aceptación que basa en la estructura de microkernel su estabilidad como sistema para tareas
críticas. Además siguen existiendo algunos proyectos de investigación dirigidos a resolver los
problemas de rendimiento asociados a los núcleos microkernel.
28 A las 280 llamadas al sistema de Microsoft Windows XP –algo menos de 200 en Microsoft Windows NT 3.51– se
deben sumar las más de 650 del subsistema gráfico, alojado en el núcleo desde Microsoft Windows NT 4.0.
2-43
Sistemas Operativos - 2014/2015 2. Estructura de los sistemas operativos
Estos núcleos suelen disponer un pequeño conjunto de componentes fundamentales que se cargan
durante el arranque, aunque también pueden enlazar dinámicamente servicios adicionales tanto
durante la inicialización del sistema como o en tiempo de ejecución. En este aspecto se asemejan a
los núcleos microkernel, ya que el módulo principal sólo tiene funciones básicas, aunque es mucho
más eficiente al no necesitar un mecanismo de paso de mensajes, puesto que los componentes se
cargan directamente en la memoria destinada al núcleo. Por lo tanto también deben ser
considerados como sistemas monolíticos.
Este tipo de estructura es la utilizada en los UNIX modernos, como Oracle/Sun Microsystems
Solaris, Linux (véase la Figura 2.9) y Mac OS X.
2-44
aplicaciones
modo
privilegiado
llamadas al sistema
planificación de
buffer-cache File IPC
procesos
VFS bin_exec gestión del tiempo core mmap swap Net IPC
controladores de
gestión de módulos Kernel IPC
dispositivo
System V IPC
red
Linux
hardware
3.1. Procesos
Los primeros sistemas informáticos sólo permitían que un programa se ejecutara de cada vez. Dicho
programa tenía un control completo sobre el sistema y acceso a todos los recursos del mismo. Por el
contrario, los sistemas de tiempo compartido actuales permiten que múltiples programas sean
cargados y ejecutados concurrentemente. Obviamente esta evolución requiere un control más fino y
la compartimentación de los diversos programas para que no interfieran unos con otros. Esto a su
vez conduce a la aparición de la noción de proceso, que no es sino la unidad de trabajo en un
sistema operativo moderno de tiempo compartido.
Por simplicidad, en este tema utilizaremos los términos trabajo y proceso de forma indistinta. A fin
de cuentas tanto los trabajos en los sistemas de procesamiento por lotes como los procesos en los
sistemas de tiempo compartido son la unidad de trabajo en sus respectivos sistemas y el origen de
toda actividad en la CPU.
Por último, antes de continuar, no debemos olvidar que en un sistema operativo hay:
● Procesos del sistema ejecutando el código del sistema operativo contenido en los programas
del sistema, que generalmente realizan tareas que es mejor mantener fuera del núcleo.
Sin embargo en lo que resta de tema no estableceremos ningún tipo de distinción entre ellos. Al fin
y al cabo todos son simples procesos de cara al resto del sistema.
3.1.1. El proceso
Como ya hemos comentado con anterioridad, un proceso es un programa en ejecución. Sin
embargo los procesos no son sólo el código del programa, sino que también suelen contener
algunos otros elementos:
● La sección de datos contiene las variables globales. Se divide entre la sección data, donde se
almacenan las variables inicializadas, y la sección bss, donde se almacenan las variables sin
inicializar.
● La pila contiene datos temporales como parámetros y direcciones de retorno de las funciones
y variables locales. Es conocida como la sección stack.
Máx.
sistema operativo
pila
montón
datos
código
0x00000000
3-48
3.1. Procesos Sistemas Operativos - 2014/2015
En todo caso es importante recordar que un proceso es una entidad activa, con un contador de
programa especificando la próxima instrucción a ejecutar y un conjunto de recursos del sistema
asociados. Mientras que un programa no es un proceso ya que es una entidad pasiva, como un
archivo en disco que contiene el código que algún día será ejecutado en la CPU. Por lo tanto dos
procesos pueden estar asociados al mismo programa pero no por eso dejan de ser distintos procesos
(véase el apartado 2.1.2). Ambos tendrán la misma sección text pero el contador de programas, la
pila, la sección data, etc. contendrán valores diferentes.
● Ejecutando. El proceso está siendo ejecutado puesto que ha sido escogido por el planificador
de la CPU. Sólo puede haber un proceso en este estado por CPU en el sistema.
● Esperando. El proceso está esperando por algún evento, como por ejemplo que termine
alguna operación de E/S o que se reciba alguna señal. Obviamente varios procesos pueden
estar en este estado.
● Preparado. El proceso está esperando a que se le asigne la CPU. Varios procesos pueden estar
en este estado.
nuevo terminado
admitido salida
temporizador
preparado ejecutando
asignación por el
E/S o evento planificador de la CPU a la espera de un
completado evento o E/S
esperando
3-49
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● Terminado. El proceso ha finalizado su ejecución y espera a que se liberen los recursos que le
fueron asignados.
● Contador de programa. Indica la dirección de la próxima instrucción del proceso que debe
ser ejecutada por la CPU.
● Registros de la CPU.
3-50
3.1. Procesos Sistemas Operativos - 2014/2015
petición de E/S
E/S cola de espera de E/S
esperar por
un evento
evento cola de espera del evento
● Cola de trabajo. Contiene a todos los procesos en el sistema de manera que cuando un
proceso entra en el sistema va a esta cola.
● Cola de preparados. Contiene a los procesos que están cargados en la memoria principal y
están preparados para ser ejecutados. La cola de preparados es generalmente una lista
enlazada de PCB donde cada uno incluye un puntero al PCB del siguiente proceso en la cola.
● Colas de espera. Contienen a los procesos que están esperando por un evento concreto, como
por ejemplo la finalización de una solicitud de E/S. Estas colas también suelen ser
implementadas como listas enlazadas de PCB y suele existir una por evento, de manera que
cuando ocurre algún evento todos los procesos en la cola asociada pasan automáticamente a la
cola de preparados.
● Colas de dispositivo. Son un caso particular de cola de espera. Cada dispositivo de E/S tiene
asociada una cola de dispositivo que contiene los procesos que están esperando por ese
dispositivo en particular.
3-51
Sistemas Operativos - 2014/2015 3. Gestión de procesos
○ El proceso puede solicitar una operación de E/S por lo que abandona la CPU y es
colocado en la cola de dispositivo correspondiente. No debemos olvidar que aunque en
nuestro diagrama no exista más que una de estas colas, en un sistema operativo real
suele haber una para cada dispositivo.
○ El proceso puede querer esperar por un evento. Por ejemplo puede crear un subproceso
y esperar a que termine. En ese caso el proceso hijo es creado mientras el proceso padre
abandona la CPU y es colocado en una cola de espera hasta que el proceso hijo termine.
La terminación del proceso hijo es el evento que espera el proceso padre para continuar
su ejecución.
2. Cuando la espera concluye los procesos pasan del estado de espera al de preparado y son
insertados en la cola de preparados.
3. El proceso repite este ciclo hasta que termina. En ese momento es eliminado de todas las
colas mientras el PCB y los recursos asignados son liberados.
29 Los sistemas de tiempo compartido como GNU/Linux, Microsoft Windows o cualquier sabor de UNIX carecen de
planificador de trabajos. En estos sistemas simplemente se cargan los procesos en memoria para que sean ejecutados
cuando el usuario lo solicita.
3-52
3.1. Procesos Sistemas Operativos - 2014/2015
● Algunos sistemas operativos utilizan el planificador de medio plazo para sacar procesos de la
memoria y reintroducirlos posteriormente. A este esquema se le denomina intercambio –o
swapping– y puede ser necesario utilizarlo cuando escasea la memoria.
El cambio de contexto es sobrecarga pura puesto que no hace ningún trabajo útil mientras se
conmuta. Su velocidad depende de aspectos tales como: el número de registros, la velocidad de la
memoria y la existencia de instrucciones especiales30.
a) Creación de procesos
Un proceso –denominado padre– puede crear múltiples procesos –los hijos– utilizando una
llamada al sistema específica para la creación de procesos. En general cada proceso se identifica
de manera unívoca mediante un identificador de proceso o PID (Process Identifier), que
30 Algunas CPUs disponen de instrucciones especiales para salvar y cargar todos los registros de manera eficiente.
Esto reduce el tiempo que la CPU está ocupada en los cambios de contexto. Otra opción es el uso de juegos de
registros, como es el caso de los procesadores Sun UltraSPARC e Intel Itanium. Con ellos el juegos de registros de
la CPU puede ser mapeado sobre un banco de registros mucho más extenso. Esto permite que la CPU almacene de
forma eficiente el valor de los registros de más de un proceso.
3-53
Sistemas Operativos - 2014/2015 3. Gestión de procesos
normalmente es un número entero. Puesto que cada nuevo proceso puede a su vez crear otros
procesos, al final se acaba obteniendo un árbol de procesos31.
Hay varios aspectos en la creación de los procesos que pueden variar de un sistema operativo a otro:
● ¿Cómo obtienen los subprocesos los recursos que necesita para hacer su trabajo?
○ Mientras que en otros cada subproceso puede solicitar y obtener los recursos
directamente del sistema operativo.
● ¿Qué ocurre con los recursos de un proceso cuando decide crear subprocesos?
○ El proceso puede estar obligado a repartir sus recursos entre sus hijos.
● ¿Cómo un proceso puede pasar parámetros de inicialización a sus procesos hijo? Además
de los diversos recursos que un proceso obtiene cuando es creado, el proceso padre suele
poder pasar parámetros de inicialización a sus procesos hijo. Por ejemplo en lenguaje C/C++
se puede obtener acceso a estos parámetros través de los argumentos argc y argv de la
función main() del programa.
● ¿Qué ocurre con la ejecución de un proceso cuando crea un subproceso? Si eso ocurre se
suelen contemplar dos posibilidades en términos de la ejecución del padre:
31 En los sistemas UNIX el proceso init es el proceso padre raíz de todos los procesos de usuario. Su PID siempre es
1 ya que es el primer proceso creado por el sistema operativo al terminar la inicialización del núcleo. Por lo tanto es
el responsable de crear todos los otros procesos que son necesarios para el funcionamiento del sistema.
3-54
3.1. Procesos Sistemas Operativos - 2014/2015
○ El espacio de direcciones del proceso hijo es un duplicado del que tiene el padre. Es
decir, que inicialmente tiene el mismo código y datos que el padre.
○ El espacio de direcciones del proceso hijo se crea desde cero y se carga en él un nuevo
programa.
Para ilustrar la diferencia entre estos dos últimos casos, supondremos que tenemos un proceso que
quiere crear un subproceso. En los sistemas operativos POSIX un nuevo proceso siempre se crea
con la llamada fork() que se encargar de crear el nuevo proceso con una copia del espacio de
direcciones del proceso original (véase la Figura 3.4). Esto facilita la comunicación entre procesos
puesto que al copiarse el espacio de direcciones también se copia la tabla de archivos abiertos. No
debemos olvidar que muchos de los recursos de un sistema POSIX se muestran de cara a los
procesos que los utilizan como archivos. Por lo tanto, el proceso hijo no sólo tiene acceso a los
archivos abiertos por el padre antes de la llamada al fork() sino también a tuberías (véase el
apartado 3.2.4), sockets (véase el apartado 3.2.4) y regiones de memoria compartida (véase el
apartado 3.2.2), entre otros muchos recursos. Todos estos son mecanismos que los procesos pueden
utilizar para comunicarse.
Tanto padre como hijo continúan la ejecución en la siguiente instrucción después del fork(). La
diferencia es que para el padre el valor de retorno de la llamada fork() es el identificador de
3-55
Sistemas Operativos - 2014/2015 3. Gestión de procesos
proceso del hijo, mientras que para el hijo el valor de retorno es cero. De esa forma padre e hijo
pueden saber quién es cada uno (véase la Figura 3.4).
En muchas ocasiones lo que se desea es iniciar la ejecución de un nuevo programa. Como POSIX
no dispone de una llamada al sistema para dicha tarea, lo que se debe hacer es invocar la llamada
exec() en el hijo después del fork(). La llamada exec() carga un nuevo archivo ejecutable en el
espacio de direcciones del proceso actual e inicia su ejecución, destruyendo la imagen del programa
que realizó la llamada a exec(). Mientras tanto el padre puede crear más hijos o si no tiene nada
más que hacer puede esperar. Para ello utiliza la llamada wait() que mueve el proceso a una cola
de espera hasta que termine el hijo creado previamente (véase la Figura 3.4).
Respecto a la familia de sistemas operativos Microsoft Windows NT, se supone que ambos modelos
son soportados a través de la llamada al sistema NTCreateProcess(). Es decir, que el espacio de
direcciones del padre puede ser duplicado o se puede indicar el nombre de un programa para que el
sistema operativo lo cargue en un nuevo proceso. Sin embargo el hecho es que los programadores
no tienen acceso directo a NTCreateProcess() ya que se supone que debe ser utilizada a través de
la función CreateProcess() de la librería de sistema de la API Win32. Dicha función no duplica el
espacio de direcciones del padre, sino que simplemente carga en un nuevo proceso el programa
indicado en los argumentos32.
b) Terminación de procesos
Un proceso termina cuando se lo indica al sistema operativo con la llamada al sistema exit(). En
ese momento puede devolver un valor de estado a su padre, que este puede recuperar a través de la
llamada al sistema wait(). Cuando un proceso termina todos los recursos son liberados incluyendo:
la memoria física y virtual, archivos abiertos, buffers de E/S, etc.
En todo caso un proceso puede provocar la terminación de otro proceso a través de una llamada al
sistema. Habitualmente el proceso que la invoca es el padre ya que puede que sea el único con
permisos para hacerla. Los motivos pueden ser:
● El hijo ha excedido el uso de algunos de los recursos reservados. Obviamente esto tiene
sentido cuando los hijos utilizan un subconjunto de los recursos asignados al padre.
32 Esta decisión de diseño en el API principal de Microsoft Windows estuvo motivada por el hecho de que la creación
de nuevos procesos tiene un coste alto en ese sistema operativo. En Microsoft Windows la forma adecuada de
realizar varias tareas al mismo tiempo es utilizando hilos (véase el apartado 3.3).
3-56
3.1. Procesos Sistemas Operativos - 2014/2015
● El padre termina y el sistema operativo está diseñado para no permite que el hijo pueda
seguir ejecutándose si no tiene un padre. Esto provoca que el sistema operativo inicie lo que
se denomina una terminación en cascada33, donde todos los procesos que cuelgan de uno
dado terminan.
● Los procesos independientes, que no afectan o pueden ser afectados por otros procesos del
sistema. Cualquier proceso que no comparte datos –temporales o persistentes– con otros
procesos es independiente.
● Los procesos cooperativos, que pueden afectar o ser afectados por otros procesos ejecutados
en el sistema. Los procesos que comparten datos siempre son cooperativos.
proceso A proceso B
memoria compartida
proceso A proceso B
3-57
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● Compartición de información. Dado que varios usuarios pueden estar interesados en los
mismos bloques de información –por ejemplo en un archivo compartido– el sistema operativo
debe proporcionar un entorno que permita el acceso concurrente a este tipo de recursos.
● Velocidad de cómputo. Para que una tarea se ejecute más rápido se puede partir en subtareas
que se ejecuten en paralelo. Es importante destacar que la mejora en la velocidad sólo es
posible si el sistema tiene varios componentes de procesamiento –como procesadores o
canales E/S–.
● Modularidad. Podemos querer crear nuestro software de forma modular, dividiendo las
funciones del programa en procesos separados.
● Conveniencia. Incluso un usuario individual puede querer hacer varias tareas al mismo
tiempo. Por ejemplo editar, imprimir y compilar en paralelo.
Las ejecución concurrente de procesos cooperativos requiere mecanismos tanto para comunicar
unos con otros (véase los apartados 3.2.2 y 3.2.3) como para sincronizar sus acciones (véase el
apartado 3.3.3).
Dos procesos que comparten una región de la memoria pueden intercambiar información leyendo y
escribiendo datos en la misma, pero:
● Los procesos son responsables de sincronizarse (véase el apartado 3.3.3) para no escribir en el
mismo sitio al mismo tiempo, lo que que podría generar inconsistencias.
Las principales ventajas de la memoria compartida frente a otros mecanismos de comunicación son:
3-58
3.2. Procesos cooperativos Sistemas Operativos - 2014/2015
La mejor forma de proporcionar IPC es utilizando un sistema de paso de mensajes (véase la Figura
3.5).
El componente de IPC de cualquier sistema operativo debe proporcionar al menos dos llamadas al
sistema:
Además los diseñadores del sistema operativo deben escoger entre implementar un componentes de
IPC con mensajes de tamaño fijo o mensajes de tamaño variable.
Para que dos procesos se puedan comunicar es necesario que haya un enlace de comunicaciones.
No trataremos aquí la implementación física del enlace –que por ejemplo puede ser mediante
3-59
Sistemas Operativos - 2014/2015 3. Gestión de procesos
En general existen varias opciones a la hora de implementar de manera lógica un enlace y las
correspondientes operaciones de envío y recepción:
b) Referenciación
Los procesos que se quiera comunicar debe tener una forma de referenciarse el uno al otro. Para ello
puede utilizar la comunicación directa o la indirecta.
Comunicación directa
En la comunicación directa cada proceso debe nombrar explícitamente al proceso destinatario o
receptor de la información. Por ejemplo:
El esquema anterior se de nomina direccionamiento simétrico pero existe una variante de ese
mismo esquema denominado direccionamiento asimétrico.
○ receive (&id, message) para recibir un mensaje de cualquier proceso. En este caso el
sistema operativo asigna a la variable id el identificador del proceso transmisor del
mensaje antes de volver de la llamada al sistema.
3-60
3.2. Procesos cooperativos Sistemas Operativos - 2014/2015
requiere actualizar todas las referencias al anterior identificador en todos los procesos que se
comunican con el. En general cualquier técnica que requiera que los identificadores de los procesos
sean establecidos explícitamente en el código de los programas no es deseable. Esto es así porque
en muchos sistemas los identificadores de los procesos cambian de una ejecución a otra. Por lo
tanto lo mejor sería disponer de una solución con un nivel adicional de indirección que evite que los
identificadores tenga que ser usados explícitamente
Comunicación indirecta
En la comunicación indirecta los mensajes son enviados a buzones, maillox o puertos que son
objetos dónde los procesos pueden dejar y recoger mensajes.
Este tipo de comunicación da lugar a algunas situaciones que deben ser resueltas. Por ejemplo,
¿qué pasa si los procesos P, Q y R comparten el puerto A, P manda un mensaje, y Q y R
invocan la llamada receive() en A?. La respuesta correcta dependerá de cuál de los siguientes
métodos escogieron los diseñadores del sistema:
● No permitir que más de un proceso puedan ejecutar receive() al mismo tiempo. Por ejemplo,
haciendo que sólo el proceso que crea el puerto tenga permiso para recibir de él. Los sistemas
que optan por esta solución suelen disponer de algún mecanimos para transferir el permiso de
recibir a otros procesos.
● O permitir que el sistema operativo escoja arbitrariamente quién recibe el mensaje si dos o
más procesos ejecutan receive() al mismo tiempo. La elección puede ser aleatoria o
mediante algún algoritmo, por ejemplo por turnos.
c) Buffering
Los mensajes intercambiados durante el proceso de comunicación residen en una cola temporal.
Básicamente hay tres formas de implementar dicha cola:
● Con capacidad cero o sin buffering la cola tiene una capacidad máxima de 0 mensajes, por lo
3-61
Sistemas Operativos - 2014/2015 3. Gestión de procesos
tanto no puede haber ningún mensaje esperando en el enlace. En este caso el transmisor debe
bloquearse hasta que el receptor recibe el mensaje.
○ Con capacidad limitada la cola tiene una capacidad limitada a N mensaje, por que si la
cola no se llena el transmisor no espera. Sin embargo si la cola se llena, el transmisor
debe bloquearse a la espera de haya espacio en la cola.
d) Sincronización
La comunicación entre dos procesos tiene lugar por medio de las llamadas send() y receive(); de
tal forma que generalmente la primera se bloquea cuando la cola de transmisión se llena –en
función del tipo de buffering– mientras que la segunda lo hace cuando la cola de recepción está
vacía.
Sin embargo existen diferentes opciones de diseño a la hora de implementar cada una de estas
primitivas en función de si se pueden bloquear o no. Por tanto, el paso de mensajes puede ser con
bloqueo o sin bloqueo, o lo que es lo mismo síncrono u asíncrono.
● Cuando el envío es sin bloqueo, el proceso transmisor nunca se bloquea. En caso de que la
cola de mensaje esté llena, la solución más común es que la llamada send() vuelva con un
código de retorno que indique que el proceso debe volver a intentar el envío más tarde.
● Cuando el envío es con bloqueo, el proceso transmisor se bloquea cuando no queda espacio en
la cola de mensajes y hasta que pueda depositar el mensaje en la misma.
● Cuando la recepción es sin bloqueo, el proceso receptor nunca se bloquea. En caso de que la
cola de mensajes esté vacía, el sistema operativo puede indicar al proceso que lo intente más
tarde a través de un código de retorno o devolviendo un mensaje nulo.
34 Las colas de longitud real infinita son imposibles puesto que los recursos son limitados. La longitud de estas colas
viene determinada por la memoria principal disponible, que suele ser lo suficientemente grande para que podamos
considerar que las colas son infinitas.
3-62
3.2. Procesos cooperativos Sistemas Operativos - 2014/2015
a) Tuberías
Las tuberías son un mecanismo de IPC de comunicación indirecta que está incluido en muchos
sistemas operativos. La comunicación es de capacidad cero y síncrona, aunque en algunos sistema
operativos también puede ser asíncrona.
Conceptualmente cada tubería tiene dos extremos. Un extremo permite al proceso en ese extremo
escribir en la tubería, mientras el otro extremo permite a los procesos leer de la tubería.
int fds[2];
char buffer[255];
exit(0);
3-63
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● Las tuberías anónimas sólo existen en el espacio de direcciones del proceso que las crea.
○ Los procesos hijo pueden heredar las tuberías abiertas por el proceso padre. Usando esa
capacidad de herencia se puede comunicar un proceso padre con sus hijos de manera
privada (véase la Figura 3.6).
● Las tuberías con nombre son públicas al resto del sistema, por lo que teóricamente son
accesibles por cualquier proceso.
Por simplicidad las tuberías son tratadas de forma similar a los archivos por lo que en ambos casos
se utilizar las mismas primitivas de E/S –read() y write()–.
Los procesos pueden mandar señales utilizando la llamada al sistema kill(), que sólo requiere el
identificador del proceso de destino y el número de la señal. Por tanto, estamos hablando de un
mecanismo de comunicación directa. Cada señal tiene un efecto particular por defecto –que por lo
general es matar al proceso– en el proceso que las recibe. Sin embargo cada proceso puede declarar
un manejador de señales que redefina la acción por defecto para una señal determinada. Un
manejador de señales no es más que una función que es ejecutada asíncronamente cuando la señal
es recibida. En ese sentido las señales en POSIX puede interpretarse como una forma de
interrupción por software.
Las señales fueron diseñadas originalmente como un mecanismo para que el sistema operativo
notificara a los programas ciertos errores y sucesos críticos, no como un mecanismo de IPC. Por
ejemplo:
3-64
3.2. Procesos cooperativos Sistemas Operativos - 2014/2015
● La señal SIGHUP es enviada a cada proceso iniciado desde una sesión de terminal cuando dicha
sesión termina.
● La señal SIGINT es enviada al proceso que está enganchado a la consola cuando el usuario
pulsa el carácter de interrupción –frecuentemente la combinación de teclas Control-C–.
Sin embargo esto no evita que las señales puedan ser útiles como mecanismo de IPC. No en vano el
estándar POSIX incluye dos señales –SIGUSR1 y SIGUSR2– especialmente indicadas para este uso.
Además las señales son utilizadas frecuentemente como medio de control de los demonios35 del
sistema. Por ejemplo permiten que un administrador –u otro proceso– le indique a un demonio que
debe reinicializarse, empezar a realizar el trabajo para el que fue diseñado o escribir su estado
interno en un sitio conocido del almacenamiento.
c) Sockets
Un socket es un punto final en una comunicación bidireccional entre procesos. Para que una pareja
de procesos se pueda comunicar son necesarios dos sockets –uno para cada proceso– de manera que
cada uno de ellos representa un extremo de la conexión.
La API de sockets fue creada por la Universidad de Berkeley para ser la que abstrajera el acceso a la
familia de protocolos de Internet (TCP/IP) en el UNIX desarrollado por esa misma universidad. Sin
embargo rápidamente se convirtió en el estándar de facto para la comunicación en red, por lo que
todos los sistemas operativos modernos –incluidos los sistemas POSIX y Microsoft Windows–
tienen una implementación de la misma.
Pese a sus orígenes, los sockets se diseñaron para ser independientes de la tecnología de red
subyacente. Por ejemplo:
● En las redes TCP/IP para crear un socket es necesario indicar la dirección IP y el número de
puerto en el que debe de escuchar o desde el que se debe conectar a otro socket. Mientras que
en el momento de establecer una conexión con ese otro socket, se debe indicar la dirección IP
y el número de puerto donde el socket debe estar escuchando. Esto es así porque la tecnología
de red TCP/IP subyacente establece que cada máquina tiene una IP y que los procesos se
comunican a través de los puertos en las mismas.
35 Un demonio es un proceso no interactivo que se ejecuta en segundo plano en vez de ser controlado directamente por
el usuario. Este tipo de programas se ejecutan de forma continua y proporcionan servicios específicos, como por
ejemplo es el caso de los servidores de correo electrónico, servidores de páginas Web o de bases de datos.
3-65
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● En los sistemas POSIX es habitual el uso de sockets de dominio UNIX para comunicar
procesos dentro de un mismo sistema. Estos no son más que sockets locales identificados
mediante un nombre de archivo y que, por tanto, están representados en el sistema de archivos.
Su principal utilidad están en las aplicaciones que siguen el modelo cliente-servidor pero
donde no es interesante –o seguro– que el servicio esté disponible a través de la red. Por
ejemplo se suelen utilizar para conectar gestores de bases de datos con aplicaciones Web
servidas desde el mismo equipo.
Si comparamos los ejemplos anteriores, podemos observar que existen grandes diferencias en
cuanto a la tecnología de comunicación empleada cuando se trata de comunicar procesos en redes
TCP/IP o en un mismo equipo mediante sockets de dominio UNIX. Sin embargo para ambos casos
la API de sockets siempre es la misma.
Los sockets implementan buffering automático y admiten tanto comunicación síncrona como
asíncrona, aunque el comportamiento final de la interfaz depende de la tecnología de red utilizada.
3.3. Hilos
Hasta el momento el modelo de proceso que hemos descrito asume que tenemos un sólo hilo de
ejecución, es decir, que se ejecuta en la CPU una única secuencia de instrucciones. Un proceso con
un hilo de ejecución sólo puede realizar una tarea a la vez. Por ejemplo, en un procesador de textos
con un sólo hilo de ejecución el usuario nunca podría escribir al mismo tiempo que se comprueba la
ortografía. Por eso muchos sistemas operativos modernos han extendido el concepto de proceso
3-66
3.3. Hilos Sistemas Operativos - 2014/2015
para permitir múltiples hilos de ejecución en cada uno. Los procesos con varios hilos pueden
realizar varias tareas a la vez.
3.3.1. Introducción
El hilo es la unidad básica de uso de la CPU en los sistemas operativos multihilo. De los recursos
de un proceso es privado a cada hilo (véase la Figura 3.8):
● El contador de programa indica la dirección de la próxima instrucción del proceso que debe
ser ejecutada por la CPU.
● La pila contiene datos temporales como parámetros y direcciones de retorno de las funciones
y variables locales.
Sin embargo todos los hilos de un mismo proceso comparten (véase la Figura 3.8):
a) Beneficios
Muchos son los beneficios que aporta la programación multihilo:
● Respuesta. Una aplicación multihilo interactiva puede continuar ejecutándose aunque parte de
la misma esté bloqueada o realizando una operación lenta, mejorando la respuesta al usuario
de la misma. Por ejemplo, un navegador Web multihilo puede gestionar la interacción del
usuario a través de un hilo mientras el contenido solicitado se descarga en otro hilo.
● Compartición de recursos. Por defecto los hilos comparten la memoria y los recursos del
proceso al que pertenecen. El compartir el código es lo que permite a una aplicación tener
varios hilos que realizan diferentes actividades dentro del mismo espacio de direcciones
3-67
Sistemas Operativos - 2014/2015 3. Gestión de procesos
Puesto que los hilos comparten los recursos de los procesos a los que pertenecen es más
económico crearlos. También es más económico el cambio de contexto entre ellos ya que hay
que guardar y recuperar menos información. Por ejemplo en Oracle/Sun Microsystems Solaris
crear un proceso es 30 veces más lento que crear un hilo; y el cambio de contexto es 5 veces
más lento.
b) Soporte multihilo
Las librerías de hilos proporcionan al programador la API para crear y gestionar los hilos de su
proceso. Hay dos formas fundamentales de implementar una librería de hilos:
○ Los hilos así gestionados no existen para el núcleo. Sólo existen en el espacio de usuario
dentro del proceso que los ha creado. Por ese motivo se los denomina hilos de usuario.
○ El código y los datos de la librería residen en el espacio de usuario, por lo que invocar
una función de la misma se reduce a una simple llamada a una función, evitando el coste
de hacer llamadas al sistema.
○ Los hilos así gestionados son soportados y gestionados por el núcleo, quien se encarga
de planificarlos en la CPU. Por ese motivo se los denomina hilos de núcleo.
○ El código y los datos de la librería residen en el espacio del núcleo, por lo que invocar
una función de la misma requiere frecuentemente hacer una llamada al sistema.
En la actualidad en los diferentes sistemas operativos se pueden encontrar librerías de ambos tipos.
Por ejemplo, la librería de hilos del API Win32 es del segundo tipo mientras que la librería de hilos
POSIX Threads –frecuentemente utilizada en los sistemas POSIX– puede ser de ambos tipos,
dependiendo solamente del sistema donde se implemente36.
36 POSIX Threads se implementa en el núcleo en los sistemas Linux y en la mayor parte de los UNIX actuales.
3-68
3.3. Hilos Sistemas Operativos - 2014/2015
a) Muchos a uno
En un sistema operativo cuyo núcleo no soporta múltiples hilos de ejecución la única posibilidad es
utilizar una librería de hilos implementada en el espacio de usuario. El planificador de dicha librería
se encarga de determinar que hilo de usuario se ejecuta en cada momento en el proceso, mientras
este es planificado en la CPU por el núcleo, obviamente elegido cuando le corresponda de entre
todos los procesos del sistema.
A efectos prácticos un proceso «sin hilos» se puede interpretar como un proceso con «un único
hilos de usuario
u u
u u
modo
usuario
modo
privilegiado
hilos de núcleo
3-69
Sistemas Operativos - 2014/2015 3. Gestión de procesos
hilo» de ejecución en el núcleo. Por eso se dice que en el modelo muchos a uno se mapean los
múltiples hilos de usuario de un proceso en el único hilo de núcleo del mismo (véase la Figura 3.8).
● La gestión de hilos se hace con una librería en el espacio de usuario, por lo que puede ser
muy eficiente. Como hemos visto anteriormente la invocación de las funciones de la librería se
hace por medio de simples llamadas a funciones.
● El proceso entero se bloquea si un hilo hace una llamada al sistema que deba ser bloqueada.
Por ejemplo operaciones de E/S a archivos, esperar a que suceda un evento, etc.
● Como sólo un hilo de usuario puede ser asignado al hilo de núcleo, los hilos de un mismo
proceso no se pueden ejecutar en paralelo en sistemas multiprocesador. El planificador de la
librería de hilos es el encargado de determinar que hilo de usuario es asignado al único hilo de
núcleo del proceso y este sólo puede ejecutarse en una única CPU al mismo tiempo.
El problema del bloqueo de procesos puede ser evitado sustituyendo las funciones de la librería de
sistema, de manera que las llamadas al sistema que se pueden bloquear sean sustituidas por
versiones con llamadas equivalentes pero no bloqueantes. Por ejemplo, las llamadas al sistema de
E/S se pueden reemplazar por llamadas de E/S asíncrona, que retornan inmediatamente aunque la
operación no haya sido completada. Después de cada una de estas llamadas asíncronas al sistema, la
librería del sistema invoca al planificador de la librería de hilos para que bloquee el hilo que ha
realizado la llamada y asigne el hilo de núcleo a un nuevo hilo de usuario. Obviamente el
planificador de la librería de hilos debe estar al tanto de cuando las operaciones asíncronas son
completadas para poder volver a planificar los hilos de usuario bloqueados. Este procedimiento es a
todas luces bastante complejo y requiere versiones no bloqueantes de todas las llamadas al sistema,
así como modificar las funciones bloqueantes de la librería del sistema para implementar el
comportamiento descrito.
Ejemplos de implementaciones este modelo de hilos son la Green Threads, una de las
implementaciones de hilos para Solaris y Java, Stackless Python37 y GNU Portable Threads38. Estas
implementaciones son muy útiles en los sistemas monohilo, de cara a poder ofrecer cierto soporte
de hilos a las aplicaciones, pero también en los sistemas multihilo, ya que debido a su bajo coste en
3-70
3.3. Hilos Sistemas Operativos - 2014/2015
hilos de usuario
u u u u
modo
usuario
modo
privilegiado
k k k k
hilos de núcleo
recursos y a su alta eficiencia son ideales cuando la cantidad de hilos a crear –el nivel de
concurrencia– va a ser previsiblemente muy alta .
b) Uno a uno
Si el núcleo del sistema operativo soporta hilos de ejecución, lo más común es que estos sean
visibles directamente en el espacio de usuario. Por lo tanto se dice que en el modelo uno a uno se
mapea cada hilo de usuario en exactamente un hilo de núcleo (véase la Figura 3.9).
● Permite a otro hilo del mismo proceso ejecutarse aun cuando un hilo hace una llamada al
sistema que debe bloquearse, ya que el núcleo se encarga de ponerlo en espera y planificar en
la CPU a otro de los hilos preparados para ejecutarse de entre todos los existentes en el
sistema.
● Crear un hilo de usuario requiere crear el correspondiente hilo de núcleo. Debido a que la
3-71
Sistemas Operativos - 2014/2015 3. Gestión de procesos
hilos de usuario
u u
u u
modo
usuario
modo
privilegiado
k k k
hilos de núcleo
cantidad de memoria disponible para el núcleo suele estar limitada, muchos sistemas
restringen la cantidad máxima de hilos soportados.
● Las gestión de los hilos se hace con una librería en el espacio de núcleo, lo que requiere
utilizar llamadas al sistema.
Este modelo se utilizar en la mayor parte de los sistemas operativos multihilo modernos. Linux,
Microsoft Windows 95/98/NT/2000/XP y superiores, y Solaris 9 y superiores, son ejemplos de
sistemas operativos que los utilizan.
c) Muchos a muchos
En teoría debería ser posible aprovechar lo mejor de los dos modelos anteriores. Por eso en el
modelo muchos a muchos se mapean los hilos de usuario en un menor o igual número de hilos de
núcleo del proceso (véase la Figura 3.10). Así los desarrolladores pueden utilizar la librería de hilos
en el espacio de usuario para crear tantos hilos como quieran. El planificador de la librería de hilos
se encarga de determinar que hilo de usuario es asignado a que hilo de núcleo. Mientras que el
planificador de la CPU asigna la CPU a alguno de los hilos de núcleo del sistema.
3-72
3.3. Hilos Sistemas Operativos - 2014/2015
hilos de usuario
u u
u u u
modo
usuario
modo
privilegiado
k k k k
hilos de núcleo
● Permite a otro hilo del mismo proceso ejecutarse cuando un hilo hace una llamada al sistema
que debe ser bloqueada, puesto que si un hilo de usuario realiza una llamada al sistema que
debe ser bloqueada, el correspondiente hilo de núcleo quedará bloqueado. Sin embargo, el
resto de los hilos de usuario pueden seguir ejecutándose en los otros hilos de núcleo.
Existe una variación del modelo muchos a muchos donde, además de hacer lo comentado
anteriormente, se permite que un hilo de usuario quede ligado a un único hilo de núcleo. Esta
variación se denomina en ocasiones modelo de dos niveles (véase la Figura 3.11) y es soportada en
sistemas operativos como Solaris 8 y anteriores, IRIX, HPUX y Tru64 UNIX.
Tanto en el modelo muchos a muchos como en el de dos niveles es necesario cierto grado de
coordinación entre el núcleo y la librería de hilos del espacio de usuario. Dicha comunicación tiene
como objetivo ajustar dinámicamente el número de hilos del núcleo para garantizar la máxima
eficiencia. Uno de los esquemas de comunicación se denomina activación del planificador y
consiste en que el núcleo informa a la librería de hilos en espacio de usuario del bloqueo de un hilo
de un proceso. Antes de dicha notificación el núcleo se encarga de crear un nuevo hilo de núcleo en
el proceso, de manera que el planificador de la librería pueda encargarse de asignarle alguno de los
3-73
Sistemas Operativos - 2014/2015 3. Gestión de procesos
otros hilos de usuario. Así es como se ajusta el número de hilos dinámicamente de manera que el
proceso nunca quede bloqueado.
3.3.3. Sincronización
Hemos comentado anteriormente que los hilos comparten el espacio de direcciones del proceso al
que pertenecen. Al mismo tiempo distintos procesos pueden compartir regiones de la memoria con
el objeto de cooperar en las tareas que deben desempeñar. Ambas posibilidades introducen algunos
riesgos, puesto que el acceso concurrente a los datos compartidos puede ocasionar inconsistencias.
En este apartado vamos a discutir como se puede asegurar la ejecución ordenada de hilos y/o
procesos cooperativos que comparten regiones de la memoria, con el fin de mantener la
consistencia de los datos.
Una forma de controlar el acceso a los recursos compartidos es que cada proceso o hilo pueda tener
un tipo de secciones de código denominadas sección crítica dónde se puedan cambiar las variables
compartidas, actualizar tablas o listas, escribir en un archivo, etc. El acceso a las secciones críticas
es controlado de manera que cuando un proceso se esté ejecutando en su sección de este tipo
3-74
3.3. Hilos Sistemas Operativos - 2014/2015
ningún otro pueda hacerlo en la suya. Sí eso ocurre, se dice que la ejecución es mutuamente
exclusiva en el tiempo.
Para ilustrarlo supongamos que dos procesos comparten una región de la memoria que contiene
un vector de elementos y un contador con el número de elementos del vector.
● El primer proceso realiza varias tareas que no entraremos a describir. Sin embargo como
resultado de esas tareas en ocasiones añade un elemento a un vector e incrementa un
contador que indica el número de elementos en el vector. Es decir, el primer proceso actúa
como productor. A continuación mostramos una porción de la subrutina del productor.
● El segundo proceso también realiza varias tareas que no describiremos. Pero para realizar
esas tareas en ocasiones debe tomar un elemento del vector compartido y decrementar el
contador. Es decir, el segundo proceso actúa como consumidor. A continuación
mostramos una porción de la subrutina del consumidor.
Aunque las subrutinas del productor y del consumidor son correctas cuando se ejecutan por
separado, no funcionan adecuadamente cuando se ejecutan concurrentemente. El motivo es que
los distintos procesos o hilos comparten la variable count. Supongamos que el valor de dicha
variable es 5 actualmente y que el productor y el consumidor ejecutan concurrentemente la
sentencia ++count y --count respectivamente. Si hacemos la traza de la ejecución de esas
sentencias, veremos que el valor de la variable count finalmente podría ser 4, 5 o 6. Pero el
único resultado correcto es 5, que es el que obtendríamos si ejecutamos las sentencias
secuencialmente.
3-75
Sistemas Operativos - 2014/2015 3. Gestión de procesos
Como ejemplo mostraremos como el resultado de la sentencia ++count puede ser incorrecto. En
este punto es importante destacar que la sentencia ++count no tiene porque tener una
instrucción en lenguaje máquina equivalente, por lo que podría ser implementada de la siguiente
manera:
registro1 = count;
registro1 = registro1 + 1;
count = registro1;
Donde registro1 es un registro de la CPU. De forma parecida la sentencia --count puede ser
implementada de la siguiente manera:
registro2 = count;
registro2 = registro2 - 1;
count = registro2;
En este caso llegamos al valor incorrecto de count = 4, indicando que hay 4 elementos en el
3-76
3.3. Hilos Sistemas Operativos - 2014/2015
vector cuando realmente hay 5. Si invertimos el orden de las sentencias S4 y S5, obtendríamos el
valor incorrecto count = 6. Como se puede apreciar, hemos llevado a estos valores incorrectos
porque hemos permitido la manipulación concurrente de la variable count.
b) Semáforos
Para que las operaciones sobre los datos compartidos se ejecuten de manera ordenada, el sistema
operativo debe proporcionar a los programadores de aplicaciones objetos abstractos cuya
implementación utilice las características que la CPU ofrece para tal fin. Ese es el caso de los
semáforos.
Los semáforos son un tipo de objetos que nos permite controlar el acceso a una sección crítica, por
medio de dos primitivas: acquire() y release().
semaphore S;
El semáforo S debe ser compartido entre los hilos que tengan secciones críticas cuya ejecución
deber ser mutuamente exclusiva. A continuación describimos el mecanismo de funcionamiento.
2. El contador es decrementado por acquire() cada vez que un hilo entra en la sección crítica.
3. El contador es incrementado por release() cada vez que un hilo sale de la sección crítica.
4. Cuando el contador está a 0, los hilos que ejecuten acquire() deben esperar hasta que otro
hilo salga, puesto que no se puede seguir decrementando el contador. El hilo saliente ejecuta
release() que incrementa el contador, permitiendo que uno de los hilos a la espera en
3-77
Sistemas Operativos - 2014/2015 3. Gestión de procesos
realizarse utilizando las características proporcionadas por el hardware, de forma que el incremento,
decremento y comparación del contador se pueda realizar de forma atómica39.
Por otro lado existen dos alternativas desde el punto de vista de la forma en la que se implementa la
espera de los hilos dentro de acquire():
● El hilo puede cambiar su estado a esperado y moverse a una cola de espera asociada al
semáforo. Entonces el planificador de la CPU escogerá a otro proceso para ser ejecutado.
● El hilo puede iterar sobre el contador a la espera de que sea incrementado. Este tipo de
espera ocupada sólo se utiliza en el caso de esperas previsiblemente cortas, puesto que se
desperdician ciclos de CPU que otro hilo podría utilizar de forma más productiva. Por eso,
para evitar que las esperas ocupadas sean demasiado largas, los sistema operativos nunca
expropian (véase el apartado 3.4.1) hilos que se estén ejecutando dentro de secciones críticas
controladas por semáforos con este tipo de espera.
A estos semáforos también se los denomina spinlocks. Los spinlocks son utilizados frecuentemente
para proteger las estructuras del núcleo de los sistemas multiprocesador, donde un hilo itera en un
procesador mientras que otro hilo ejecuta la sección crítica en otro procesador, especialmente
cuando las tareas a realizar dentro de dicha sección crítica requiere poco tiempo. Además son muy
eficientes al no obligar a hacer cambios de contexto entre hilos, lo que podría necesitar un tiempo
considerable.
39 Una operación o conjunto de operaciones es atómica o no interrumpible si de cara al resto del sistema parece que la
operación ocurre de forma instantánea e indivisble.
3-78
3.3. Hilos Sistemas Operativos - 2014/2015
b) Cancelación de hilos
La cancelación es la operación de terminar un hilo antes de que termine su trabajo. Por ejemplo,
en un navegador web un hilo se puede encargar de la interfaz de usuario mientras otros hilos se
encargan de descargar las páginas y las imágenes de la misma. Si el usuario pulsa el botón
cancelar es necesario que todos los hilos que intervienen en la descarga sean cancelados. Esto
40 Al usar el término función nos estamos refiriendo a cualquier procedimiento, función, método, subprograma,
subrutina o rutina del programa.
3-79
Sistemas Operativos - 2014/2015 3. Gestión de procesos
En ocasiones ambos conceptos se confunden porque es bastante común que el código reentrante
también sea seguro en hilos. Sin embargo es posible crear código reentrante que no sea seguro en
hilos y viceversa. Por ejemplo, una función que manipule datos específicos de hilo seguramente no
será reentrante aunque si segura en hilos. Mientras que una función que sólo utilice variables locales
y que no invoque a otras funciones seguramente será reentrante y segura en hilos.
El estándar POSIX establece que si se utiliza fork() en un programa multihilo, el nuevo proceso
debe ser creado con un sólo hilo, que será una réplica del que hizo la llamada, así como un
duplicado completo del espacio de direcciones del proceso. Sin embargo algunos sistemas UNIX
tienen una segunda llamada no estándar, denominada forkall(), capaz de duplicar todos los hilos
del proceso padre. Obviamente sólo resulta conveniente emplearla si no se va a utilizar la llamada
exec().
● Las señales síncronas se deben a alguna acción del propio proceso. Ejemplos de señales de
este tipo son las originadas por accesos ilegales a memoria o divisiones por 0. Las señales
síncronas son enviadas al mismo proceso que las origina.
3-80
3.3. Hilos Sistemas Operativos - 2014/2015
● Las señales asíncronas son debidas a procesos externos. Un ejemplo de este tipo de señales es
la terminación de procesos con teclas especiales como Control-C.
Las señales que llegan a un proceso pueden ser interceptadas por un manejador definido por el
programador. En caso de que éste no haya sido definido, se utiliza un manejador por defecto cuya
acción depende del tipo de evento.
La pregunta es: ¿cuando se tienen múltiples hilos a cuál de ellos deben llegar las señales para ser
manejadas? Obviamente las señales síncronas, por su propia naturaleza, deben ser enviadas al hilo
que las genera. Pero con las señales asíncronas la cosa no está tan clara. Dependiendo del caso
algunas deben ser capturadas por un sólo hilo, mientras que otras –como aquellas que ordenan
terminar el proceso– deben ser enviadas a todos.
La mayor parte de los UNIX multihilo permiten especificar que señales acepta cada hilo y cuales
no. Por lo tanto una señal asíncrona sólo será entregada a aquellos hilos que no la bloquean. Puesto
que generalmente las señales necesitan ser manejadas una sola vez, normalmente sólo llegan al
primer hilo al que se le asigna la CPU y que no las esté bloqueando.
Aunque a lo largo de este tema hablaremos de planificar procesos en la CPU, en los sistemas
operativos multihilo se planifican los hilos de núcleo y no los procesos. Por ello todo lo que
comentemos a partir de ahora se aplica de la misma manera a los hilos de núcleo, en aquellos
sistemas operativos que los soportan.
3-81
Sistemas Operativos - 2014/2015 3. Gestión de procesos
1. Cuando un proceso pasa de ejecutando a esperando. Por ejemplo, por solicitar una operación
de E/S, esperar a que un hijo termine, etc.
Cuando el planificador es invocado en alguno de los casos anteriores decimos que tenemos un
sistema operativo con planificación cooperativa o no expropiativa.
Sin embargo, las decisiones de planificación también pueden ser tomadas en otros casos:
2. Cuando un proceso pasa de esperando a preparado. Por ejemplo porque para un proceso ha
terminado la operación de E/S por la que estaba esperando.
Cuando el planificador es invocado en los cuatro casos decimos que tenemos planificación
expropiativa o apropiativa. La planificación expropiativa si requiere de un soporte adecuado por
parte del hardware, por lo que se utiliza en la mayor parte de los sistemas operativos modernos.
Ejemplos de estos sistemas son Microsoft Windows 9x/NT/2000/XP, Mac OS X, GNU/Linux y los
UNIX modernos.
● Puesto que un proceso puede ser expropiado en cualquier momento, el sistema operativo debe
proporcionar mecanismos de sincronización (véase el apartado 3.3.3) para coordinar el acceso
a datos compartidos que podrían estar siendo modificados por el proceso que abandona la
CPU.
● ¿Qué pasa si un proceso va a ser expropiado cuando se está ejecutando una llamada al
sistema? No debemos olvidar que generalmente dentro del núcleo se manipulan datos
importantes que deben permanecer consistentes en todo momento. Para resolver esta cuestión
los diseñadores pueden optar por impedir la expropiación dentro del núcleo. Es decir, antes de
hacer el cambio de contexto, que sacaría al proceso de la CPU, se espera a que la llamada se
complete o se bloquee pasando el proceso al estado de esperando. Esto permite núcleos
simples y garantiza que las estructuras del mismo permanezcan consistentes, pero es un
3-82
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
3.4.2. El asignador
El asignador es el componente que da el control de la CPU al proceso seleccionado por el
planificador de corto plazo. Esta tarea implica realizar las siguientes funciones:
● Cambiar el contexto.
Puesto que el asignador es invocado para cada conmutación entre procesos, es necesario que el
tiempo que tarda en detener un proceso e iniciar otro sea lo más corto posible. Al tiempo que
transcurre desde que un proceso es escogido para ser planificado en la CPU hasta que es asignado
a la misma se lo denomina latencia de asignación.
a) Criterios a maximizar
● Uso de CPU: Un buen planificador debería mantener la CPU lo más ocupada posible. El uso
de CPU es la proporción de tiempo que se usa la CPU en un periodo de tiempo determinado.
Se suele indicar en tanto por cierto.
● Tasa de procesamiento: Cuando la CPU está ocupada es porque el trabajo se está haciendo.
3-83
Sistemas Operativos - 2014/2015 3. Gestión de procesos
Por tanto una buena medida del volumen de trabajo realizado puede ser el número de tareas o
procesos terminados por unidad de tiempo. A dicha magnitud es a la que denominamos como
tasa de procesamiento.
b) Criterios a minimizar
● Tiempo de ejecución: Es el intervalo de tiempo que transcurre desde que el proceso es
cargado hasta que termina.
En general podemos encontrar dos clases de trabajos para los que puede ser necesario evaluar la
eficiencia del sistema de manera diferente.:
3-84
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
Obviamente estos criterios varían de un proceso a otro, por lo que normalmente lo que se busca es
optimizar los valores promedios en el sistema. Sin embargo no debemos olvidar que en muchos
casos puede ser más conveniente optimizar el máximo y mínimo de dichos valores antes que el
promedio. Por ejemplo, en los sistemas interactivos es más importante minimizar la varianza en el
tiempo de respuesta que el tiempo de respuesta promedio, puesto que para los usuarios un sistema
con un tiempo de respuesta predecible es más deseable que uno muy rápido en promedio pero con
una varianza muy alta.
3-85
Sistemas Operativos - 2014/2015 3. Gestión de procesos
duración de la ráfaga
La curva que relaciona la frecuencia de las ráfagas de CPU con la duración de las mismas tiende a
ser exponencial o hiper-exponencial (véase la Figura 3.12) aunque varía enormemente entre
procesos y sistemas informáticos distintos. Esto significa que los procesos se pueden clasificar entre
aquellos que presentan un gran número de ráfagas de CPU cortas o aquellos con un pequeño
número de ráfagas de CPU largas. Concretamente:
● Decimos que un proceso es limitado por la E/S cuando presenta muchas ráfagas de CPU
cortas, debido a que si es así pasa la mayor parte del tiempo esperando por la E/S.
● Decimos que un proceso está limitado por la CPU cuando presenta pocas ráfagas de CPU
largas, debido a que si es así hace un uso intensivo de la misma y a penas pasa tiempo
esperando por la E/S.
Esta distinción entre tipos de procesos puede ser importante en la selección de un algoritmo de
planificación de CPU adecuado. En general:
● El algoritmo escogido debe favorecer –planificándolos antes– a los procesos limitados por la
E/S, evitando así que los procesos limitados por la CPU –que son los que tienden a usarla más
tiempo– la acaparen. Si eso ocurriera, los procesos limitados por la E/S se acumularían en la
cola de preparados, dejando vacías las colas de dispositivos. A este fenómeno tan negativo que
provoca una infrautilización de los dispositivos de E/S se lo denomina efecto convoy.
● Además planificar primero a los procesos limitados por la E/S tiene dos efectos muy positivos:
3-86
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
○ Los procesos interactivos son generalmente procesos limitados por la E/S, por lo que
planificarlos primero hace que mejore el tiempo de respuesta.
3.4.5. Planificación
Hasta el momento hemos considerado la cola de preparados como una estructura donde los procesos
que están preparados para ser ejecutados se ordenan y se escogen según el criterio del algoritmo de
planificación. Aunque a lo largo de todo el tema 3 se puede haber intuido que dicha cola es de tipo
FIFO –lo que se conoce como algoritmo de planificación FCFS o First Come, First Served– ya al
principio del apartado 3.4 indicamos que no tiene porqué ser así pues existen muchos otros
algoritmos –SJF o Shortest-Job First, SRTF o Shortest-Remaing-Time First, RR o Round-Robin,
por prioridades, etc.– que pueden ser preferibles en función del criterio que utilicemos para evaluar
la eficiencia de los mismos.
Sin embargo en los sistemas operativos modernos realmente las cosas son un poco más complejas
ya que generalmente se utiliza algún tipo de planificación con colas multinivel. En este tipo de
planificación no existe una única cola de preparados sobre la que se utiliza un único algoritmo de
planificación sino que:
● La cola de preparados se divide en varias colas separadas y los procesos son asignados a
alguna de dichas colas en base a características de los mismos.
● Cada cola puede tener un algoritmo de planificación de la CPU distinto. Es decir, alguno de
los que hemos mencionado anteriormente y que se estudiarán en las clases de problemas.
● Mediante un algoritmo determinado se debe seleccionar la cola que debe escoger al siguiente
proceso a ejecutar.
Precisamente una cuestión interesante es la indicada en éste último punto ¿cómo seleccionar la cola
que debe escoger al siguiente proceso que debe ser ejecutado?.
41 En la literatura sobre algoritmos de planificación de la CPU se indica que SJF (Shortest-Job First) y SRTF
(Shortest-Remaing-Time First) son los óptimos respecto al tiempo de espera promedio precisamente porque siempre
escogen al proceso con la ráfaga de CPU más corta de entre los que esperan en la cola de preparados.
3-87
Sistemas Operativos - 2014/2015 3. Gestión de procesos
0
procesos del sistema
1
procesos interactivos
2
procesos de edición interactivos
3
procesos por lotes
4
procesos de estudiantes
a) Prioridad fija
Aunque existen muchas maneras de clasificar los procesos entre las diferentes colas, lo más común
en los sistemas operativos modernos es hacerlo en base a la prioridad de los procesos (véase la
Figura 3.13):
● Los procesos, al entrar en la cola de preparados, son insertados en aquella cola que coincide
con su prioridad.
● El planificador escoge primero siempre la cola de prioridad más alta que no esté vacía.
● Las prioridades normalmente vienen determinadas por criterios ajenos al sistema operativo.
3-88
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
Por ejemplo: la importancia del proceso, la cantidad de dinero pagada para el uso del sistema u
otros factores políticos. A este tipo de prioridades se las denomina definidas externamente.
En la planificación FCFS (First Come, First Served) o primero que llega, primero servido la cola es
FIFO:
● Los procesos que llegan se colocan al final de la cola que les corresponde.
42 Los algoritmos FCFS y RR se pueden combinar de múltiples maneras. En algunos sistemas todas las colas son o
bien FCFS o bien RR, mientras que en otros unas colas pueden ser de un tipo y otras del otro. Por ejemplo, en el
núcleo Linux las prioridades más altas –las etiquetadas como de tiempo real– tienen tanto una cola FCFS como una
cola RR. En cada prioridad primero se planifican los procesos de la cola FCFS y después lo de la cola RR.
3-89
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● La cola RR se define como una cola circular dónde el planificador asigna la CPU a cada
proceso en intervalos de tiempo de hasta un cuanto.
Cuando se utilizar la planificación RR el tamaño del cuanto es un factor clave en la eficiencia del
planificador:
● Cuando se reduce el tiempo del cuanto, el tiempo de respuesta y el tiempo de espera promedio
tienden a mejorar. Sin embargo el número de cambios de contexto será mayor, por lo que la
ejecución de los procesos será mas lenta. Además es importante tener en cuenta que interesa
que el tiempo del cuanto sea mucho mayor que el tiempo del cambio de contexto; pues si por
ejemplo el tiempo del cambio de contexto es un 10% del tiempo del cuanto, entonces
alrededor del 10% de CPU se perdería en cambios de contexto.
● Cuando se incrementa el tiempo del cuanto, el tiempo de espera promedio se incrementa dado
que entonces el RR tiende a comportarse como un FCFS, que suele tener grandes tiempos de
espera promedio. Además se puede observar experimentalmente que el tiempo de ejecución
promedio generalmente mejora cuantos más procesos terminan su próxima ráfaga de CPU
dentro del tiempo del cuanto43. Por lo tanto nos interesan un cuanto grande para que más
procesos terminen su siguiente ráfaga dentro del mismo.
La regla general que siguen los diseñadores es intentar que el 80% de las ráfagas de CPU sean
menores que el tiempo de cuanto. Se busca así equilibrar los criterios anteriores, evitando que el
tiempo de cuanto sea demasiado grande o demasiado corto44.
Además, como vimos en el apartado 3.4.4, es conveniente favorecer a los procesos limitados por la
E/S frente a los procesos limitados por la CPU para evitar el efecto convoy y para mejorar los
43 Por ejemplo, dados tres procesos con una duración cada uno de ellos de 10 unidades de tiempo y cuanto igual a 1, el
tiempo de ejecución promedio será de 29 unidades. Sin embargo si el cuanto de tiempo fuera 10, el tiempo de
ejecución promedio caería a 20 unidades de tiempo.
44 De manera práctica actualmente se utilizan tiempos de cuanto de entre 10 y 100 ms. Estos tiempos son mucho
mayores que los tiempos de cambios de contexto, que generalmente son inferiores a 10µs.
3-90
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
tiempos tanto de espera como de respuesta promedio. Lamentablemente este tipo de planificación
con prioridad fija no es capaz de hacerlo ya que la prioridad de los procesos viene determinada
exclusivamente por criterios externos al funcionamiento del sistema operativo.
b) Prioridad dinámica
La mayor parte de los sistemas operativos modernos de propósito general 45 solucionan los
inconvenientes de la planificación con prioridad fija permitiendo que la prioridad de los procesos
se ajuste dinámicamente bajo su propio criterio:
● Por ejemplo, una solución al problema de la muerte por inanición es utilizar un mecanismo de
envejecimiento que aumente gradualmente la prioridad de los procesos mientras están
esperando en la cola de preparados –por ejemplo 1 unidad de prioridad cada 15 minutos–. De
esta manera los procesos de baja prioridad tarde o temprano tendrán oportunidad de ejecutarse.
Con este mecanismo una vez consiguen ejecutarse, se les restablece su prioridad original.
● Para favorecer en la planificación a los procesos limitados por la E/S el sistema puede añadir
o quitar prioridad a los procesos, respecto a su prioridad fija, en función de medidas internas
del sistema operativo. Por ejemplo se puede tomar en consideración: límites de tiempo,
necesidades de memoria, número de archivos abiertos, la proporción entre el tiempo de ráfaga
de E/S promedio y el de ráfaga de CPU promedio del proceso, etc. Obviamente el objetivo
suele ser mejorar el rendimiento del sistema priorizando unos procesos respecto a otros.
El resultado de estas políticas es que la prioridad que finalmente utiliza el sistema operativo para
planificar los procesos en un valor calculado dinámicamente a partir de intereses externos y
medidas internas. Por lo tanto los procesos pueden cambiar múltiples veces de cola durante su
tiempo de vida. A la planificación de múltiples niveles donde los procesos pueden cambiar de una
cola a otra se la denomina planificación con colas multinivel realimentadas.
45 Microsoft Windows, Mac OS X, Oracle/Sun Microsystems Solaris, las versiones de Linux anteriores a la 2.6.23 y,
en general, casi la totalidad de los sistemas operativos modernos de propósito general utilizan este tipo de
planificación de prioridades dinámicas con RR como planificador en cada prioridad.
3-91
Sistemas Operativos - 2014/2015 3. Gestión de procesos
es precisamente lo que hace la planificación equitativa (Fair Scheduling) que intenta repartir por
igual el tiempo de CPU entre los procesos de la cola de preparados. Por ejemplo, si 4 procesos
compiten por el uso de la CPU, el planificador asignará un 25% del tiempo de la misma a cada uno.
Si a continuación un usuario iniciase un nuevo proceso, el planificador tendría que ajustar el reparto
asignando un 20% del tiempo a cada uno. El algoritmo de planificación equitativa es muy similar al
algoritmo RR pero, a diferencia de este último en el que se utiliza un cuanto de tamaño fijo, la
ventana de tiempo se calcula de dinámicamente para garantizar el reparto equitativo de la CPU.
Al igual que en los algoritmos anteriores, en ocasiones puede ser interesante priorizar unos procesos
frente a otros, tanto por motivos ajenos al sistema operativo como por motivos internos. Por
ejemplo se puede querer favorecer a los procesos limitados por la E/S para mejorar la eficiencia del
sistema, tal y como comentamos en el apartado 3.4.4. La planificación equitativa resuelve este
problema asignando proporcionalmente más tiempo de CPU a los procesos con mayor prioridad. A
esta generalización del planificador equitativo se la conoce como planificador equitativo
ponderado46.
46 Linux desde la versión 2.6.23 utiliza un tipo de planificador equitativo ponderado denominado CFS (Completely
Fair Scheduler) o planificador completamente justo.
3-92
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
tiempo real estricto no es compatible con los sistemas operativos de propósito general, como los de
tiempo compartido.
● Sistema operativo con planificación con prioridades. Los procesos de tiempo real deben tener
la mayor prioridad. Además, no deben ser afectados por ningún mecanismo de envejecimiento
o bonificación47, que sí puede afectar a los procesos de tiempo no real.
● Baja latencia de asignación. Cuanto menor es la latencia más rápido comenzará a ejecutarse el
proceso de tiempo real después de ser seleccionado por el planificador de la CPU.
Mientras que el primer requerimiento es bastante sencillo de conseguir, el segundo es mucho más
complejo. Muchos sistemas operativos tienen un núcleo no expropiable. Estos núcleos no pueden
realizar un cambio de contexto mientras se está ejecutando código del núcleo –por ejemplo debido a
una llamada al sistema– por lo que se ven obligados a esperar hasta que la tarea que se esté
realizando se termine antes de asignar la CPU a otro proceso. Esto aumenta la latencia de
asignación dado que algunas llamadas al sistema pueden ser muy complejas y requerir mucho
tiempo para ser completadas. Con el objetivo de resolverlo existen diversas alternativas:
47 Linux, Microsoft Windows y la mayor parte de los sistemas operativos modernos de propósito general dividen el
rango de prioridades en dos partes. El conjunto de prioridades más altas son prioridades de tiempo real y por tanto
son fijas. Mientras que el grupo de prioridades más bajas son de tiempo no real y dinámicas. Además el planificador
se implementa de tal manera que un proceso con prioridad dinámica nunca puede alcanzar el rango de prioridades de
tiempo real.
3-93
Sistemas Operativos - 2014/2015 3. Gestión de procesos
Puntos de expropiación
Una posibilidad es hacer que el código del núcleo sea expropiable. Esto se consigue introduciendo
puntos de expropiación en diversos lugares seguros dentro del código. En dichos puntos se
comprueba si algún proceso de prioridad más alta está en la cola de preparados. En caso de que sea
así se expropia la CPU al proceso actual y se le asigna al proceso de más alta prioridad.
Debido a la función que realizan los puntos de expropiación, sólo pueden ser colocados en lugares
seguros del código del núcleo. Es decir, sólo pueden estar situados allí donde no se interrumpe la
modificación de estructuras de datos. Sin embargo esto limita el número de puntos que pueden ser
colocados, por lo que la latencia de asignación puede seguir siendo muy alta para algunas tareas
muy complejas del código del núcleo.
Núcleo expropiable
Otra posibilidad es diseñar un núcleo completamente expropiable. Puesto que en este caso la
ejecución de cualquier tarea en el núcleo puede ser interrumpida en cualquier momento por
procesos de mayor prioridad –que el que actualmente tiene asignada la CPU– es necesario proteger
las estructuras de datos del núcleo con mecanismos de sincronización, lo que hace que el diseño de
un núcleo de estas características sea mucho más complejo.
Supongamos que un proceso de baja prioridad es interrumpido, porque hay un proceso de alta
prioridad en la cola de preparados, mientras accede a una importante estructura de datos del núcleo.
Durante su ejecución el proceso de alta prioridad podría intentar acceder a la misma estructura que
manipulaba el proceso de baja prioridad cuando fue interrumpido. Debido al uso de mecanismos de
sincronización el proceso de alta prioridad tendría que abandonar la CPU a la espera de que el de
baja libere el acceso. Sin embargo este tardará en ser asignado a la CPU mientras haya algún otro
proceso de alta prioridad en la cola de preparados. Además otros procesos puede irse añadiendo a la
cola de espera del mecanismo de sincronización que regula el acceso a la estructura de datos del
núcleo. Al hecho de que un proceso de alta prioridad tenga que esperar por uno de baja se le conoce
como inversión de la prioridad. Para resolverlo se utiliza un protocolo de herencia de la
prioridad dónde un proceso de baja prioridad hereda la prioridad del proceso de más alta prioridad
que espera por un recurso al que el primero está accediendo. En el momento en que el proceso de
baja prioridad libere el acceso a dicho recurso, su prioridad retornará a su valor original.
Linux 2.6, Solaris y Microsoft Windows NT/2000/XP son algunos ejemplos de sistemas operativos
3-94
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
con núcleos expropiables. En el caso concreto de Solaris la latencia de asignación es inferior a 1 ms.
mientras que con la expropiación del núcleo desactivada ésta puede superar los 100 ms.
Lamentablemente el conseguir baja latencia de asignación no tiene coste cero. El hecho de que el
núcleo sea expropiable aumenta el número de cambios de contexto, lo que reduce el rendimiento del
sistema a cambio de una mejor respuesta. Por ello resulta muy interesante para aplicaciones de
tiempo real, multimedia y sistemas interactivos pero es poco adecuado para servidores y
computación de alto rendimiento. Es por eso que Linux 2.6 permite escoger entre tener un núcleo
expropiativo, usar puntos de expropiación o nada de lo anterior. De esta forma Linux está preparado
tanto para servidores como para sistemas de escritorio o de tiempo real.
48 Un ejemplo de lo contrario –de sistema heterogéneo– se puede observar en los PC modernos donde muchos
disponen tanto de una CPU como de una GPU especializada en el procesamiento de gráficos y en las operaciones de
coma flotante.
49 El HyperThreading disponible en algunos procesadores de Intel es una implementación de la tecnología
Simultaneous Multithreading.
3-95
Sistemas Operativos - 2014/2015 3. Gestión de procesos
○ Algunos sistemas disponen de una cola de preparados común para todos los
procesadores. Puesto que se mira en una única cola, todos los procesos pueden ser
planificados en cualquier procesador. Este esquema requiere el uso mecanismos de
sincronización debido a que hay estructuras de datos que se comparten entre todos los
núcleos. En caso contrario varios procesadores podrían escoger y ejecuta el mismo
proceso a la vez.
○ Por el contrario otros sistemas disponen de una cola de preparados para cada
procesador. El mayor inconveniente de esta solución es que puede generar
desequilibrios entre los procesadores, ya que un procesador puede acabar desocupado
–con la cola de preparados vacía– mientras otro está muy ocupado.
Muchos sistemas operativos modernos implementan el esquema SMP con una cola de preparados
común. Esto incluye Microsoft Windows NT/2000/XP, Solaris, Mac OS X y versiones anteriores a
Linux 2.6. Sin embargo, esta solución presenta algunos inconvenientes:
50 En los sistemas de multiprocesamiento asimétrico hay una CPU maestra y varias esclavas a quienes la primera
entrega el trabajo. En ocasiones las CPU esclavas se distinguen por haber sido diseñadas para realizar algún tipo de
trabajo de forma eficiente –como es el caso las GPU, que no son sino CPU diseñadas para el procesamiento de
gráficos– o por el hardware al que están conectadas –como por ejemplo las CPU unidas a discos para gestionarlos–.
51 En los sistemas de multiprocesamiento simétrico o SMP (Symmetric Multiprocessing) todos los procesadores son
iguales. Todos comparten los mismos recursos, pueden acceder a los mismos dispositivos y cada uno ejecuta una
copia del núcleo del sistema operativo. Por lo tanto el sistema operativo debe saber compartir los recursos y repartir
la carga entre las CPU. Casi todos los sistemas multiprocesador modernos son de este tipo.
3-96
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
Cada vez más sistemas modernos –incluido Linux 2.6– están optando por utilizar el esquema SMP
con una cola de preparados por procesador. De esta manera, al no utilizar mecanismos de
sincronización, se eliminan los tiempos de espera para acceder a la cola de preparados y escoger un
nuevo proceso. Sin embargo, con el fin de mantener la carga de trabajo equilibrada entre todos los
procesadores es necesario disponer de algunos mecanismos de balanceo de carga. Por ejemplo:
● En la migración comandada o push migration un tarea específica –que se ejecuta con menor
frecuencia que el planificador de la CPU– estima la carga de trabajo de cada CPU y en caso de
encontrar algún desequilibrio mueve algunos procesos de la cola de preparados de unos
procesadores a la de los otros
Tanto el planificador de Linux 2.6 como el planificador ULE, disponible en los sistemas FreeBSD,
implementan ambas técnicas. Mientras que en Microsoft Windows, apartir de Windows Vista, sólo
se hace uso de la migración solicitada.
3-97
Sistemas Operativos - 2014/2015 3. Gestión de procesos
● Dispone de 32 niveles con una prioridad fija entre 0 y 31 donde la prioridad 31 es la más
alta, mientras que la 0 –la más baja– se dedicada en exclusiva a un hilo encargado de poner
las páginas de memoria a cero. El planificador siempre escoge un proceso de la cola de
prioridad más alta.
● En cada nivel hay una cola RR para escoger el proceso que debe ser asignado a la CPU.
Ese algoritmo es ideal para los sistemas de tiempo compartido ya que facilita que los
procesos de una misma prioridad compartan la CPU.
Como cualquier sistema operativo moderno, el núcleo de Windows es expropiable –lo que
sabemos que ofrece latencias de asignación más bajas que si no lo fuera– y soporta tiempo real
flexible:
● El rango de prioridades se reparte de forma que las más altas –las que van desde la 16 a la
31– son para los procesos de tiempo real y las mas bajas para los de tiempo no real.
● Los hilos de tiempo real no se ven nunca afectados o beneficiados por bonificaciones ni
penalizaciones en la prioridad –la prioridad real del hilo es siempre la prioridad estática
fijada por el programador– y en ningún caso las bonificaciones o penalizaciones en las
prioridades pueden hacer que un proceso pase de un tipo al otro.
Respecto a esto último, en Windows los programadores o administradores del sistema pueden
utilizar el API para establecer la prioridad de los hilos. Sin embargo sobre estas preferencias el
núcleo aplica ciertas bonificaciones para obtener la prioridad real; combinando diferentes
criterios para reducir la latencia, mejorar la respuesta –obviamente a través de beneficiar a los
hilos limitados por E/S– evitar la muerte por inanición y la inversión de prioridad. Estas
bonificaciones pueden ocurrir en los siguientes casos:
● Ante eventos del planificador/asignador de la CPU –para reducir la latencia–. Por ejemplo,
cuando se configura un temporizdor, la hora del sistema cambia, un proceso termina, un
mutex o un semáforo es liberado o se entrega un evento de una operación de E/S asíncrona.
● Cuando se completan ciertas operaciones de E/S –para reducir la latencia–. Por ejemplo,
acceso al disco, CD-ROM o gráficos (+1); comunicaciones en red, tuberías o puerto serie
3-98
3.4. Planificación de la CPU Sistemas Operativos - 2014/2015
● Ante operaciones de espera sobre recursos del núcleo –para evitar la muerte por inanición
y la inversión de prioridad–. Por ejemplo bonificando la prioridad del hilo que dispone en
exclusiva de dicho recurso.
● Ante hilos que llevan mucho tiempo para ser ejecutados –para evitar la muerte por
inanición–. Para ser exactos el planificador escoge cada segundo unos pocos hilos que
lleven esperando aproximadamente 4 segundos, les triplica el cuanto y les aumenta la
prioridad a 15. Los hilos recuperan la prioridad y el cuanto anterior cuando agotan el
tiempo de cuanto actual o son expropiados.
Respecto al tiempo de cuanto, desde Windows Vista –NT 6.0– no se usa el temporizador para
controlarlo sino un contador de ciclos de reloj de la CPU 52. Así el sistema puede determinar con
precisión el tiempo que se hay estado ejecutando un hilo, sin incluir los tiempos dedicados a
otras cuestiones, como por ejemplo a manejar interrupciones.
En Windows los hilos se insertan en la cabeza de su cola –no en el final– y conservan lo que les
queda de cuanto, cuando son expropiados. Mientras que se insertan por el final con el valor de
cuanto reiniciado, cuando abandonan la CPU por haber agotado el cuanto anterior.
52 Desde el Intel Pentium las CPU de la familia x86 incorporan un contador de marca de tiempo (Time Stamp Counter
o TSC) de 64 bits que indica el número de ciclos transcurridos desde el último reset del procesador.
3-99
Sistemas Operativos - 2014/2015 3. Gestión de procesos
Windows y la del núcleo. Esta última es la que hemos estudiado en el apartado anterior.
Mientras que el API tiene una organización muy diferente que en última instancia debe ser
mapeada a las prioridades numéricas del núcleo de Windows.
El API organiza los procesos por clases de prioridad: Tiempo real (15), Alta (10), Arriba de lo
normal (9), Normal (8), Debajo de lo normal (7), Baja (6) y Reposo (1) . Al tiempo que cada
hilo tiene una prioridad relativa: De tiempo crítico (15), Más alta (2), Arriba de lo normal (1),
Normal (0), Debajo de lo normal (–1), Más baja (–2) y Reposo (–15). Por lo que la prioridad
interna de cada hilo, desde el punto de vista del núcleo, es el resultado de sumar la prioridad
base obtenida a partir de la clase de prioridad del proceso con la prioridad relativa del hilo en
cuestión.
3-100
4. Gestión de la memoria
Como ya comentamos en el aparatado 1.3.1, en los sistemas multiprogramados existe una cola de
entrada que se define como aquella formada por el conjunto de procesos en disco que esperan
para ser cargados en la memoria para su ejecución.
En los sistemas de tiempo compartido no existe cola de entrada, por lo que los programas se
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
código
fuente
compilador o
ensamblador
módulo tiempo de
compilación
objeto
enlazado
otros estático
módulos enlazador
objeto
modulo
ejecutable
tiempo
de carga
enlazado
librería del dinámico
sistema y otras cargador
librerías de enlace
dinámico
enlazado imagen
tiempo de
dinámico con binaria en
ejecución
carga diferida la memoria
cargan inmediatamente en memoria cuando su ejecución es solicitada por los usuarios. Excepto por
eso, el procedimiento normal de ejecución de un programa es el mismo que para los sistemas
multiprogramados.
4-102
4.2. Reubicación de las direcciones Sistemas Operativos - 2014/2015
de ser ejecutado (véase la Figura 4.1). En cada una de ellas las direcciones pueden representarse de
formas distintas, por lo que en cada paso es necesario reubicar las direcciones usadas en una etapa
en direcciones de la siguiente. Por ejemplo, en el código fuente de un programa las direcciones son
generalmente simbólicas, como los nombres de las variables y las funciones. A continuación, un
compilador suele reasignar esas direcciones simbólicas en irecciones reubicables del estilo de “120
bytes desde el comienzo del módulo”. Finalmente, el enlazador o el cargador convierte esas
direcciones reubicables en irecciones absolutas como 0x210243.
Por tanto, en cada etapa se mapean las direcciones de un espacio de direcciones en el siguiente. Sin
embargo, para que al final el programa pueda ser ejecutado es necesario que tanto a los datos como
a las instrucciones se les reasignen direcciones absolutas de la memoria. Esto realmente puede
ocurrir en cualquiera de las siguientes etapas:
En el apartado 2.2.2 vimos en lo sistemas operativos modernos, como medida de protección, los
procesos no tienen acceso libre a la memoria física. En lugar de eso el sistema operativo –asistido
por la MMU (Memory-Management Unit)– proporciona a cada proceso un espacio de direcciones
virtual que ofrece una «vista» privada de la memoria similar a la que tendrían si cada uno de los
4-103
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
procesos estuviera siendo ejecutando en solitario (véase la Figura 2.4). Es durante los acceso a la
memoria principal en tiempo de ejecución cuando estas direcciones virtuales son convertidas en las
direcciones física con las que realmente se accede a la memoria.
El mecanismo de protección descrito es una forma muy común de reubicación de las direcciones en
tiempo de ejecución que está presente en la mayor parte de los sistemas operativos modernos de
propósito general. A parte de la protección, algunas de las características de dicho mecanismo son:
● Los programas pueden ser cargados en cualquier zona libre de la memoria física e incluso
movidos de una región a otra durante la ejecución de los procesos, puesto que la
transformación (reubicación) de las direcciones virtuales en direcciones físicas se realiza
durante la ejecución de cada instrucción.
● En el enlazado estático, las librerías del sistema y otros módulos son combinados por el
enlazador para formar la imagen binaria del programa que es almacenada en disco. Algunos
sistemas operativos, como MS-DOS, sólo soportan este tipo de enlazado.
● En el enlazado dinámico, éste se pospone hasta la carga o la ejecución (véase la Figura 4.1).
4-104
4.3. Enlazado dinámico y librerías compartidas Sistemas Operativos - 2014/2015
1. Durante la carga del módulo ejecutable se comprueban las dependencias del mismo. Estas se
almacenan en el mismo archivo en disco que dicho módulo.
2. Las librerías a enlazar se cargar y ubican en el espacio de direcciones virtual creado para el
nuevo proceso.
3. Finalmente, las referencias del programa a las subrutinas de cada una de las librerías
cargadas se actualizan con la dirección en memoria de las mismas. Así la invocación de las
subrutinas por parte del programa se puede realizar de forma transparente, como si siempre
hubieran formado parte del mismo.
1. Durante el enlazado estático del módulo ejecutable se pone un stub a cada referencia a
alguna subrutina de la librería que va a ser enlazada dinámicamente.
Sin esta habilidad cada programa en el sistema, por ejemplo, debe tener una copia de la librería del
sistema incluida en la imagen binaria del mismo, lo que significa un desperdicio de espacio libre en
disco y memoria principal. Además este esquema facilita la actualización de las librería, puesto que
los programas pueden utilizar directamente las versiones actualizadas sin necesidad de volver a ser
enlazados.
Puesto que durante la compilación de una librería no se conoce la región que va a ocupar dentro de
los espacios de direcciones virtuales de los distintos procesos que la van a utilizar:
● Para las librerías el compilador debe generar código PIC (Position-Independent Code) o
independiente de la posición. Este tipo de código se puede ejecutar adecuadamente y sin
modificaciones independientemente del lugar de la memoria donde esté ubicado. Esto permite
reducir el consumo de memoria principal compartiendo las regiones de memoria física
asignadas al código de una misma librería en los distintos procesos que la utilizan.
● En los sistemas operativos donde no se usa código PIC el compilador debe generar código
4-105
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
reubicable para que la reubicación de las direcciones virtuales de las librerías dinámicas se
haga en tiempo de carga. Esto aumenta el tiempo de carga de las librerías y sólo permite que
compartan memoria física el código de las instancias de una misma librería que ha sido
cargado en la misma región del espacio de direcciones virtual en los distintos procesos que la
utilizan.
Habitualmente las librerías incluyen información acerca de la versión que puede ser utilizada para
evitar que los programas se ejecuten con versiones incompatibles de las mismas, o para permitir
que haya más de una versión de cada librería en memoria. Así los viejos programas se pueden
ejecutar con las viejas versiones de las mismas, o con versiones actualizadas pero compatibles,
mientras los nuevos programas se ejecuten con las versiones más recientes e incompatibles con los
viejos programas. A este sistema se lo conoce como librerías compartidas.
4.4. Paginación
El mapeo entre direcciones virtuales y físicas puede realizarse de diversas maneras. La forma más
·
· f
·
dirección dirección
virtual física f 00. . .00
·
CPU p d f d ·
·
f 11. . . 11
p ·
·
· ·
·
f
·
·
·
· memoria física
tabla de
páginas
4-106
4.4. Paginación Sistemas Operativos - 2014/2015
extendida es la paginación, que no es sino un esquema de gestión de la memoria que permite que
el espacio de direcciones físico de un proceso no sea continuo.
1. Cada dirección virtual generada por la CPU es divida en dos partes: un número de página p
y un desplazamiento d.
2. El número de página es utilizado por la MMU para indexar la tabla de páginas, que contiene
el número de marco f de cada página en la memoria física.
3. El número de marco es combinado con el desplazamiento para generar la dirección física que
va a ser enviada por el bus de direcciones hacia la memoria.
El tamaño de las páginas –y el de los marcos– viene definido por el hardware y normalmente es un
número entero potencia de 2 que puede variar entre 512 bytes y 16 MB, dependiendo de la
arquitectura. Es decir, si el espacio de direcciones es de 2 m y el tamaño de página es de 2 n, los m - n
bits de mayor orden del espacio de direcciones indican el número de página, mientras que los n bits
de menor orden indican el desplazamiento (véase la Figura 4.3)
p d
m-n n
4-107
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
1. Si el proceso requiere n páginas, el sistema operativo debe escoger n marcos. Estos marcos
son tomados de la lista de marcos libres que debe mantener el sistema. Puesto que son
escogidos de allí donde los haya libres, el espacio de direcciones físico puede no ser contiguo
aunque los procesos vean un espacio de direcciones virtual contiguo.
2. Los marcos seleccionados son asignados al proceso y cada página del proceso es cargada en
uno de dichos marcos.
3. La tabla de páginas es actualizada de manera que en la entrada de cada página del proceso se
pone el número de marco correspondiente.
Un aspecto importante de la paginación es la diferencia entre como ven los proceso la memoria y
como es realmente la memoria física. Cada proceso ve la memoria como un espacio único que lo
contiene sólo a él. Sin embargo la realidad es que el programa está disperso por la memoria física,
que además puede almacenar a otros programas. Esto es posible porque en cada momento la tabla
de páginas sólo contiene las páginas del proceso actual.
Toda esta información generalmente se guarda en una estructura denominada la tabla de marcos,
que tiene una entrada por cada marco de la memoria física.
Además el sistema operativo debe mantener una copia de la tabla de páginas para cada proceso en
el PCB, igual que mantiene una copia del contador de programa y del contenido de los registros de
la CPU. Esta copia es utilizada:
● Por el asignador para sustituir la tabla de páginas hardware cuando realiza un cambio de
contexto. Por lo tanto el uso de la paginación incrementa el tiempo del cambio de contexto.
● Para el mapeo manual de direcciones virtuales en físicas. Por ejemplo, cuando un proceso
4-108
4.4. Paginación Sistemas Operativos - 2014/2015
realiza una llamada al sistema para realizar una operación de E/S y proporciona una dirección
como parámetro, dicha dirección debe ser mapeada manualmente para producir la dirección
física correspondiente que será utilizada por el hardware para realizar la operación.
● Con páginas más pequeñas esperamos tener menos fragmentación interna. Los marcos son
asignados como unidades indivisibles, por lo que si los requerimientos de memoria de un
procesos no coinciden con un límite de páginas el último marco asignado no sería utilizado
completamente (en ocasiones incluso se podría desperdiciar un marco completo). A ese
fenómeno se lo conoce como fragmentación interna
● Con páginas más grande se pierde menos espacio en la tabla de páginas. No olvidemos que
cuanto más pequeñas son las páginas más páginas son necesarias y, por tanto, más entradas en
la tabla de páginas se necesitan. Además la E/S es más eficiente cuanto más datos son
transferidos en cada operación.
Los tamaños de páginas típicos son 4 y 8 KB. Por ejemplo, normalmente cada entrada en la tabla de
paginas es de 4 bytes –aunque esto también puede variar–. Eso significa que cada entrada puede
direccionar a uno de los 2 32 marcos de la memoria física. Si suponemos que el tamaño de cada
marco es de 4 KB, podemos determinar que el sistema es capaz de direccionar 2 44 bytes –o 16 TB–
de memoria física, para lo que es necesario disponer de una tabla de páginas de 4 MB.
● Como un conjunto de registros dedicados de la CPU. Es decir, la tabla de páginas del proceso
actual es alojada dentro de la propia CPU, en unos registros destinados a tal fin.
4-109
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
En los sistemas modernos se utilizan tablas de páginas muchos más grandes –de un millón de
entradas o más– que difícilmente pueden alojarse en registros dentro de la CPU, ya que alojar tablas
de páginas de más de 256 entradas es muy costoso. Por eso los sistemas actuales almacenan la tabla
de páginas del proceso en ejecución en la memoria. Eso permite disponer tablas de páginas de gran
tamaño aunque a costa de necesitar dos acceso a la memoria física por cada acceso a una palabra
de la memoria virtual53.
Para que la MMU pueda conocer la ubicación de la tabla de páginas durante la traducción de las
direcciones, la CPU debe disponer de un registro –el PTBR (Page-Table Base Register)– donde se
guarda la dirección de la tabla de páginas actual. Además esto permite que el cambio de contexto
sea más rápido –respecto al uso de registros para almacenar la tabla de páginas– puesto que sólo es
necesario carga un único registro más –el PTBR– durante el mismo.
4.4.3. Protección
La protección de las páginas se consigue mediante unos bits de protección asociados a cada
entrada de la tabla de páginas y normalmente almacenados en la misma. Estos bits pueden ser:
● Solo lectura.
● Lectura – Escritura. En algunos sistemas hay un bit específico para este permiso, mientras
que en otros se utilizan bit separados como: lectura, escritura y ejecución.
● Sólo ejecución. Que no existen en todas las plataformas. Por ejemplo, la familia Intel x86
careció de esta característica hasta que AMD la incluyó en su arquitectura AMD64, lo que
obligó a Intel a incluirla en las versiones más modernas de su Pentium IV. El bit –que para ser
exacto indica no ejecución– fue introducido para evitar cierto tipo de ataques de seguridad.
Durante la traducción de las direcciones la MMU comprueba que el tipo de acceso sea válido. Si
esto no es así, se genera una excepción de violación de protección de memoria, dado que el acceso
53 La solución a este problema pasa porque la CPU disponga de una eficiente y pequeña –de entre 64 y 1024 entradas–
memoria caché en la que almacenar las entradas de la tabla de página previamente utilizadas en la traducción de las
direcciones. A dicha caché se la denomina TLB (Translation Look-aside Buffer). Obviamente es necesario que el
asignador borre la TLB durante los cambios de contexto.
4-110
4.4. Paginación Sistemas Operativos - 2014/2015
8
·
·
· ·
·
·
Además de los bits comentados se suele añadir a cada entrada un bit de válido:
● Cuando una página es válida, la pagina asociada está en el espacio de direcciones virtual del
proceso. Es decir, es legal.
El sistema operativo puede utilizar este bit para permitir o denegar el acceso a una página, por
ejemplo porque no le ha asignado un marco ya que no está siendo utilizada por el proceso. Al igual
que con los bits de permisos, los intentos de acceso a una página ilegal generan una excepción.
Por ejemplo, en la Figura 4.4 vemos el espacio de direcciones virtual y la tabla de páginas de un
proceso de 5096 bytes en un sistema con páginas de 1024 bytes. Puesto que el proceso no ocupa
todo el espacio de direcciones, sólo las direcciones de la 0 a la 5119 son válidas. En dicho ejemplo
podemos apreciar varios fenómenos:
4-111
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
Máx.
sistema operativo
pila
montón
datos
código
0x00000000
● Debido a la fragmentación interna las direcciones de la 5097 a la 5119 son válidas, aunque el
proceso solo ocupe hasta la 5096. Es decir, se está asignando al proceso una porción de
memoria que no necesita.
● Las páginas ocupadas por el proceso son válidas. Pero todas las paginas en direcciones por
encima de la 5119 están marcadas como ilegales. Así el sistema operativo no tiene que asignar
marcos a páginas no utilizadas por el proceso.
En general los procesos sólo necesitan una porción muy pequeña de su espacio de direcciones
virtual. En esos casos es un desperdicio de memoria crear y almacenar un tabla de página completa
con una entrada para cada página del espacio de direcciones. Para evitarlo en algunas CPU existe el
PTLR (Page-Table Length Register) que se utiliza para indicar el tamaño actual de la tabla de
página. Este valor es comparado por la MMU durante la traducción con el número de página de
cada dirección virtual, de manera que las páginas con entradas más allá de la última almacenada en
la tabla son consideradas ilegales.
En realidad, tal y como vimos en el apartado 3.1.1, lo más común es que los procesos tengan un
spacio de direcciones virtual disperso como el de la Figura 4.5. En la misma podemos observar
como el sistema operativo ubica los diferentes componentes del proceso de una forma particular
dentro del espacio de direcciones virtual. Este esquema permite que tanto el montón –a través del
mecanismo de asignación dinámica de memoria de malloc()– como la pila puedan extenderse, en
base a las necesidades de memoria que tenga el proceso, sobre la región de memoria no ocupada.
4-112
4.4. Paginación Sistemas Operativos - 2014/2015
Esa región también puede ser parcialmente ocupada por librerías de enlace dinámico o por otros
objetos compartidos que sean necesitados durante la ejecución del proceso. En cualquier caso las
páginas de dicha región forman parte del espacio de direcciones virtual pero no tienen marcos de
memoria física asignados, en tanto en cuanto el proceso no las vaya a utilizar. La falta de marco es
indicada por el sistema operativo utilizando el bit de válido para denegar el acceso.
Compartir páginas no sólo permite ahorrar memoria pues en los sistemas operativos modernos la
memoria compartida (véase el apartado 3.2.2) se implementa mediante páginas compartidas.
Los programas suelen tener partes de código que rara vez son ejecutadas, por ejemplo las subrutinas
para manejar condiciones de error que, aunque útiles, generalmente nunca son invocadas. También
es frecuente que se reserve más memoria para datos de lo que realmente es necesario. Por ejemplo
muchos programadores tiene la costumbres de hacer cosas tales como declarar un array de 1000 por
4-113
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
1000 elementos cuando realmente sólo necesitan 100 por 100. Teniendo todo esto en cuenta y con el
fin de mejorar el aprovechamiento de la memoria, parece que sería interesante no tener que cargar
todas las porciones de los procesos pero de manera que éstos aun así puedan seguir siendo
ejecutados. Eso es exactamente lo que proporciona la memoria virtual, en general, y la paginación
bajo demanda, en particular, para los sistemas que soportan paginación.
● Un programa no estará nunca más limitado por la cantidad de memoria disponible. Es decir,
los desarrolladores pueden escribir programas considerando que disponen de un espacio de
direcciones virtual extremadamente grande y sin considerar la cantidad de memoria realmente
disponible. Es importante no olvidar que sin memoria virtual para que un proceso pueda ser
ejecutado debe estar completamente cargado en la memoria.
● Puesto que cada programa ocupa menos memoria más programas se pueden ejecutar al
mismo tiempo, con el correspondiente incremento en el uso de la CPU y en el rendimiento del
sistema y sin efectos negativos en el tiempo de respuesta y en el de ejecución.
Para que se puedan cargar las páginas cuando son necesitadas por su proceso hace falta que el
paginador sepa cuando lo son. Eso requiere que el hardware proporcione algún tipo de soporte, por
ejemplo incorporando un bit de válido a la entrada de cada página en la tabla de páginas:
● Cuando el bit de válido está a 1 la página es legal y está en la memoria. Es decir, la página
existe en el espacio de direcciones virtual del proceso y tiene asignado un marco de memoria
física.
4-114
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
Si un proceso accede a una página residente en memoria –marcada como válida– no ocurre nada y
la instrucción se ejecuta con normalidad. Pero si accede a una página marcada como inválida:
1. Al intentar acceder a la página la MMU comprueba el bit de válido y genera una excepción
de fallo página al estar marcada como inválida. Dicha excepción es capturada por el sistema
operativo.
2. El sistema operativo comprueba en una tabla interna si la página es legal o no. Es decir, si la
página realmente no pertenece al espacio de direcciones virtual del proceso o si pertenece
pero está almacenada en el disco. Esta tabla interna suele almacenarse en el PCB del proceso
como parte de la información de gestión de la memoria.
3. Si la página es ilegal, el proceso ha cometido un error y debe ser terminado. En UNIX, por
ejemplo, el sistema envía al proceso una señal de violación de segmento que lo obliga a
terminar.
1.1. El núcleo debe buscar un marco de memoria libre que, por ejemplo, se puede escoger
de la lista de marcos libres del sistema.
1.2. Se solicita una operación de disco para leer la página deseada en el marco asignado.
Puesto que no resulta eficiente mantener la CPU ocupada mientras la página es
recuperada desde el disco, el sistema debe solicitar la lectura de la página y poner al
proceso en estado de espera.
1.3. Cuando la lectura del disco haya terminado se debe modificar la tabla interna, antes
mencionada, y la tabla de páginas para indicar que la página está en la memoria.
1.4. Reiniciar la instrucción que fue interrumpida por la excepción. Generalmente esto se
hace colocando el proceso nuevamente en la cola de preparados y dejando que el
asignador lo reinicie cuando sea escogido por el planificador de la CPU.
Un caso extremo de la paginación bajo demanda es la paginación bajo demanda pura. En ella la
4-115
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
ejecución de un proceso se inicia sin cargar ninguna página en la memoria. Cuando el sistema
operativo sitúa al contador de programas en la primera instrucción del proceso –que es una página
no residente en memoria– se genera inmediatamente un fallo de página. La página es cargada en la
memoria –tal y como hemos descrito anteriormente– y el proceso continua ejecutándose, fallando
cuando sea necesario con cada página que necesite y no esté cargada. Las principales ventajas de la
paginación bajo demanda pura son:
● El inicio de la ejecución de un proceso es mucho más rápido que si se cargara todo el proceso
desde el principio.
● Tabla de páginas con habilidad para marcar entradas inválidas, ya sea utilizando un bit
específico o con valores especiales en los bits de protección.
● Disponibilidad de una memoria secundaria. En esta memoria se guardan las páginas que no
están presentes en la memoria principal. Normalmente se trata de un disco conocido como
dispositivo de intercambio, mientras que la sección de disco utilizada concretamente para
dicho propósito se conoce como espacio de intercambio o swap.
4-116
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
número de fallos de páginas. En el peor de los casos, en cada instrucción un proceso puede intentar
acceder a una página distinta empeorando notablemente el rendimiento. Sin embargo esto no ocurre
puesto que los programas tienden a tener localidad de referencia (véase el apartado 4.5.9).
Por tanto, para calcular el tiempo de acceso efectivo Tem necesitamos estimar el tiempo de fallo de
página Tfp, que se consume fundamentalmente en:
● Servir la excepción de fallo de página. Esto incluye capturar la interrupción, salvar los
registros y el estado del proceso, determinar que la interrupción es debida a una excepción de
fallo de página, comprobar si la página es legal y determinar la localización de la misma en el
disco. Aproximadamente, en realizar esta tarea el sistema puede tardar de 1 a 100μs.
● Leer la página en un marco libre. En esta tarea se puede tardar alrededor de 8ms, pero este
tiempo puede ser mucho mayor si el dispositivo está ocupado y se debe esperar a que se
realicen otras operaciones.
4-117
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
Como se puede apreciar la mayor parte del tiempo de fallo de página es debido al tiempo requerido
para acceder al dispositivo de intercambio.
Para ilustrar el cálculo del tiempo de acceso efectivo a la memoria: sólo vamos a considerar el
tiempo requerido para acceder al dispositivo de intercambio –ignorando las otras tareas a realizar
durante el fallo de página– vamos suponer que el tiempo de acceso a la memoria Tm es de 200 ns y
que la probabilidad p es muy pequeña (es decir, p≪1 ):
Como se puede apreciar el tiempo de acceso efectivo es proporcional a la tasa de fallos de página
r fp = pT fp .
Por ejemplo, si un proceso causa un fallo de página en uno de cada 1000 accesos (p = 0,001), el
tiempo de acceso efectivo es de 8,2 ms. Es decir, el rendimiento del sistema es 40 veces inferior
debido a la paginación bajo demanda. Por tanto es necesario mantener la tasa de fallos de página
lo más baja posible para mantener un rendimiento adecuado.
4-118
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
de los programas durante el inicio del proceso, para después realizar la paginación bajo
demanda sobre dicha copia.
● Otra alternativa es cargar las páginas desde el archivo que contiene la imagen cuando son
usadas por primera vez pero siendo escritas en el espacio de intercambio cuando dichas
páginas tiene que ser reemplazadas. Esta aproximación garantiza que sólo las páginas
necesarias son leídas desde el sistema de archivos reduciendo el uso de espacio de
intercambio, mientras que las siguientes operaciones de intercambio se hacen sobre dicho
espacio.
● También se puede suponer que el código de los procesos no puede cambiar. Esto permite
utilizar el archivo de la imagen binaria para recargar las páginas de código, lo que también
evita escribirlas cuando son sustituidas. Sin embargo el espacio de intercambio se sigue
utilizando para las páginas que no están directamente asociadas a un archivo, como la pila o
el montón de los procesos. Este método parece conseguir un buen compromiso entre el tamaño
del espacio de intercambio y el rendimiento. Por eso se utiliza en la mayor parte de los sitemas
operativos modernos.
4.5.5. Copy-on-write
El copy-on-write o copia durante la escritura permite la creación rápida de nuevos procesos,
página A
página B página B
sistema operativo
4-119
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
minimizando la cantidad de páginas que deben ser asignadas a estos. Para entenderlo es importante
recordar que la llamada al sistema fork() crear un proceso hijo cuyo espacio de direcciones es un
duplicado del espacio de direcciones del padre. Indudablemente esto significa que durante la
llamada es necesario asignar suficientes marcos de memoria física como para alojar las páginas del
nuevo proceso hijo. El copy-on-write minimiza de la siguiente manera el número de marcos que
deben ser asignadas al nuevo proceso:
1. Cuando la llamada al sistema fork() crea el nuevo proceso lo hace de forma que éste
comparta todas sus páginas con las del padre (véase la Figura 4.6). Sin el copy-on-write el
fork() tendría que asignar marcos de memoria física a el hijo, para a continuación copiar las
páginas del padre en ellos. Sin embargo con el copy-on-write padre e hijo mapean sus páginas
en los mismos marcos, evitando tener que asignar memoria libre.
2. Las páginas compartidas se marcan como copy-on-write. Para ello se puede marcar todas las
páginas como de solo lectura en la tabla de páginas de ambos procesos y utilizar una tabla
interna alojada en el PCB para indicar cuales son realmente de sólo lectura y cuales están en
copy-on-write. Es importante destacar que realmente sólo las páginas que pueden ser
modificadas se marcan como copy-on-write. Las páginas que no puede ser modificadas –por
ejemplo las que contienen el código ejecutable del programa– simplemente pueden ser
compartidas como de sólo lectura por los procesos, como hemos comentado anteriormente.
página A
página B página B
sistema operativo
4-120
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
3. Si algún proceso intenta escribir en una página copy-on-write, la MMU genera una
excepción para notificar el suceso al sistema operativo. Siguiendo lo indicado en el punto
anterior, la excepción se originaría porque la página está marcada como de solo lectura, por lo
que el sistema operativo debería comprobar si se trata de un acceso a una página
copy-on-write o a un intento real de escribir en una página de sólo lectura. Para ello el sistema
sólo tendría que mirar la tabla interna almacenada en el PCB. Si se ha intentado escribir en
una página de solo lectura, el proceso ha cometido un error y generalmente debe ser
terminado.
4. Si el sistema detecta una escritura a una página de copy-on-write sólo tiene que copiarla en
un marco libre y mapearlo en el espacio de direcciones del proceso (véase la Figura 4.7). Para
esto se sustituye la página compartida por otra que contiene una copia pero que ya no está
compartida. Indudablemente la nueva página debe ser marcada como de escritura para que en
el futuro pueda ser modificada por el proceso.
5. La página original marcada como copy-on-write puede ser marcada como de escritura y no
como copy-on-write, pero sólo si ya no va a seguir siendo compartida. Esto es así porque una
página marcada como copy-on-write puede ser compartida por varios procesos.
6. El sistema operativo puede reiniciar el proceso. A partir de ahora éste puede escribir en la
página sin afectar al resto de los procesos. Sin embargo puede seguir compartiendo otras
páginas en copy-on-write.
El copy-on-write permite ahorrar memoria y tiempo en la creación de los procesos puesto que sólo
se copian las páginas que son modificadas por éstos, por lo que se trata de una técnica común en
múltiples sistemas operativos, como por ejemplo Microsoft Windows, Linux y Solaris.
● Cuando una región del espacio de direcciones queda marcada para ser mapeada sobre una
región de un archivo se utiliza una estrategia similar a la comentada para el método básico de
4-121
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
la paginación bajo demanda. La diferencia es que las páginas son cargadas desde dicho
archivo y no desde el espacio de intercambio. Es decir, en un primer acceso a una página
mapeada se produce un fallo de página que es resuelto por el sistema operativo leyendo una
porción del archivo en el marco asignado a la página.
● Esto significa que la lectura y escritura del archivo se realiza a través de lecturas y escrituras
en la memoria, lo que simplifica el acceso y elimina el costo adicional de las llamadas al
sistema: read(), write(), etc.
● Las escrituras en disco se suelen realizar de forma asíncrona. Para ello el sistema operativo
comprueba periódicamente las páginas modificadas y las escribe en disco.
● Los marcos utilizados en el mapeo pueden ser compartidos, lo que permite compartir los
datos de los archivo. Además se puede incluir soporte de copy-on-write, lo que permite a los
procesos compartir un archivo en modo de sólo lectura pero disponiendo de sus propias copias
de aquellas páginas que modifiquen. Indudablemente para que los procesos puedan compartir
datos es necesario que exista algún tipo de coordinación (véase el apartado 3.3.3).
Algunos sistemas operativos ofrecen el servicio de mapeo de archivos en la memoria sólo a través
de una llamada al sistema concreta, permitiendo utilizar las llamadas estándar – read(), write(),
etc.– para hacer uso de la E/S tradicional. Sin embargo muchos sistemas modernos utilizan el
mapeo en la memoria independientemente de que se pidan o no. Por ejemplo, en Linux si un
proceso utiliza llamada al sistema mmap() es porque explícitamente pide que el archivo sea
mapeado en memoria. Por tanto, el núcleo mapea el archivo en el espacio de direcciones del
proceso. Sin embargo, si un archivo es abierto con llamadas al sistemas estándar –como open()–
Linux mapea el archivo en el espacio de direcciones del núcleo y traduce las llamadas read() y
write() en accesos a la memoria en dicha región. No importa como sea abierto el archivo, Linux
trata toda la E/S a archivos como mapeada en memoria, permitiendo que el acceso a los mismos
tenga lugar a través del eficiente componente de gestión de la memoria.
4-122
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
disco y utilizar el marco de la misma para cargar la nueva página. Es decir, debemos modificar la
subrutina descrita en el apartado 4.5.2 de la siguiente manera:
1.2. El núcleo debe buscar un marco de memoria libre que, por ejemplo, se puede escoger
de la lista de marcos libres del sistema.
1.3. Se solicita una operación de disco para leer la página deseada en el marco asignado.
Para evitar mantener la CPU ocupada, el sistema debe solicitar la escritura de la
página y poner al proceso en estado de espera.
1.4. Cuando la lectura del disco haya terminado se debe modificar la tabla interna de
páginas válidas y la tabla de páginas para indicar que la página está en la memoria.
Es importante destacar que en caso de reemplazo se necesita realizar dos accesos al disco. Esto se
puede evitar utilizando un bit de modificado asociado a cada página en la tabla de páginas.
● Se puede evitar escribir en disco aquellas páginas que tienen este bit a 0 cuando son
seleccionada para reemplazo, siempre que el contenido de la página no haya sido sobreescrito
por otra en el espacio de intercambio
● Un algoritmo de asignación de marcos que se encarga de asignar los marcos a los procesos.
4-123
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
Obviamente estos algoritmos deben ser escogidos de forma que mantengan la tasa de fallos de
página lo más baja posible.
Otros algoritmos de reemplazo pueden utilizar uno o varios de los siguientes criterios:
● Reemplazar la página que hace más tiempo que fue cargada. Este criterio da lugar al
algoritmo FIFO de reemplazo que no siempre tiene un buen rendimiento puesto que la página
más antigua no necesariamente es la que se va a tardar más tiempo en necesitar –que sería la
elección óptima–.
● Reemplazar la página que hace más tiempo que fue utilizada bajo la hipótesis de que si una
página no ha sido usada durante un gran periodo de tiempo, entonces es poco probable que
vaya a serlo en el futuro. Este criterio da lugar a la familia de algoritmos LRU (Least Recently
Used):
○ Estos algoritmos requieren de soporte por parte del hardware puesto que al sistema
operativo no se le notifican los acceso legales a las páginas, por lo que no tiene forma
de saber cuando una página fue usada por última vez.
54 Se trata de una aproximación puesto que usando el bit de referencia el sistema operativo no puede conocer con
exactitud la última vez que una página fue utilizada. Sin embargo, aunque existen soluciones exactas que hacen uso
de un contador o de una pila que se actualiza en cada acceso a las páginas, se trata de soluciones muy costosas como
para ser implementarlas en hardware.
4-124
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
○ Dentro de los algoritmos NRU también están aquellos que son mejorados incluyendo el
valor del bit de modificado en el criterio de elección de la página. Estos algoritmos
escogen las páginas no referencias antes que las referencias –para lo que utilizan el valor
del bit de referencia– y dentro de cada clase las no modificadas antes que las
modificadas –para lo que utilizan el valor del bit de modificado– para evitar en lo
posible reemplazar páginas cuyo contenido tiene que ser escrito en disco.
● Reemplazar la página que ha sido usada con mayor o menos frecuencia utilizando contadores
de referencias para cada página –almacenados en la tabla de páginas– que sos actualizados por
el hardware en cada referencia. Este criterio da lugar a los algoritmos LFU (Least Frequently
Used) –cuando se escogen las páginas utilizadas con menos frecuencia– y MFU (Most
Frequently Used) –cuando se escogen las páginas utilizadas con más frecuencia–.
● Se puede mantener una lista de marcos libres. Cuando se produce un fallo de paginas se
escoge un marco de la lista y se carga la página, al tiempo que se selecciona una página como
víctima y se copia al disco. Esto permite que el proceso se reinicie lo antes posible, sin esperar
a que la página reemplazada sea escrito en el disco. Posteriormente, cuando la escritura
finalice, el marco es incluido en la lista de marcos libres.
● Una mejora de lo anterior sería recordar que página estuvo en cada marco antes de que éste
pasara a la lista de marcos libres. De esta forma las páginas podrían ser recuperadas
directamente desde la lista si fallara alguna antes de que su marco fuera utilizado por otra
página. Esto permite reducir los efectos de que el algoritmo de reemplazo escoja una víctima
equivocada.
4-125
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
● En el reemplazo local sólo se pueden escoger marcos de entre los asignados al proceso.
● En el reemplazo global se pueden escoger marcos de entre todos los del sistema,
independientemente de que estén asignados a otro proceso o no.
Generalmente el reemplazo global proporciona mayor rendimiento por lo que es el método más
utilizado.
4-126
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
● Cuando ocurre un fallo de página la instrucción que la ha provocado debe ser reiniciada
después de cargar la página en un marco libre. Por lo tanto un proceso debe disponer de
suficientes marcos como para guardar todas las páginas a las que una simple instrucción
pueda acceder, pues de lo contrario el proceso nunca podría ser reiniciado al fallar
permanentemente en alguno de los acceso a memoria de la instrucción. Obviamente este límite
viene establecido por la arquitectura de la máquina.
● Todo proceso tiene una cierta cantidad de páginas que en cada instante son utilizadas
frecuentemente. Si el proceso no dispone de suficientes marcos como para alojar dichas
páginas, generará fallos de página con demasiada frecuencia. Esto afecta negativamente al
rendimiento del sistema, por lo que es conveniente que el sistema asigne al número de marcos
necesario para que eso no ocurra.
4.5.9. Hiperpaginación
Se dice que un proceso sufre de hiperpaginación cuando gasta más tiempo paginando que
ejecutándose.
a) Causas de la hiperpaginación
En los primeros sistemas multiprogramados que implementaron la paginación bajo demanda era
posible que se diera el siguiente caso:
2. Si un proceso necesitaba demasiada memoria, le podía quitar los marcos a otro puesto que se
utilizaba un algoritmo de reemplazo global. Esto podía ocasionar que aumentara la tasa de
fallos de página del proceso que perdía los marcos.
3. Al aumentar los fallos de pagina el uso de la CPU decrecía, por lo que el sistema operativo
4-127
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
hiperpaginación
grado de multiprogramación
cargaba más procesos para aumentar el grado de multiprogramación y con ello el uso de la
CPU.
4. Esto reducía la cantidad de memoria disponible para cada proceso, lo que aumentaba la tasa
de fallos de páginas que nuevamente reducía el uso de la CPU
El fenómeno comentado se ilustra en la Figura 4.8 donde el uso de la CPU es trazado frente al
número de procesos cargados en el sistema. Cuando esto último aumenta el uso de la CPU aumenta
hasta alcanzar un máximo. Si el grado de multiprogramación supera dicho punto, el sistema
comienza a hiperpaginar, por lo que el uso de la CPU disminuye bruscamente. Por lo tanto, si el
sistema está hiperpaginando, es necesario reducir el grado de multiprogramación con el objetivo de
liberar memoria.
En los sistemas de tiempo compartido modernos ocurre algo parecido a lo descrito para los sistemas
multiprogramados, aunque sin el efecto en cadena ocasionado por el intento del planificador de
largo plazo de maximizar el uso de la CPU, ya que estos sistemas carecen de dicho planificador. Sea
como fuere, en ambos casos los procesos hiperpaginarán si no se les asigna un número suficiente
de marcos.
b) Soluciones a la hiperpaginación
Para el problema de la hiperpaginación existen diversas soluciones:
4-128
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
● Utiliza un algoritmo de reemplazo local pues de esta manera un proceso que hiperpagina no
puede afectar a otro. Sin embargo, el uso intensivo del dispositivo de intercambio podría
afectar al rendimiento del sistema al aumentar el tiempo de acceso efectivo.
● Proporcionar a un proceso tantos marcos como le hagan falta. Como ya hemos comentados
en diversas ocasiones, para evitar la hiperpaginación es necesario asignar al procesos al menos
un número mínimos de marcos, que a priori no es conocido. Una de las estrategias que
pretenden estimar dicho número es el modelo de conjunto de trabajo.
Por ejemplo, cuando se invoca una subrutina se define una nueva localidad. En esta localidad las
referencias a la memoria se realizan al código de la subrutina, a las variables locales de la misma y a
algunas variables globales del programa.
Supongamos que proporcionamos a un proceso suficientes marcos como para alojar toda su
localidad en un momento dado. Entonces el proceso generará fallos de página hasta que todas las
páginas de su localidad estén cargadas, pero después de eso no volverá a fallar hasta que no cambie
a una nueva localidad. Sin embargo si damos al proceso menos marcos de los que necesita su
localidad, éste hiperpaginará.
El modelo de conjunto de trabajo es una estrategia que permite obtener una aproximación de la
localidad del programa y consiste en lo siguiente:
4-129
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
Obviamente la precisión del conjunto de trabajo como aproximación de la localidad del programa
depende del parámetro Δ. Por ejemplo:
1. Se selecciona Δ.
3. Si sobran suficientes marcos otro proceso puede ser iniciado –en el caso de los sistemas
multiprogramados– o se puede destinar la memoria libre a otros usos.
Donde el tamaño del conjunto de trabajo D es la suma del tamaño de los conjuntos de trabajo WSSi
para cada proceso i:
y representa la demanda total de marcos. Por eso si D es mayor que el número de marcos
disponibles, habrá hiperpaginación.
4-130
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
Este sencillo algoritmo anterior permite evitar la hiperpaginación. Sin embargo, el problema está en
como mover la ventana del conjunto de trabajo en cada referencia, con el fin de volver a calcular el
conjunto de trabajo. Una posible aproximación sería utilizar un temporizador que periódicamente
invocase a una subrutina encargada de examinar el bit de referencia de las páginas en la ventana Δ.
Es de suponer que las páginas con el bit de referencia a 1 forman parte de la localidad del programa
y por tanto serán el conjunto de trabajo a lo largo del siguiente periodo.
a) Prepaginado
El prepaginado es una técnica que consiste en cargar múltiples páginas junto con la página
demandada en cada fallo de página. Esas otras páginas se escogen especulativamente bajo la
hipótesis de que van a ser necesitadas por el proceso en un corto espacio de tiempo, de manera que
si la predicción es acertada la tasa de fallos de página se reduce significativamente. Esta técnica
puede ser utiliza, por ejemplo, en las siguiente situaciones:
● En la paginación bajo demanda pura, donde el sistema sabe de antemano que cuando se inicia
un proceso siempre fallan las primeras páginas de código, por lo que son buenas candidatas
para el prepaginado.
En general el único inconveniente del prepaginado es que debe ser ajustarlo para que el coste del
mismo sea inferior al de servir los fallos de página.
4-131
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
Muchos sistemas operativos modernos permiten que los programas que lo soliciten puedan acceder
a los discos en modo raw. En el modo raw no hay sistemas de archivos, ni paginación bajo
demanda, ni bloqueo de archivos, ni prepaginación, ni nada; por lo que dichas aplicaciones deben
implementar sus propios algoritmos de almacenamiento y gestión de la memoria. Sin embargo, hay
que tener en cuenta que la mayor parte de las aplicaciones siempre funcionan mejor utilizando los
servicios convencionales ofrecidos por el sistema operativo.
○ La E/S para acceder al contenido de cada página requiere menos tiempo. En general el
tiempo de transferencia es proporcional a la cantidad de información transferida, lo que
debería beneficiar a los sistemas con páginas de pequeño tamaño. Sin embargo la
latencia y el tiempo requerido para posicionar la cabeza lectora de los discos es muy
superior al tiempo de transferencias de datos, por lo que es más eficiente tener menos
transferencias de mayor tamaño –como cuando se usan páginas de grandes– que más
transferencias de menor tamaño –como cuando se usan páginas pequeñas–.
4-132
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
Vamos a ilustrarlo con el siguiente ejemplo de un programa que inicializa a 0 un array de 128 por
128 elementos.
De manera que si suponemos que el tamaño de cada página es de 128 palabras, en el mejor de los
casos cada fila estará almacenada en una página. Por lo tanto:
55 Es común que los núcleos de los sistemas operativos utilicen páginas de gran tamaño para alojar su código y sus
datos. De esta forma se minimiza el número de entradas de la TLB que utilizan, con el fin de disponer de más
entradas libres para los procesos en ejecución.
4-133
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
● Si el sistema le asigna 128 marcos o más, el proceso solo generará 128 fallos de página.
Sin embargo, el ejemplo sería diferente si el bucle interno del programa recorriera las columnas del
array y no las filas:
Pues se podrían a 0 primero todas las palabras de una misma página antes de empezar con la
siguiente, reduciendo el número de fallos de página a 128 aunque el sistema operativo sólo asigne
un marco al proceso.
● La elección del lenguaje de programación también puede tener efecto. En los lenguajes como
C y C++ se utilizan punteros con frecuencia, lo que aleatoriza el acceso a la memoria
empeorando la localidad de referencia. Además algunos estudios indican que los lenguajes
orientados a objetos tienden a tener peor localidad de referencia que los que no lo son.
○ Separando el código de los datos para permitir que las paginas de código pueda ser de
sólo lectura. Esto es interesante porque las paginas no modificadas no tienen que ser
escritas antes de ser reemplazadas.
○ El compilador puede colocar las subrutinas que se llaman entre sí en la misma página.
○ El cargador puede evitar situar las subrutinas de forma que crucen los bordes de las
páginas.
4-134
4.5. Paginación bajo demanda Sistemas Operativos - 2014/2015
e) Interbloqueo de E/S
Supongamos que un proceso solicita una operación de E/S sobre el contenido de alguna de las
páginas de su espacio de direcciones y que la página es reemplazada después de que el proceso
queda en espera pero antes de que la operación es realizada. En ese caso la operación de E/S se
podría acabar realizando sobre una página que pertenece a un proceso diferente. Para evitarlo
existen diversas soluciones:
● Se puede utilizar la memoria del núcleo como buffer en las operaciones de E/S. En una
escritura esto obliga a la llamada al sistema a copiar los datos desde las páginas del proceso a
la memoria del núcleo antes de solicitar la operación de E/S. Mientras que en las operaciones
de lectura sería justo al contrario.
● Cada página puede tener un bit de bloqueo que se utiliza para indicar que páginas no pueden
ser seleccionadas para reemplazo.
● Bloquear las páginas del núcleo para evitar que sean reemplazadas.
● Bloquear las páginas que acaban de ser cargadas. Esto evita que un proceso de mayor
prioridad pueda reclamar el marco antes de que el proceso para el que se cargó la página sea
reiniciado, desperdiciando el trabajo de cargarla y provocando un nuevo fallo de página. Para
implementarlo se puede poner el bit de bloqueo a 1 cuando la página se carga, volviéndolo a
poner a 0 cuando el proceso es planificado por primera vez después del fallo de página que
provocó la carga de la misma.
● En los sistemas con tiempo real flexible se suele permitir que las tareas de tiempo real
informen de cuales son las páginas más importantes con el fin de que sean bloqueadas para
evitar que puedan ser reemplazadas. Para evitar riesgos, el sistema suele considerar estás
solicitudes como consejos de bloqueo, de manera que es libre de descartar dichos consejos si
el conjunto de marcos libres llega a ser demasiado pequeño o si un proceso concreto pide
bloquear demasiadas páginas.
4-135
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
una llamada al sistema para gestionar su espacio de direcciones virtual. En los sistemas POSIX
–como GNU/Linux– esta llamada es mmap() –junto a su opuesta munmap()– y sirve para:
● Reservar una porción de espacio de direcciones virtual del proceso. Obviamente la llamada
sólo hace la reserva para que dicha región pueda ser usada por el proceso, siendo el
componente de paginación bajo demanda el responsable de asignar la memoria física que la
respalda.
Sin embargo en funciones como mmap() la página es la unidad mínima en la gestión de la memoria.
Es decir, las regiones reservadas del espacio de direcciones virtual siempre comienzan en un borde
de página y su tamaño es múltiplo del tamaño de página. La cuestión es como compatibilizar eso
con las necesidades reales de los programas, que durante su ejecución necesitan reservar y liberar
constantemente memoria para pequeños elementos como: arrays, cadenas de texto, estructuras,
objetos, etc. Para esos casos utilizar directamente mmap() no es una solución puesto que la
fragmentación interna con llevaría un importante derroche de recursos.
Máx.
sistema operativo
pila
montón
datos
código
0x00000000
4-136
4.6. Interfaz de gestión de la memoria Sistemas Operativos - 2014/2015
● La variables y constantes globales se almacenan en la sección de datos, que tiene tamaño fijo
ya que las dimensiones de estas variables se conocen de antemano en tiempo de compilación,
al igual que ocurre con el código del programa.
● Las variables locales y los argumentos de las subrutinas se almacenan en la pila junto con la
direcciones de retorno de las mismas. Esta es la ubicación ideal puesto que la pila es
restablecida, en el retorno, al estado que tenía antes de invocar la subrutina, haciendo que las
variables locales y argumentos desaparezcan automáticamente.
Cada lenguaje de programación debe proporcionar –por ejemplo a través de su librería estándar–
un mecanismo en espacio de usuario adecuado para la gestión en tiempo de ejecución de la
memoria del montón del proceso. Para eso cada lenguaje puede utilizar su propia implementación
de dicho mecanismo o bien recurrir a la proporcionada por la librería del sistema. Por ejemplo, en
C++ los operadores new y delete utilizan sus propios algoritmos de gestión de la memoria del
montón, estando optimizados para la creación y destrucción de objetos de manera eficiente. Sin
embargo, la librería del sistema también proporciona su propia implementación –por ejemplo las
funciones malloc() y free() en el caso de los sistemas POSIX– que es utilizada directamente por
los programas escritos en C y puede ser empleada por otras implementaciones de lenguajes de
programación como soporte de la asignación dinámica de memoria.
4-137
Sistemas Operativos - 2014/2015 4. Gestión de la memoria
3. Si no hay suficiente memoria libre contigua como para atender la petición se utiliza la
llamada al sistema brk() para ampliar el tamaño del montón sobre la región no asignada del
espacio de direcciones virtual del proceso.
Cuando un proceso hace una petición de asignación de memoria dinámica espera que el espacio
ofrecido sea continuo en el espacio de direcciones virtual, por lo que es necesario utilizar algún
algoritmo de asignación de memoria contigua. Como las peticiones de los procesos son de tamaño
variable, la forma más eficiente de enfrentar este problema es utilizando lo que se denomina un
esquema de particionado dinámico:
1. La librería mantiene una lista indicando que regiones del montón están libres y cuales no. El
montón se inicializa con un tamaño determinado completamente libre, por lo que es
considerado como un gran hueco de memoria disponible.
3. Si el proceso libera una porción de la memoria y se crean dos huecos adyacentes, se funden
en uno solo.
En general, en un momento dado tenemos una petición de tamaño n que debemos satisfacer con una
lista de huecos libres de tamaño variable. Esto no es más que un caso particular del problema de la
asignación dinámica de almacenamiento para el que hay diversas soluciones:
● En el primer ajuste se escoge el primer hueco lo suficientemente grande como para satisfacer
la petición. La búsqueda puede ser desde el principio de la lista o desde donde ha terminado la
búsqueda anterior.
● En el mejor ajuste se escoge el hueco más pequeño que sea lo suficientemente grande para
4-138
4.6. Interfaz de gestión de la memoria Sistemas Operativos - 2014/2015
● En el peor ajuste se escoge el hueco más grande. Igualmente obliga a buscar en toda la lista de
huecos o a tenerla ordenada por tamaño.
En la actualidad la estrategia más común es utilizar el mejor ajuste junto con algún tipo de
estructura de datos que mantenga los huecos libres ordenados por tamaño, de manera que puedan
ser encontrados eficientemente.
4.6.3. Fragmentación
Las estrategia comentada no sufre de fragmentación interna porque se asigna exactamente la
cantidad de memoria solicitada. Sin embargo si sufre de otro tipo de fragmentación denominada
fragmentación externa.
La fragmentación externa ocurre cuando hay suficiente espacio libre para satisfacer una petición
pero el espacio no es contiguo. Es decir, el espacio de almacenamiento está fraccionado en un gran
número de huecos de pequeño tamaño, obligando a la librería a invocar la llamada al sistema brk()
con el objetivo de incrementar el tamaño del montón. Este problema:
● Afecta tanto a la estrategia del primer como del mejor ajuste. Siendo el primero mejor en
algunos sistemas y el segundo mejor en otros.
● Algunos análisis estadísticos realizados con el primer ajuste revelan que incluso con algunas
optimizaciones, con n bloques asignados se pierden 0.5n por fragmentación externa. Es decir,
un tercio de la memoria no es utilizable. A esto se lo conoce como la regla del 50%.
Lamentablemente este problema no tiene una solución sencilla ya que aunque se podría intentar
mover los bloques de memoria para que toda la memoria libre quedara en un único hueco, sería
necesario modificar en tiempo de ejecución las direcciones virtuales utilizadas por el proceso.
4-139
5. Gestión del almacenamiento
sector
sector de
una pista
pista /
cilindro
Desde el punto de vista lógico (véase la Figura 5.2) la superficie de cada plato está dividida en
pistas circulares, cada una de las cuales se subdivide en sectores. El conjunto de pistas formado
por todas aquellas que están situadas en la misma posición en los distintos platos se denomina
cilindro.
En este tipo de discos la información se almacena siguiendo un recorrdio continuo en espiral que
cubre la superficie entera del disco, extendiéndose desde el interior hacia el exterior. Dado que el
5-142
5.1. Dispositivos de almacenamiento Sistemas Operativos - 2014/2015
láser simpre debe desplazarse sobre la espiral, el acceso aleatorio a los datos es más lento que con
otras tecnologías de disco.
El sistema operativo puede ofrecer esta abstracción gracia al sistema de archivos. Este proporciona
los mecanismos para el almacenamiento de lo datos y programas, tanto del propio sistema
operativo como los de todos los usuarios del sistema informático, así como para acceder a dichos
datos y programas.
● Una colección de archivos, cada uno de los cuales almacena una serie de datos relacionados.
● Una colección de estructuras de metadatos, que contienen información relativa a los archivos
almacenados –nombre, ubicación en el disco, permisos, etc.– y que se encarga de organizarlos,
generalmente haciendo uso de una estructura de directorios.
5-143
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
A continuación comentaremos brevemente las tecnologías utilizadas con mayor frecuencia para
construir estos volúmenes.
5.3.1. RAID
La tecnología RAID (Redundant Array of Inexpensive Disks) permite combinar varios discos duros
para mejorar las prestaciones a través del paralelismo en el acceso y/o para mejorar la fiabilidad a
través del almacenamiento de información redundante. En concreto se definen diversos niveles
RAID, de entre los cuales los más comunes son:
● En un conjunto RAID 1 se crea una copia exacta –en espejo– de los datos en dos o más
discos. El resultado es que, incluso con dos discos, se incrementa exponencialmente la
fiabilidad respecto a tener uno solo, ya que para que el conjunto falle es necesario que lo
hagan todos los discos. Adicionalmente el rendimiento en las operaciones de lectura se
incrementa linealmente con el número de copias, ya que los datos están disponibles en todos
los discos al mismo tiempo, por lo que se pueden balacear la operaciones de lectura entre
todos ellos.
5-144
5.3. Volúmenes de datos Sistemas Operativos - 2014/2015
entre dos o más discos y se utiliza uno adicional para almacenar la información de paridad
de los bloques de una misma división 56. El disco utilizado para almacenar el bloque de paridad
cambia de forma escalonada de una división a la siguiente, de ahí que se diga que el bloque de
paridad está distribuido. Algunos aspectos adicionales a tener en cuenta son que:
○ Cada vez que se escribe un bloque de datos se debe actualizar el bloque de paridad. Por
lo tanto las escrituras en un conjunto RAID 5 son costosas en términos de operaciones
de disco y tráfico.
○ Los bloques de paridad no se leen durante las lecturas de datos, ya que eso reduciría el
rendimiento. Sólo se hace en caso de que la lectura de un sector falle, puesto que el
sector en la misma posición relativa dentro de cada uno de los otros bloques de datos de
la división y en el bloque de paridad se pueden utilizar para reconstruir el sector
erroneo.
● En un conjunto RAID 6 se utiliza la misma estrategia que en RAID 5 pero utilizando dos
bloques de paridad, lo que permite que fallen hasta dos discos sin perder los datos.
● En un conjunto con niveles anidados se combinan varios niveles RAID básicos como si fueran
capas superpuestas. Ejemplos típicos son:
○ RAID 1+0 o RAID 10, donde diversos conjuntos en espejo se combina en un RAID 0,
aumentando la capacidad total.
● RAID puede implementarse en el hardware de la controladora de disco, de tal forma que sólo
los discos conectados a esta pueden formar parte de un conjunto RAID determinado. Esta
56 En RAID se denomina división o stripe a la serie de bloques consecutivos escogido cada uno de uno de los discos
del conjunto.
5-145
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
solución es muy eficiente, especialmente cuando se utilizan niveles que requieren cálculo de la
paridad, ya que se evita utilizar tiempo de CPU para ese trabajo. Sin embargo estas
controladoras son notablemente más caras que las que carecen de soporte para RAID.
● RAID puede implementarse dentro del sistema operativo en lo que se denomina el software de
gestión de volúmenes. En este caso las soluciones RAID con paridad son bastante lentas por
lo que normalmente sólo se soportan los niveles RAID 0, 1, 10 o 0+1. Además algunas
controladoras modernas que dicen venir con soporte RAID realmente implementan esta
tecnología en software, a nivel del controlador de dispositivo, mientras que en el hardware
sólo se implementan unas características de apoyo mínimas57.
Cada conjunto RAID se comporta como una unidad de almacenamiento independiente desde el
punto de vista del resto del sistema, por lo que se puede utilizar entero para albergar un único
sistema de archivos. Sin embargo lo más común es dividirlo en regiones con el objeto de utilizar
múltiples sistemas de archivos o combinarlo en estructuras de mayor tamaño, para lo cuál se pueden
utilizar alguna de las técnicas que veremos a continuación.
5.3.2. Particiones
Un disco, un conjunto RAID o cualquier otro dispositivo de almacenamiento se puede dividr en
regiones para utilizar en cada una de ellas un sistema de archivos diferente. A esas regiones se las
conoce comúnmente como particiones, franjas o minidiscos.
Según la plataforma, existen diversas maneras de implementar el soporte de particiones. Entre los
sistemas de escritorio las tecnologías más difundidas y utilizadas son la MBR (Master Boot Record)
y la GPT (GUID Partition Table). En ámbas se almacena, en los primeros sectores del dispositivo
de almacenamiento, una tabla con una entrada por partición donde se guardan las direcciones del
primer y último sector de cada una de ellas en el dispositivo, así como otra información. Eso es
todo lo que necesita el sistema operativo para determinar los límites de la región ocupada por cada
sistema de archivos.
5-146
5.3. Volúmenes de datos Sistemas Operativos - 2014/2015
Para resolverlo algunos sistemas operativos incluyen un software de gestión de volúmenes que hace
uso de tecnología propia para superar estas limitaciones. Estas herramientas generalmente permiten
agrupar dispositivos completos, conjuntos RAID, particiones, etc. y sobre ellos construir los
volúmenes que sean necesarios. Estos volúmenes pueden ser redimensionados –en ocasiones sin
tener que deterner la ejecución del sistema operativo– y en caso de que haga falta se pueden incluir
dinámicamente nuevos dispositivos para incrementar el espacio disponible. Además, como ya
hemos comentado, el software de gestión de volúmenes puede incluir alguna funcionalidad propia
de conjuntos RAID con el objeto de mejorar las prestaciones, a través del paralelismo en el acceso,
y/o mejorar la fiabilidad, a través del almacenamiento de información redundante.
programas de aplicación
control de E/S
dispositivos
5-147
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
58 Dependiendo de la unidad de disco, los sectores pueden tener tamaños de entre 32 bytes y 4096 bytes. Lo más
común es que su tamaño sea de 512 bytes.
5-148
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
gestor de espacio libre, que controla los bloques no asignados y proporciona dichos bloques
cuando el módulo de organización de archivos lo necesita.
4. El sistema lógico de archivos gestiona los metadatos. Los metadatos incluyen toda la
estructura del sistema de archivos, excepto los propios datos de los archivos. Entre dichos
metadatos está la estructura de directorios y los bloques de control de archivo. Un bloque de
control de archivo o FCB (File Control Block) contiene información acerca del archivo,
incluyendo su propietario, los permisos y la ubicación del contenido del mismo. Además, el
sistema lógico de archivos también es responsable de las tareas de protección y seguridad.
Cada sistema operativo puede soportar uno o más sistemas de archivos para dispositivos de disco.
Por ejemplo, en los sistemas UNIX se utiliza el sistema de archivos UNIX o UFS (UNIX File
System), que está basado en el sistema FFS (Fast File System) de Berkeley. Microsoft Windows
NT/2000/XP soporta los sistemas de archivo FAT, FAT32 y NTFS (NT File System). En Linux se
soportan más de cuarenta sistemas de archivo, entre los que podríamos destacar: el sistema de
archivos extendido –ext2, ext3 y ext4– XFS y BtrFS. Además la mayoría de los sistemas operativos
modernos soportan otros sistemas de archivo, como los utilizados en los soportes removibles. Por
ejemplo el ISO-9660, utilizado por la mayor parte de los CD-ROM, o el UFS (Universal File
System), utilizado por los DVD-ROM.
● Un bloque de control de arranque (bloque de inicio o sector de arranque) que suele ocupar
el primer bloque de cada volumen y que contiene la información necesaria para iniciar un
sistema operativo a partir de dicho volumen. Este bloque puede estar vacío, si el volumen no
contiene un sistema operativo.
● Un bloque de control de volumen que contiene todos los detalles acerca del volumen, tales
como: el número máximo de bloques, el tamaño de los bloques, el número de bloques libres y
punteros a los mismos, así como un contador de bloques de información FCB y punteros a
estos. En los sistemas de archivos para UNIX y Linux, a esta estructura se la denomina
5-149
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
● Un FCB por cada archivo donde se almacenan numerosos detalles sobre el mismo, por
ejemplo: los permisos, el propietario, el tamaño y la ubicación de los bloques de datos. En
términos generales todos los FCB del sistema de archivos se almacenan en una tabla
denominada irectorio de dispositivo o abla de contenidos del volumen. En los sistemas de
archivos para UNIX y Linux cada FCB se denomina inodo y se almacenan a continuación del
superbloque. En NTFS esta información se almacena en la MFT, ya que cada entrada de dicha
tabla es un FCB.
● Una estructura de directorios para organizar los archivos. En los sistemas de archivos para
UNIX y Linux, cada directorio almacena los nombres de los archivos que contiene y los
números de FCB asociados a los mismos. En NTFS es similar aunque la estructura de
directorios completa se almacena en la MFT.
La información almacenada en memoria se utiliza tanto para la gestión del sistema de archivo como
para mejorar el rendimiento del mismo mediante mecanismos de caché. Los datos se cargan en el
momento comenzar a utilizar el sistema de archivos del –montaje– y se descartan cuando se va a
dejar de hacer uso del mismo –desmontaje–. Las estructuras existentes en la memoria pueden
incluir las que a continuación se describen:
● Una tabla de montaje en memoria que contiene información acerca de cada volumen
montado.
● La tabla global de archivos abiertos que contiene una copia del FCB de cada archivo abierto
en el sistema, además de otras informaciones.
5-150
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
5.4.4. Archivos
Cada sistema de archivos contiene una tabla donde cada entrada almacena un bloque de control de
archivo o FCB (File Control Block) por archivo. Concretamente en cada FCB se almacena diversa
información acerca del archivo al que representa.
a) Atributos de archivos
La colección de atributos asociada a un archivo varía de un sistema operativo a otro, pero
típicamente son los siguientes:
5-151
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
● Nombre. Nombre simbólico del archivo que se mantiene en un formato legible para
conveniencia de las personas.
● Tipo. Es un atributo necesario en los sistemas que soportan diferentes tipos de archivos.
● Tamaño. Indica el tamaño actual de archivo (en bytes, palabras o bloques) y, posiblemente, el
tamaño máximo permitido.
● Protección. Información de control de acceso que determina quién puede leerlo, escribirlo,
ejecutarlo, etc.
● Fecha, hora e identificación del usuario. Esta información puede mantenerse para los
sucesos de creación, de última modificación y último uso del archivo. Esto puede resultar útil
para la protección, seguridad y monitorización del uso del archivo.
Los atributos de los archivos se almacenan en las estructuras de metadatos. Normalmente el nombre
se almacena en la estructura de directorios, de tal manera que una entrada de directorio está
compuesta del nombre de un archivo y de su identificador. A su vez, dicho identificador permite
localizar el FCB que contiene el resto de los atributos del archivo.
59 Generalmente el sistema mantiene un puntero de lectura/escritura que hace referencia a la ubicación dentro del
archivo en la que debe tener lugar la siguiente operación. Este puntero se actualiza avanzando cada vez que se
realiza un nueva lectura/escritura. Para desplazarse aleatoriamente por el archivo, el sistema operativo debe ofrecer
una llamada al sistema que permita reposicionar el puntero allí donde interese.
5-152
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
para consultar y modificar diversos atributos de un archivo, como la longitud o el propietario del
mismo.
La mayor parte de estas operaciones implican realizar una búsqueda en el directorio para encontrar
la entrada asociada con el archivo cuyo nombre se ha indicado. Para evitarlo muchos sistemas
requieren60 que el proceso haga una llamada al sistema open(), antes de realizar cualquiera de
estas operaciones por primera vez sobre un archivo. En concreto esta llamada al sistema:
1. Busca en el directorio el nombre del archivo hasta encontrar la entrada sociada y recupera el
identificador del mismo
3. Crea una entrada para el archivo en la tabla de archivos abiertos donde se almacena la
información del FCB.
El nombre con el que se designa a esas entradas en la tabla de archivos abiertos varía de unos
sistemas a otros. En los sistemas UNIX se utiliza el término descriptor de archivo –o file
descriptor– mientras que en los sistemas Microsoft Windows se prefiere el término manejador de
archivo –o file handler–.
Después de utilizar la llamada al sistema open(), cuando se desee solicitar una operación sobre un
archivo sólo es necesario proporcionar el identificador devuelto, evitando así que haga falta realizar
exploración alguna del directorio. Cuando el archivo deja de ser utilizado activamente por el
proceso, puede ser cerrado utilizado la llamada al sistema close().
En los sistemas operativos donde varios procesos pueden abrir un mismo archivo se suelen utilizar
dos niveles de tablas de archivos abiertos:
1. Una tabla para cada proceso –almacenada en el PCB– donde se indican todos los archivos
que éste ha abierto. En dicha tabla se almacena toda la información referente al uso de cada
archivo por parte de un proceso. Por ejemplo se puede almacenar la posición actual utilizada
por las operaciones de lectura y escritura o los derechos de acceso.
60 En unos pocos sistemas los archivos se abren automáticamente cuando un proceso solicita su primera operación
sobre los mismos y se cierran cuando el proceso termina. Sin embargo lo más común es que los procesos tengan que
abrir los archivos explícitamente.
5-153
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
2. Una tabla global para todo el sistema donde se almacena toda la información independiente
de los procesos, como la ubicación del archivo en el disco, las fechas de acceso y el tamaño
del archivo.
Cuando un proceso invoca la llamada open() se añade una entrada en la tabla de archivos abiertos
del proceso, que a su vez apunta a la entrada correspondiente dentro de la tabla global del sistema.
Si el archivo no existe en esta última, también hay que crear una entrada en la tabla global del
sistema haciendo uso de la información contenida en el FCB correspondiente. Por otro lado es muy
común que la tabla global almacene un contador de aperturas para cada archivo con el objetio de
indicar cuantos procesos lo mantienen abierto. Dicho contador se decrementa con cada llamada al
sistema close(), de forma que cuando alcance el cero querrá decir que la entrada puede ser
eliminada de la tabla global de archivos abiertos.
c) Tipos de archivo
Cuando se diseña un sistema operativo es necesario considerar si debe reconocer y soportar el
concepto de tipo de archivo. Si el sistema operativo reconoce el tipo de un archivo puede operar con
el mismo de formas razonables. Por ejemplo, el sistema puede impedir que un usuario intente
imprimir los archivos que contienen programas en formato binario, pues el documento impreso
sería ininteligible.
En los sistemas operativos más comunes las técnicas utilizadas para implementar los tipos de
archivo son las siguientes:
● En MSDOS y Microsoft Windows el tipo de archivo se incluye como parte del nombre del
archivo. Es decir, el nombre se divide en dos partes: un nombre y una extensión; normalmente
separadas por un carácter de punto. El sistema puede utilizar la extensión para conocer el tipo
de archivo y el tipo de operaciones que se pueden realizar con el mismo.
● En Mac OS X cada archivo tiene un atributo que almacena el tipo (por ejemplo, TEXT para los
archivos de texto o APPL para las aplicaciones) y otro que contiene el nombre del programa
que lo creó. Cuando el usuario hace clic con el ratón sobre el icono de un archivo, el programa
que lo creó se ejecuta automáticamente y el archivo se carga en la memoria.
5-154
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
a) Directorios de un nivel
En la estructura de directorios de un nivel todos los archivos están contenidos en un único
directorio; sin embargo esto presenta algunas limitaciones:
● Cuando el número de usuarios del sistema aumenta se hace más difícil que cada uno escoja
nombres diferentes para sus archivos, lo cual es necesario puesto que todos los archivos se
encuentran en el mismo directorio.
● Incluso en los sistemas operativos monousuario puede ser difícil para un usuario mantener
organizados sus datos a media que se incrementa el número de archivos.
Este esquema fue utilizado por la primera versión del sistema operativo MSDOS.
5-155
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
realizar un usuarios sobre los archivos a su UFD. Sin embargo, aunque esto resuelve el problema de
la colisión de nombres entre diferentes usuarios, también presenta algunas desventajas:
● La estructura descrita aisla a los usuarios, lo cual puede ser un problema cuando éstos quieren
compartir datos para cooperar en alguna tarea. La solución pasa por utilizar nombres de ruta
para designar a un archivo de forma unívoca. Por ejemplo, si el usuario usera quiere acceder a
su archivo test, simplemente debe referirse a el como test. Mientras que si quiere acceder al
archivo test del usuario userb, debe utilizar un nombre de ruta como /userb/test, donde se
indica el nombre del usuario y el nombre del archivo. En general cada sistema operativo
utiliza su propia sintaxis par nombrar los archivos contenidos en los directorios de otros
usuarios.
● Incluso en este caso puede ser difícil para un usuario mantener organizados sus datos a media
que se incrementa el número de archivos.
Cada sistema de archivos tiene un directorio raíz que puede contener tanto archivos como otros
directorios. A su vez cada directorio puede contener un conjunto de archivos y subdirectorios.
Normalmente cada entrada de directorio incluye un bit donde se indica si dicha entrada apunta a un
archivo o a un subdirectorio. Esto se hace así porque los directorios no son más que archivos con un
formato interno especial, por lo que el sistema debe saber si la entrada apunta a un directorio para
interpretar correctamente los datos del directorio.
Generalmente cada proceso tiene un directorio actual, de forma que cuando se hace referencia a un
archivo se busca en ese directorio. Si se necesita un archivo que no se encuentra en el directorio
actual, entonces el usuario debe especificar un nombre de ruta o cambiar el directorio actual al
directorio donde fue almacenado el archivo. Los nombres de ruta pueden ser de dos tipos:
● Un nombre de ruta absoluto comienza en la raíz y va indicando los directorios que componen
la ruta de forma descendente hasta llegar al archivo especificado.
● Un nombre de ruta relativo define una ruta a partir del directorio actual.
Con una estructura de directorios en árbol se puede permitir que unos usuarios accedan a los
5-156
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
archivos de otros. Para eso sólo es necesario que se utilicen nombres de ruta para designar los
archivos o que se cambie el directorio actual.
Este tipo de estructura de directorios es la utilizada por MSDOS y por las distintas versiones de
Microsoft Windows.
● Se pueden crear una entrada de directorio denominada enlace. Un enlace es, generalmente,
un archivo que contiene la ruta relativa o absoluta de otro archivo o subdirectorio. En los
sistemas UNIX a estos se los conoce como enlaces simbólicos.
Una estructura en grafo acíclico es más flexible que una estructura en árbol, pero no por eso está
exenta de inconvenientes:
● Si estamos intentando recorrer el sistema de archivos completo –por ejemplo, para buscar
un archivo o para copiarlos en un dispositivo de copias de seguridad– debemos evitar
acceder más de una vez a los archivos y subdirectorios compartidos. No olvidemos que en
los sistemas con estructura en grafo acíclico cada archivo puede tener múltiples nombres de
ruta absoluta. Esto es más sencillo de resolver en el caso de los enlaces, puesto que podemos
evitar recorrerlos al ser claramente distinguibles del archivo original.
5-157
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
cuando un usuario lo borra podríamos dejar punteros que referencian a archivos que no
existen.
○ El caso más sencillo de resolver es el de los enlaces ya que pueden ser borrados sin que
el archivo original se vea afectado, puesto que lo que se elimina es el enlace y no el
archivo original.
○ Otra opción es almacenar en la entrada del archivo original un contador con el número
de referencias al archivo. Así, cuando el contador sea 0, sabremos que a llegado el
momento de liberar el espacio asignado. En los sistemas UNIX se utiliza esta técnica
para los enlaces duros.
Por último no debemos olvidar que la estructura de directorios en grafo se conserva acíclica si se
prohíbe que hayan múltiples referencias a un mismo directorio. Ese es el motivo por el que en los
sistemas UNIX no se permite que los enlaces duros hagan referencia a directorios. Sin embargo si
se pueden utilizar enlaces simbólicos para este fin, puesto que al ser distinguibles del directorio
original podemos evitar los ciclos si mientras se explora se ignorar dichos enlaces.
● Es importante evitar encontrar cualquier archivo dos o más veces, tanto por razones de
corrección como de rendimiento.
5-158
5.4. Sistemas de archivos Sistemas Operativos - 2014/2015
● En una estructura de directorios en forma de grafo donde existan ciclos puede que el
contador de referencias no sea 0, aunque no hayan más referencias al archivo. Esto significa
que generalmente se necesita algún mecanismo de recolección de basura 61 para determinar con
seguridad cuando se ha borrado la última referencia. Sin embargo la recolección de basura
para un sistema de archivos basado en disco consume mucho tiempo, por lo que en pocas
ocasiones se utiliza.
Por tanto, es mucho más sencillo trabajar con estructuras de directorio en grafo acíclico. Para evitar
que en un grafo aparezca un ciclo al añadir un nuevo enlace, se pueden utilizar diversos algoritmos.
Sin embargo, y puesto que estos son muy costosos, lo más común es ignorar los enlaces durante el
recorrido de los directorios. En el caso de la duplicación de entradas de directorio (donde las
entradas duplicadas no se pueden distinguir de la original) lo más sencillo es evitar que puedan
haber múltiples referencias a un mismo directorio.
Para implementar la compartición y los mecanismo de protección el sistema debe soportar más
atributos para cada archivo y directorio que los que necesita en un sistema monousuario. Aunque a
lo largo de la historia se han adoptado diversos enfoques, la mayoría han evolucionado hasta utilizar
los conceptos de propietario (o usuario) y grupo de un archivo:
61 La recolección de basura implica recorrer todo el sistema de archivos y marcar todos aquellos elementos que sean
accesibles. Después, en una segunda pasada, se elimina todo lo que no esté marcado.
5-159
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
Los identificadores del propietario y el grupo de un archivo se almacenan junto con los otros
atributos en el FCB. Cuando un usuarios solicita realiza una operación sobre un archivo, se compara
el identificador del usuario con el atributo del propietario para determinar si el solicitante es el
propietario. Exactamente de la misma manera se puede proceder con los identificadores de grupo.
El resultado de la comparación indicará que permisos son aplicables. A continuación el sistema
aplicará dichos permisos a la operación solicitada y la autorizará o denegará según sea el caso.
Existen diversas implementaciones del esquema utilizado para determinar los permisos aplicables
aun usuario que pretende operar sobre un archivo concreto:
● El esquema más general consiste en asociar a cada archivo o directorio una lista de control
de acceso o ACL (Access-control list) que especifique los nombres de usuario o grupos y los
tipos de acceso para cada uno. Cuando un usuario solicita acceder a un archivo concreto, el
sistema operativo comprueba la ACL asociada a dicho archivo. Si dicho usuario, o alguno de
sus grupos, está incluido en la lista para el tipo de acceso solicitado, se permite el acceso. Esta
técnica presenta diversas ventajas e inconvenientes:
○ Sin embargo, construir la lista puede ser una tarea tediosa. Por ejemplo, si queremos
que varios usuarios puedan leer unos archivos determinados, es necesario enumerar
todos los usuarios que disponen de ese acceso en las ACL de dichos archivos.
○ El FCB, que hasta el momento tenía un tamaño fijo, ahora tendrá que ser de tamaño
variable para almacenar la ACL, lo que requiere mecanismo más complejos de gestión
del espacio.
● Para solucionar algunos de los problemas de las ACL muchos sistemas utilizan listas de
control de acceso condensadas. Para condensar la longitud de la lista de control de acceso,
muchos sistemas clasifican a los usuarios en tres grupos: propietario, grupo y todos. Así sólo
es necesario un campo para cada clase de usuario, siendo cada campo una colección de bits,
donde cada uno permite o deniega el tipo de acceso asociado al mismo. Por ejemplo, en los
5-160
5.5. Compartición de archivos Sistemas Operativos - 2014/2015
sistemas UNIX se definen 3 campos (propietario, grupo y todos) de 3 bits cada uno: rwx,
donde r controla el acceso de lectura, w controla el acceso de escritura y x controla la
ejecución. Las ACL condensadas son más sencillas de construir, al mismo tiempo que por
tener una longitud fija es mucho más simple gestionar el espacio para el FCB donde se
almacena.
● La técnica más común en los sistemas operativos modernos consiste en combinar ambos tipos
de listas de control de acceso. Sin embargo esta solución no está exenta de dificultades:
○ Uno de los problemas es que los usuarios deben poder determinar cuando están
activados los permisos ACL más generales. En Linux, por ejemplo, se utiliza el símbolo
“+” detrás de los permisos de la ACL condensada para indicar dicha circunstancia. Esos
permisos pueden ser gestionados utilizando los comandos setfacl y getfacl.
La familia de sistemas operativos Microsoft Windows utiliza las ACL más generales, mientras que
en los sistemas operativos Linux y Solaris se implementan ambos tipos de ACL.
Otra técnica para resolver el problema de la protección consiste en asociar una contraseña con
cada archivo o directorio. Sin embargo esto tiene el inconveniente de que el número de contraseñas
que un usuario puede tener que recordar puede ser muy grande. No olvidemos que si se utiliza la
misma contraseña para todos los archivo, desde el momento en que esa contraseña sea descubierta
todos los archivos serán accesibles.
5-161
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
Semántica de UNIX
Los sistemas de archivos de los sistemas operativos UNIX utilizan la siguiente semántica de
coherencia:
● Las escrituras en un archivo abierto por parte de un proceso son visibles inmediatamente
para los otros usuarios que hayan abierto ese mismo archivo.
En la semántica de UNIX cada archivo está asociado con una única imagen física a la que se accede
en forma de recurso exclusivo. La contienda por acceder a esta imagen única provoca retardos en
los procesos.
Semántica de sesión
Suponiendo que una sesión de archivo es el conjunto de operaciones entre las llamadas open() y
close(), el sistema de archivos Andrew –o AFS– utiliza la siguiente semántica de coherencia:
● Una vez que se cierra un archivo, los cambios realizados en él son visibles únicamente en
las sesiones que comiencen posteriormente. Las sesiones ya abiertas sobre el archivo no
reflejarán dichos cambios.
Esto significa que un archivo puede permanecer temporalmente asociado a varias imágenes físicas
al mismo tiempo. Así se permite que múltiples usuarios realicen accesos concurrentes, tanto de
lectura como de escritura, en sus propias imágenes del archivo, evitando los retardos.
5-162
5.5. Compartición de archivos Sistemas Operativos - 2014/2015
● Un bloqueo compartido es un tipo de bloqueo que puede ser adquirido concurrentemente por
varios procesos.
● Un bloqueo exclusivo sólo puede ser adquirido por un proceso cada vez.
Algunos sistemas operativos sólo proporcionan el bloqueo exclusivo. Sin embargo en los que
implementan ambos tipos de bloqueo, lo normal es que los procesos que pretenden acceder a un
archivo compartido para sólo lectura utilicen el bloqueo compartido, mientras que los que acceden
para modificar el contenido utilicen el bloqueo exclusivo. Así varios procesos puedan leer el archivo
concurrentemente, pero si un proceso accede para escribir ningún otro podrá acceder ni para leer ni
para escribir.
Como regla general los sistemas operativos Microsoft Windows implementan un mecanismo de
bloqueo obligatorio, mientras que los sistemas UNIX emplean bloqueos sugeridos.
5-163
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
5.5.4. Coherencia
Como hemos comentado anteriormente, parte de los metadatos se almacena en la memoria principal
para acelerar el acceso. Dicha información generalmente está más actualizada que la
correspondiente en el disco, puesto que la información almacenada en la memoria no tiene porque
ser escrita inmediatamente después de una actualización.
¿Qué ocurriría entonces si fallase el sistema? Pues que el contenido de la caché y de los búferes se
perdería y con ellos también los cambios realizados en los directorios y archivos abiertos. Esto
puede dejar el sistema de archivos en un estado incoherente, pues el estado real de algunos archivos
no sería el que se describe en la estructura de metadatos.
a) Comprobación de coherencia
El comprobador de coherencia comprueba la estructura de metadatos y tratar de corregir todas
las incoherencias que detecte.
Los algoritmos de asignación y de gestión del espacio de almacenamiento dictan los tipos de
problemas que el comprobador puede tratar de detectar y también el grado de éxito que el
comprobador puede tener en esa tarea. Por ejemplo la pérdida de un FCB, cuando es este el que
almacena la lista de bloques que contienen los datos del archivo, es desastrosa porque no hay forma
de saber en todo el disco que datos le pertenecen. Por esta razón UNIX almacena en caché las
entradas de directorio para las lecturas, pero todas las escrituras de datos que provoquen algún
cambio en la asignación de espacio o en algún otro tipo de metadato se realizan síncronamente,
antes de escribir los correspondientes bloques de datos.
b) Soft Updates
Para mejorar la eficiencia del sistema de archivos, sin comprometer la coherencia en caso de fallo,
los distintos sabores de los sistemas UNIX BSD utilizan una técnica denominada soft updates.
Cuando se monta un sistema de archivos con la opción soft updates el sistema operativo desactiva
la escritura síncrona de los metadatos, permitiendo que estos sean escritos cuando los algoritmos
de gestión de la caché lo consideren necesario, pero se impone cierto orden en el que dichas
operaciones de escritura deben ser realizadas. Por ejemplo, cuando se van a escribir en el disco las
modificaciones debidas a la creación de un nuevo archivo, el sistema se asegura de que primero se
escribe el nuevo inodo y posteriormente escribe el directorio con la nueva entrada de archivo.
Teniendo en cuenta que la entrada de directorio contiene un puntero al inodo, es sencillo darse
5-164
5.5. Compartición de archivos Sistemas Operativos - 2014/2015
cuenta de que haciéndolo en este orden nos estamos aseguramos de que el sistema de archivos
permanezca consistente, aunque el sistema falle antes de actualizar la información en el disco.
Fundamentalmente en los sistemas de archivos basados en registro –o con journaling– todos los
cambios en los metadatos se escriben secuencialmente en un registro62:
● Cada conjunto de operaciones necesario para realizar una tarea específica es una
transacción.
● Mientras tanto las operaciones indicadas en el registro son ejecutadas sobre las estructuras
reales del sistema de archivos. A medida que se realizan los cambios se actualiza el registro
para indicar las operaciones completadas.
● Cuando todas las operaciones de una transacción se han ejecutado con éxito, dicha
transacción se considera completada y se elimina del registro.
● Todas las transacciones que contenga el registro no habrán sido aplicadas, por lo que será
necesario terminar de aplicarlas antes de finalizar el proceso de montaje.
62 El registro generalmente se almacena en el mismo sistema de archivos. Sin embargo también suele ser posible
almacenarlo en otro volumen o incluso en otro disco.
5-165
Sistemas Operativos - 2014/2015 5. Gestión del almacenamiento
Esta técnica está empezando a resultar común en muchos sistemas operativos. Hasta el punto de que
utilizada en sistemas tales como: ext3, ext4, NTFS, XFS, JFS, ReiserFS, etc.
El sistema de archivos XFS modifica ligeramente esta técnica, sustituyendo las escrituras síncronas
necesarias para actualizar el registro por escrituras asíncronas. El resultado es cierta mejora del
rendimiento, porque el registro deja de ser el cuello de botella para las operaciones sobre los
metadatos. Sin embargo, en el caso de que el sistema fallase, el uso de escrituras asíncronas podría
provocar la corrupción del registro. Para evitarlo XFS impone cierto orden en las operaciones de
escritura sobre el registro, de forma similar a como se hace con los soft updates.
5-166
Bibliografía
La mayor parte de los contenidos de este documento están basados en las siguientes referencias
bibliográficas:
Silberschatz, A., Galvin, P. y Gagne, G. “Operating System Concepts with Java”. 6º ed. John
Wiley & Sons Inc., 2004.
Bavier, A. “Creating New CPU Schedulers with Virtual Time”. En 21st IEEE Real-Time Systems
Symposium (RTSS 2000) WIP Proceedings, 2000.
Ganger, G. R., McKusick, M. K., Soules, C. A. N. y Patt, Y. N. “Soft Updates: A Solution to the
Metadata Update Problem in File Systems”. En ACM Transactions on Computer Systems,
Vol. 18, No. 2, May 2000, Pag. 127–153.
Gorman, M. “Understanding the Linux Virtual Memory Manager”. Prentice Hall, 2004.
“Kernel Enhancements for Microsoft Windows Vista and Windows Server Longhorn”[en línea].
Microsoft Corporation, 2005 [2006]. URL http://goo.gl/ml8C4.
“Kernel Enhancements for Windows XP”[en línea]. Microsoft Corporation, 2003 [2006]. URL
http://goo.gl/ugED.
“XFS Filesystem Structure”[en línea]. Silicon Graphics Inc, 2006 [2007]. URL
http://goo.gl/RwZwL
A C
Access-control list 160 caching 31
ACL 160 cambio de contexto 53
activación del planificador 73 cancelación 79
afinidad al procesador 96 asíncrona ....................................................79
ajuste en diferido ..................................................79
mejor ........................................................138 cilindro 142
peor ...........................................................139 código
primer .......................................................138 absoluto ....................................................103
API 24 reubicable .................................................103
Application Programming Interface 24 cola
árbol de procesos 54 dispositivo ..................................................51
archivo 30, 143 entrada ......................................................101
mapeado en memoria ...............................121 eventos ........................................................51
asignación de memoria contigua 138 planificación ...............................................51
asignador 83 preparados ..................................................51
atómica 78 trabajo .........................................................51
comprobador de coherencia 164
B comunicación
balanceo de carga 97
directa .........................................................60
bit de
indirecta ......................................................61
modificado ................................................123
condición de carrera 74
modo ...........................................................35
conjunto de trabajo 129
protección .................................................110
consumidor 75
referencia ..................................................124
control de E/S 148
válido ................................................111, 114
copia durante la escritura 119
bloque de
copy-on-write 119
control de archivo .............................149, 151
cuanto 89
control de arranque ...................................149
control de proceso ......................................50 D
control de volumen ...................................149 demonio 65
inicio .........................................................149 descriptor de archivo 153
bloqueo desplazamiento 107
compartido ................................................163 dirección
exclusivo ..................................................163 absoluta ....................................................103
c)buffering 31, 61 física ...................................................37, 104
automático ..................................................62 reubicable .................................................103
capacidad cero ............................................61 virtual .................................................37, 104
capacidad ilimitada .....................................62 direccionamiento
capacidad limitada ......................................62 asimétrico ...................................................60
páginas ......................................................125 simétrico .....................................................60
buzones 61 directorio 155
Índice
actual ........................................................156 G
archivos de usuario ...................................155 gestión
dispositivo ................................................150 almacenamiento secundario .......................31
maestro de archivos ..................................155 archivos ......................................................30
raíz ............................................................156 E/S ..............................................................31
dispositivo memoria ..............................................29, 101
intercambio ...............................................116 procesos ................................................28, 47
GPT 146
E guid partition table 146
enlace 157
comunicaciones ..........................................59 H
duro ..........................................................157 herencia de la prioridad 94
simbólico ..................................................157 hilo 66
enlazado librería ........................................................68
dinámico ...................................................104 modelo ............................................................
estático ......................................................104 dos niveles .............................................73
envejecimiento 91 muchos a muchos ..................................72
muchos a uno .........................................70
espacio de direcciones uno a uno ...............................................71
disperso .....................................................112 núcleo .........................................................68
físico ...........................................................37 usuario ........................................................68
virtual .................................................36, 103 hiperpaginación 127
espera ocupada 78
estructura I
capas ...........................................................40 identificador de proceso 53
microkernel ................................................42 inodo 150
modular ......................................................44 instrucciones privilegiadas 35
sencilla ........................................................39 intercambio 53, 114
excepción 27, 34 espacio ......................................................116
interfaz programación de aplicaciones 23
F inversión de la prioridad 94
Fair Scheduling 92
FCB 149, 150 s. J
FCFS 87, 89 journaling 165
fichero 30 K
file kernel 3
control block .....................................149, 151
descriptor ..................................................153 L
handler ......................................................153 latencia de asignación 83
fragmentación least frequently used 125
externa ......................................................139 least recently used 124
interna ...............................................109, 139 LFU 125
franjas 146 librería
170
compartida ................................................106 most frequently used 125
del sistema ..................................................25 muerte por inanición 90
estándar ......................................................24 multimedia class scheduler service 99
lista de control de acceso 160 multiprocesamiento
llamadas al sistema 26 asimétrico ...................................................96
LRU 124 simétrico .....................................................96
mutex 77
M
maillox 61 N
mainframe 4 nombre de ruta 156
manejador de archivo 153 absoluto ....................................................156
marcos 107 relativo ......................................................156
master boot record 146 not recently used 124
master file table 150 NRU 124
MBR 146 núcleo 3
memoria expropiable .................................................94
compartida ..................................................58 número
flash ..........................................................143 mágico ......................................................154
virtual ........................................................113 marco ........................................................107
memory-management unit 37 página .......................................................107
MFD 155
MFT 150 P
P2P 9
MFU 125
page-table
microkernel 42
base register ..............................................110
migración
length register ...........................................112
comandada ..................................................97
página 107
solicitada ....................................................97
compartida ................................................113
minidiscos 146
paginación 107
MMCSS 99
bajo demanda ............................................113
MMU 37
pura ......................................................115
modelo paginador 114
conjunto de trabajo ...................................129 particionado dinámico 138
localidad ...................................................129 particiones 146
modo paso de mensajes 59
dual .............................................................35 asíncrono ....................................................62
kernel ..........................................................35 con bloqueo ................................................62
privilegiado ................................................35 sin bloqueo .................................................62
sistema ........................................................35 síncrono ......................................................62
supervisor ...................................................35 PCB 50
usuario ........................................................35 peer-to-peer 9
módulo de organización de archivos 148 PIC 105
monolítico 39
Índice
172
empotrados .................................................10 contenidos del volumen ............................150
escritorio .......................................................8 maestra de archivos ..................................150
informático ...................................................1 marcos ......................................................108
lógico de archivos ....................................149 páginas ......................................................107
mano ...........................................................11 tasa
multiprocesador ..........................................95 fallos de página .........................................118
multiprogramado ..................................6, 101 procesamiento ............................................83
operativo ...................................................1, 3 temporizador 38
procesamiento por lotes ................................5 terminación en cascada 57
redes entre iguales ........................................9 thread-safe 80
tiempo compartido ...............................7, 101 thread-specific data 78
tiempo real ..................................................10 tiempo
sistema operativo acceso a la memoria .................................117
de red ..........................................................10 acceso efectivo .........................................117
distribuido ..................................................10 ejecución ....................................................84
SJF 87 espera ..........................................................84
SMP 96 fallo de página ..........................................117
socket 65 respuesta .....................................................84
dominio UNIX ...........................................66 tiempo real
soft updates 164 estricto ..................................................11, 92
spinlock 78 flexible ..................................................11, 93
spooling 31 volumen ....................................................144
SRTF 87 transacción 165
stripe 145 TSD 78
stub 105 tubería 63
superbloque 150
swap 116 U
UFD 155
swapping 53, 114
utilidades del sistema 34
T
tabla V
volumen 144
archivos abiertos .......................................150
gestión ..............................................146, 147