CARRERA:
INGENIERIA EN SISTEMAS COMPUTACIONALES.
PROFESOR:
LIC. ULISES BARRADAS.
ALUMNOS:
TAYDE A. JIMÉNEZ VELÁZQUEZ.
MARIO SILVA RODRIGUREZ.
FECHA DE ENTREGA:
22 DE MAYO DEL 2010.
VIDEO RELACIONADO
descarga archivo en word
INDICE
1.0 Introducción………………………………………………………….………….3
2.0 Historia de los sistemas operativos……………………………………………..3
2.1 Generación Cero (década de 1940)……………………………………………..3
2.2 Primera Generación (década de 1950)………………………………………….3
2.3 Segunda Generación (a mitad de la década de 1960)…………………………..4
2.4 Tercera Generación (mitad de década 1960 a mitad década de 1970)………………………………………………………………………….……..5
2.5 Cuarta Generación (mitad de década de 1970 en adelante)..12
2.6 sistemas operativos mas usados en la actualidad……………………………….5
2.6.1 Windows, el inicio de una interfaz gráfica ……………………….…………6
2.6.2 Panorámica histórica sobre el Sistema Operativo mac os….….…………….11
1.0 Introduccion
los sistemas operativos han venido evolucionando a través de los años. ya que los sistemas operativos se han apegado íntimamente a la arquitectura de las computadoras en las cuales se ejecutan.
2.0 Historia de los sistemas operativos
Los Sistemas Operativos, al igual que el Hardware de los computadores, han sufrido una serie de cambios revolucionarios llamados generaciones. En el caso del Hardware, las generaciones han sido marcadas por grandes avances en los componentes utilizados, pasando de válvulas ( primera generación ) a transistores ( segunda generación ), a circuitos integrados ( tercera generación), a circuitos integrados de gran y muy gran escala (cuarta generación). Cada generación Sucesiva de hardware ha ido acompañada de reducciones substanciales en los costos, tamaño, emisión de calor y consumo de energía, y por incrementos notables en velocidad y capacidad.
2.1 Generacion Cero (década de 1940)
Los primeros sistemas computacionales no poseían sistemas operativos. Los usuarios tenían completo acceso al lenguaje de la maquina. Todas las instrucciones eran codificadas a mano.
2.2 Primera Generacion (década de 1950)
Los sistemas operativos de los años cincuenta fueron diseñados para hacer mas fluida la transición entre trabajos. Antes de que los sistemas fueran diseñados, se perdía un tiempo considerable entre la terminación de un trabajo y el inicio del siguiente. Este fue el comienzo de los sistemas de procesamiento por lotes, donde los trabajos se reunían por grupos o lotes. Cuando el trabajo estaba en ejecución, este tenia control total de la maquina. Al terminar cada trabajo, el control era devuelto al sistema operativo, el cual limpiaba y leía e iniciaba el trabajo siguiente.
Al inicio de los 50′s esto había mejorado un poco con la introducción de tarjetas perforadas (las cuales servían para introducir los programas de lenguajes de máquina), puesto que ya no había necesidad de utilizar los tableros enchufables.
Además el laboratorio de investigación General Motors implementó el primer sistema operativo para la IBM 701. Los sistemas de los 50′s generalmente ejecutaban una sola tarea, y la transición entre tareas se suavizaba para lograr la máxima utilización del sistema. Esto se conoce como sistemas de procesamiento por lotes de un sólo flujo, ya que los programas y los datos eran sometidos en grupos o lotes.
La introducción del transistor a mediados de los 50′s cambió la imagen radicalmente.
Se crearon máquinas suficientemente confiables las cuales se instalaban en lugares especialmente acondicionados, aunque sólo las grandes universidades y las grandes corporaciones o bien las oficinas del gobierno se podían dar el lujo de tenerlas.
Para poder correr un trabajo (programa), tenían que escribirlo en papel (en Fortran o en lenguaje ensamblador) y después se perforaría en tarjetas. Enseguida se llevaría la pila de tarjetas al cuarto de introducción al sistema y la entregaría a uno de los operadores. Cuando la computadora terminara el trabajo, un operador se dirigiría a la impresora y desprendería la salida y la llevaría al cuarto de salida, para que la recogiera el programador.
2.3 Segunda Generacion (a mitad de la década de 1960)
La característica de los sistemas operativos fue el desarrollo de los sistemas compartidos con multiprogramación, y los principios del multiprocesamiento. En los sistemas de multiprogramación, varios programas de usuario se encuentran al mismo tiempo en el almacenamiento principal, y el procesador se cambia rápidamente de un trabajo a otro. En los sistemas de multiprocesamiento se utilizan varios procesadores en un solo sistema computacional, con la finalidad de incrementar el poder de procesamiento de la maquina.
La independencia de dispositivos aparece después. Un usuario que desea escribir datos en una cinta en sistemas de la primera generación tenia que hacer referencia especifica a una unidad de cinta particular. En la segunda generación, el programa del usuario especificaba tan solo que un archivo iba a ser escrito en una unidad de cinta con cierto numero de pistas y cierta densidad.
Se desarrollo sistemas compartidos, en la que los usuarios podían acoplarse directamente con el computador a través de terminales. Surgieron sistemas de tiempo real, en que los computadores fueron utilizados en el control de procesos industriales. Los sistemas de tiempo real se caracterizan por proveer una respuesta inmediata.
2.4 Tercera Generacion (mitad de década 1960 a mitad década de 1970)
Se inicia en 1964, con la introducción de la familia de computadores Sistema/360 de IBM. Los computadores de esta generación fueron diseñados como sistemas para usos generales . Casi siempre eran sistemas grandes, voluminosos, con el propósito de serlo todo para toda la gente. Eran sistemas de modos múltiples, algunos de ellos soportaban simultáneamente procesos por lotes, tiempo compartido, procesamiento de tiempo real y multiprocesamiento. Eran grandes y costosos, nunca antes se había construido algo similar, y muchos de los esfuerzos de desarrollo terminaron muy por arriba del presupuesto y mucho después de lo que el planificador marcaba como fecha de terminación.
Estos sistemas introdujeron mayor complejidad a los ambientes computacionales; una complejidad a la cual, en un principio, no estaban acostumbrados los usuarios.
2.5 Cuarta Generacion (mitad de década de 1970 en adelante)
Los sistemas de la cuarta generación constituyen el estado actual de la tecnología. Muchos diseñadores y usuarios se sienten aun incómodos, después de sus experiencias con los sistemas operativos de la tercera generación.
Con la ampliación del uso de redes de computadores y del procesamiento en línea los usuarios obtienen acceso a computadores alejados geográficamente a través de varios tipos de terminales.
Los sistemas de seguridad se ha incrementado mucho ahora que la información pasa a través de varios tipos vulnerables de líneas de comunicación. La clave de cifrado esta recibiendo mucha atención; han sido necesario codificar los datos personales o de gran intimidad para que; aun si los datos son expuestos, no sean de utilidad a nadie mas que a los receptores adecuados.
El porcentaje de la población que tiene acceso a un computador en la década de los ochenta es mucho mayor que nunca y aumenta rápidamente.
El concepto de maquinas virtuales es utilizado. El usuario ya no se encuentra interesado en los detalles físicos de; sistema de computación que esta siendo accedida. En su lugar, el usuario ve un panorama llamado maquina virtual creado por el sistema operativo.
Los sistemas de bases de datos han adquirido gran importancia. Nuestro mundo es una sociedad orientada hacia la información, y el trabajo de las bases de datos es hacer que esta información sea conveniente accesible de una manera controlada para aquellos que tienen derechos de acceso.
2.6 sistemas operativos mas usados en la actualidad.
Hoy en día trabajamos con dos de los mas importantes sistemas operativos muy poderosos y sofisticados de los cuales a continuación veremos la historia de cada uno (Windows / Mac os)
2.6.1 Windows, el inicio de una interfaz gráfica
Las dos primeras versiones de este "Entorno Operativo" (nótese que no era un sistema operativo en sus principios) no tuvieron mucho éxito entre el público consumidor. Lo único que logró fue que Apple le iniciara un juicio a Microsoft por su semejanza con su sistema operativo MacOs.
El boom de Windows se produjo con su versión 3.0 (y más aún con la 3.1) cuando comenzó a aprovechar las capacidades de los procesadores "386" y le dio un mejor manejo a la memoria hacia el año 1991
Fue simplemente un "shell" para DOS, ya que sin este no funcionaba. Y por esa razón no es un sistema operativo, sino un "entorno operativo". El atractivo que tuvo para con la gente fue su "casi real" facilidad de uso y su "cara" gráfica que hacía olvidar "las pantallas negras" de DOS.
Un tiempo más tarde se le agregaron capacidades para trabajar con redes y pasó a la versión 3.11 (para grupos de trabajo). Esta fue la última versión comercial que salió al mercado antes de que Windows 95 hiciera su aparición.
> Windows 95: El entorno operativo
Desde el principio, Windows 95 se publicitó como un sistema operativo de 32 bits. Pero cuando salió a la luz se pudo ver que esto no era totalmente verdad: era un sistema operativo (ya no un entorno), porque no necesitaba de ningún otro programa para poder funcionar (aunque se incluía el DOS 7.0 "completo" y alguien dijo que "sí" lo necesitaba). Por otro lado, la promesa de los 32 bits (programas más rápidos y mejor aprovechamiento de la memoria) no se cumplió. Muchas de las "partes" de este sistema operativo fueron de 16 bits como sus antecesores. Esto se explicó diciendo que era así por la cantidad de programas "heredados" de las versiones anteriores (Windows 3.1).
Casi en el mismo momento (un año antes) apareció en el mercado un verdadero sistema operativo de 32 bits que sería la competencia directa al tan publicitado Windows 95: OS/2 de IBM. En principio fue desarrollado en cooperación entre IBM y Microsoft (como años atrás con el DOS), y como años atrás surgieron diferencias que hicieron que cada empresa presentara su producto.
OS/2 fue un sistema operativo totalmente de 32 bits que muchos expertos consideran mejor, más estable y con mayores prestaciones que Windows 95, pero que (nuevamente) las campañas publicitarias relegaron a un segundo lugar, ya que la gran mayoría de los desarrolladores decidieron hacer sus programas "compatibles" con Windows 95 y no con OS/2.
> Windows 98/NT: Ya nada sería igual
Windows 98 no representó para los usuarios comunes ningún cambio significativo. Sólo un poco de retoque gráfico y alguna que otra utilidad nueva o mejorada (como el "liberador de espacio" o el viejo "defrag"). Pero si trajo algunas cosas nuevas: el soporte completo para los 32 bits, y la “eliminación” del DOS como sistema independiente (ya que no incluyó una nueva versión, sino un emulador del mismo).
En esta época no podemos dejar de mencionar Windows NT (Windows Nueva Tecnología). Windows NT fue un sistema operativo de 32 bits especializado en redes que utilizó otro sistema para el manejo de los archivos (NTFS), y por lo tanto "incompatible" con Windows 95/98.
Versiones de Windows NT: 3.1, 3.5, 3.51, 4; está ultima versión tuvo estas variantes: Workstation, Server, Server Enterprise Edition, Terminal Server, Embedded.
> Windows 2000/Windows ME, continua la saga
Windows 2000 fue el sucesor de NT, por lo que estuvo orientado a empresas y heredó muchas de las características de este; hasta llegar a su última versión 2003 Server.
Su gran estabilidad, su soporte para varios procesadores, su alto nivel de seguridad, además de sus impresionantes capacidades para desenvolverse como server lo hicieron la mejor opción para una empresa. Era rápido y lo suficientemente fácil de configurar casi para cualquier persona, pero hay que tener en cuenta que tiene poco soporte para el agregado de periféricos como tarjetas de video o de sonido. Es decir, este no fue un sistema operativo totalmente apto para la multimedia.
Al ser de esta manera, es no fue aconsejable su uso en hogares, donde comunmente encontraremos juegos, música en la PC, enciclopedias multimedia y demás.
Ahí es donde entró Windows Millennium Edition (ME), sucesor de Windows 98: Fue un sistema operativo donde primó la facilidad de uso, las mejoras en multimedia, comunicaciones e Internet.
Aunque no contó con la estabilidad de Windows 2000 fue más seguro que Windows 98 y 98 SE (segunda edición) ya que se incorporaron una serie de utilidades para proteger el sistema operativo y hacerlo más resistente a las instalaciones de programas y drivers de terceros que, en definitiva, fueronlas principales causas de cuelgues y pantallas azules en sus predecesores.
Una de las cosas interesantes con que nos encontramos en Windows ME es que el modo DOS, tal como lo conocimos, había dejado de existir. Ya no eraposible iniciar el sistema en "sólo símbolo del sistema" o apagar el sistema "reiniciando en modo MS-DOS". Tanto es así, que los archivos AUTOEXEC.BAT y CONFIG.SYS ya no tuvieron ninguna función en ME (salvo durante la instalación). Lo que realmente se eliminó de Windows ME fue el soporte para aplicaciones DOS de 16 bits en modo real.
En su momento, la elección de uno u otro sistema dependió del uso que deseaba hacer de la PC, siendo lo más lógico Windows 2000 para empresas y Windows ME para hogares.
El tiempo también dijo que Windows Millennium Edition fue el mas inestable de los sistemas operativos post Windows 95.
La línea Windows 2000 Server fué reemplazada por Windows Server 2003, y Windows 2000 Professional con Windows XP Professional.
Versiones de Windows 2000: Professional, Server, Advanced Server y Datacenter Server.
> Windows XP/Windows 2003 Server, la nueva generación del escritorio
Windows XP fue la mejora mas importante técnicamente desde Windows 9x, y unificó en cierto modo las versiones separadas que hubo estos años: WINDOWS 9x/ME para usuarios hogareños y SOHO contra Windows NT/2000 para usuarios corporativos con requerimientos de trabajo en redes de alto nivel.
Windows XP se distribuyó en 2 versiones principales: Windows XP Home Edition y Windows XP Profesional. La versión Home no tenía tanto soporte para redes, lo que si incluyó la versión Profesional.
Esto S.O., además de constituirse en la unión de los entornos mencionados, es en realidad la continuación de Windows NT/2000. Se destacó en este producto su alto grado de integración con las redes e Internet, además de proveer una nueva interfase gráfica que se hizo notar ni bien se comienza a utilizar. Los cambios de interfaz fueron básicamente estéticos. La diferencia real con sus predecesores estuvo dada por el soporte LAN, soft de grabación de CDs, multimedia, escritorio remoto y manejo de usuarios.
Algo muy importante es el hecho de que Microsoft con esta versión de su S.O. ha puso especial énfasis en los drivers. WXP fué muchísimo mas renuente que sus predecesores a instalar drivers no certificados para el mismo. Con esto Microsoft pretendió reducir al máximo las ya tan conocidas (y sufridas) "pantallas azules", aduciendo que la mayoría de las causas de inestabilidad de las versiones anteriores estaba dada por el uso de drivers no certificados, obsoletos o mal desarrollados. Debido a esto, se destaca la búsqueda inteligente de controladores que hace el S.O. al momento de instalar un dispositivo nuevo, escaneando unidades en busca de los drivers correctos.
Windows XP contó con las actualizaciones más profundas a nivel seguridad que ningún otro sistema operativo Microsoft: prueba de ello fueron los Service Pack 1 y 2. También fue el primero en adoptar un sistema de verificación de autenticidad del S.O.: WGA (Windows Genuine Advantage)
Windows 2003 Server estuvo basado en el núcleo de Windows XP, al que se le añadieron una serie de servicios, y se le han bloqueado algunas características. A grandes rasgos, Windows Server 2003 es un Windows XP simplificado, no con menos funciones, sino que estas están deshabilitadas por defecto para obtener un mejor rendimiento y para centrar el uso de procesador en las características de servidor.
Versiones de Windows XP:
Windows XP 64 Bits: Uso en procesadores de 64 bits.
Windows XP Media Center Edition
Windows XP Tablet PC Edition: Tablet PC
Windows XP Embedded: ATM, terminales.
Windows Fundamentals for Legacy PCs: Versión simplificada de XP para uso en hardware obsoleto.
Windows XP Starter Edition: distribuida solo en determinados países, (una versión tan básica y limitada que por momentos se torna bastante impráctica al momento de utilizarla).
Versiones de Windows 2003 Server: Web Edition, Standard Edition, Enterprise Edition, Datacenter Edition
> Windows Vista, la era post XP de Microsoft
Windows Vista requiere de hardware realmente potente para ejecutarse en toda su dimensión o con una performance aceptable; incluso para las versiones mas "básicas" de este S.O.
Las versiones disponibles son varias: Enterprise, Business, Ultimate (para usuarios corporativos), Starter (solo comercializada en países emergentes, una versión reducida que si es similar a su homónima de Windows XP); y por último las versiones Home Basic y Home Premium (para usuarios domésticos).
> Linux: el futuro alternativo?
Cuando Linus Torvalds comenzó a trabajar sobre Minix para obtener su propio sistema operativo no tenía ni la más remota idea de lo que su trabajo llegaría a ser en todo el mundo. Este sistema operativo es totalmente distinto a los vistos anteriormente por un montón de razones. He aquí algunas de ellas:
* No fue desarrollado por una gran empresa:
Linus Torvalds desarrolló el kernel (el corazón) del sistema y luego liberó el código fuente del mismo en Internet para que cualquier programador que se animara pudiera modificarlo y agregarle lo que quisiera. Así, el Linux que hoy se conoce fue creado por cientos de programadores "libres" alrededor del mundo y no por una empresa.
* Es gratis y abierto:
Todo el sistema operativo es totalmente gratuito (al igual que muchísimos de sus programas), si posee una conexión a Internet es posible bajarlo a su máquina. Lo que algunas empresas hacen es "empacar" el sistema y algunos programas y grabarlos en CD’s, que junto con algún manual es lo que luego "venden". Esto se conoce como Distribuciones.
Además, junto con el sistema vienen los códigos fuentes del mismo (y de algunos programas) para que pueda ser modificado a gusto del usuario (si este es un programador experimentado), es por esto que se dice que es "abierto".
* Nació a partir de otro sistema operativo:
Es una modificación del sistema Minix, que a su vez nació como una "reducción" de UNIX, "el único sistema operativo verdadero, a partir del cual se crearon los demás" (incluido DOS) según la opinión de muchos Hackers.
Este sistema operativo es el elegido por las empresas que proveen acceso a Internet, debido a su gran estabilidad y eficiencia. Además, posee un muy buen manejo de redes y seguridad, lo que está haciendo que muchas empresas e instituciones (escolares sobre todo) lo tengan en cuenta para reemplazar sus sistemas actuales.
En un principio, Linux también era una "pantalla negra" en modo texto y muy poco intuitivo (al igual que DOS, al igual que UNIX). Pero desde hace un tiempo se desarrollaron entornos gráficos (varios: KDE, Gnome, etc.) que no tienen nada que envidiarle a Windows 95/98 y que hacen que más usuarios (menos experimentados) se "animen" a usarlo.
Por lo anterior y el gran auge de Internet este es el sistema operativo que más crecimiento ha tenido en los últimos años, y el que se perfila quizá como una alternativa válida para el futuro.
Algunas distribuciones de Linux conocidas: Red Hat, Debian, Fedora, Gentoo, Mandriva, Rxart, Slackware, Suse, Ubuntu, Kubuntu
Conclusión;
Sin el sistema operativo nada funcionaria... por lo tanto no cabe mucho mas que acotar. Solo es de esperarse que la evolución se mantenga y quizás avizorar mas alternativas a nuestro nunca tan bien ponderado y muchas veces vilipendiado “Windows”.
2.6.2 Panorámica histórica sobre el Sistema Operativo Mac
El Sistema Operativo Mac OS no fue la primer interfaz gráfica, pero fue la primera con gran éxito por su accesibilidad de precio. Para aquellos años en el mercado lo que existía era La Xerox Alto con un costo de 32,000 dólares, la Xerox Star costó 16,600 dólares y la Apple Lisa con un precio de 10,000 dólares. El nombre de esta Apple fue un capricho de Steve Jobs por su hija. Este Sistema 1 venía incluido en el primer Macintosh, que tenía un precio de 2,500 dólares.
1984: Sistema 1
El Sistema 1 tenía escritorio, ventanas, iconos, mouse, menús y scrollbars.
El basurero “Trash” funcionaba como un tobogán de basura, todo desaparecía luego de reiniciar el ordenador, no se podía trabajar en dos aplicaciones al mismo tiempo, solo en una, ya que la memoria virtual no existía.
En el Sistema 1 era imposible crear un folder dentro de otro folder, de hecho todos los archivos eran guardados en la misma dirección del disco, se creaba una nota en la tabla de archivos para que cada archivo estuviera en su respectivo folder y así el Finder podría parecer como que el archivo estaba en su folder.
Luego el Sistema 1.1 agregó la caja de avisos de diálogo, también el comando para limpiar tu Mac y algunos implementos para la velocidad.
1985: Sistema 2
El Sistema 2 fue notable en mejoras. Incrementó la velocidad del Finder haciéndolo un veinte por ciento más rápido, los comandos de regresar y cerrar se eliminaros. Fueron agregadas más opciones como: crear nuevos folders, apagar, la impresora de escritorio y los ítems eran listados de forma vertical con un pequeño icono. Los discos o unidades podían ser arrastrados al icono de basura y podían ser extraídos.
1986: Sistema 3
En el Sistema 3 el Finder fue mejorado y más rápido, el orden de los archivos HFS (Hierarchical File System) fue reemplazado por el nuevo sistema de Macintosh MFS (Macintosh File System) de los Sistemas 1 y 2.
Los folders eran reales y se podían crear folders dentro de folders. Los iconos con Zoom fueron agregados en la parte inferior derecha en la ventana dentro del Dashboard, haciendo clic sobre estos se podía cambiar el tamaño para ajustar los contenidos del folder si era posible.
Haciendo clic nuevamente se podía hacer que la ventana regresara a su tamaño normal. El icono del basurero sobresalía cuando algo era puesto sobre este y las líneas punteadas en dirección contraria.
• El Sistema 3.2, se corrigieron treinta errores, la calculadora fue actualizada así que el teclado numérico en pantalla se parecía al teclado numérico en el teclado.
• El Sistema 3.3, fue agregado por AppleShare el antiguo compartidor de archivos de Macintosh.
1987: Sistema 4
El Sistema 4 fue introducido como Macintosh SE y Macintosh II. A este sistema se le agregó múltiple soporte al monitor.
• El Sistema 4.1, soportaba discos de 32+ MB, se le implemento el Finder múltiple, los usuarios podían cambiar entre el Finder, que solo soportaba un programa y el Finder múltiple que soportaba múltiples programas al mismo tiempo.
Ahora el Finder mostraba cuanta memoria utilizaba cada programa, también se le agregó un Panel de control configurable.
• El Sistema 4.3, fue un sistema actualizado, se le arreglaron algunos errores y controladores de impresora.
1988: Sistema 6
En el Sistema 6 se agregaron colores, aun así el Finder no tenía color, aunque las máquinas ya eran capaces. A la opción de “Borrar Disco” se le agrego un botón para poder cancelar esta acción, también fue agregada la opción de mostrar el número de versión del archivo.
Fue así también agregada una notificación en el monitor permitiendo a los programas notificar a lo usuario por medio de la barra de menú si ellos necesitaban conectarlo.
• El Sistema 6.0.1-6.0.8, simplemente se agregados algunos soportes para los nuevos modelos que ellos iban lanzando.
1990: Sistema 7
El Sistema 7 fue el gran cambio de software para esta época, se eliminó el Finder y el Finder múltiple. El Sistema 7 ya sólo tenía el Finder múltiple permitiendo hacer muchas tareas simultáneamente.
La memoria también tuvo un gran cambio a 32b, esto permitió a las Macs usar mas de 8 MB de Ram, en el sistema operativo, esto fue también implementado en el Sistema 7.
El Networking por Apple Talk y compartir archivos por AppleShare fue agregado al sistema operativo, como opción adicional. El software QuickTime multimedia también fue trabajado en este sistema, pero estaba disponible como un software extra. El Sistema 7 agregó muchas características que iban a ser construidas en el nuevo sistema Mac OS X.
Un menú fue agregado en la parte inferior derecha del Dashboard, que mostraba la lista de los programas que estaban siendo utilizados en ese momento y permitía a los usuarios cambiarse entre ellos. Luego de la aplicación de menú fue agregado el menú de “Ayuda”, el “basurero” fue cambiado a un verdadero folder permitiendo eliminar los archivos hasta que se seleccionaba la opción de “Vaciar” el basurero.
Fue implementada la opción de arrastrar que permitía llevar un texto de un programa a otro sin necesidad de copiar y pegar. En el Sistema 7 el buscador finalmente tomo una ventaja en los objetos con color, haciendo que los elementos en la interfaz se vieran como en 3D.
• El Sistema 7.0.1p Performa, fue lanzado junto con el Sistema 7.0.1’s, arreglando algunas características especiales para usuarios principiantes de este Sistema.
• El Sistema 7.1, se le implemento un folder de Fuentes así que podían ser fácilmente agregados o removidos, luego estos fueron agregados y utilizados por el mismo Sistema.
• El Sistema 7.1.1, también conocido como Sistema 7 Pro, Incorporando AppleScript, QuickTime, y PowerTalk, estos estaban disponibles como extras del sistema.
• El Sistema 7.1.2, fue creado para soportar Chips de microprocesadores.
• El Sistema 7.5, integraba todas las características del Performa, también agregaba mucha más información de la Guía de ayuda del sistema de Apple (Apple Guide help system). Finalmente en la pantalla de arranque existió una pequeña barra.
A pesar de que Mac había trabajado durante once años llegando hasta el Sistema 7.5, esto mostraba claramente de que Mac necesitaba completamente una nueva creación del Sistema Operativo.
Mac OS 7.6, fue el primer sistema operativo lanzado con una estrategia de Apple para luego ser actualizado como el actual Mac OS cada 6 meses, hasta que Rhapsody/Mac OS X fuera finalizado. Fueron corregidos algunos errores vía Mac Os 7.6.1
1997: Mac OS 8
Mac OS 8 incluyó otra renovación al Finder que podía hacer más cosas al mismo tiempo, dando la opción de controlar múltiples aplicaciones al mismo tiempo con un mejor desempeño de las computadoras con procesador.
La apariencia del Finder fue renovada para que tuviera un mejor aspecto 3D, también podía ser personalizada. El Web Sharing permitía a los usuario hospedar páginas en sus computadoras.
• Mac OS 8.1, fue mas notable para el HFS+ (Esta improvisada versión del Sistema de archivos jerárquica que fue introducido en el Sistema 3) liberaba gran cantidad de espacio (Cientos de Megabytes) en el disco duro despejaba mas de 1 GB. Mac OS 8.1. También fue la ultima versión que soportaba Macs de 68K, todas las versiones anteriores eran solo para PowerPC.
• Mac OS 8.5, introdujo Sherlock un avanzado programa de búsqueda que trabaja en el disco local, servicios de redes y la Internet.
• Mac OS 8.6, agregó una opción de contenido a Sherlock aumentando su forma de administración y un agregado soporte de USB y FireWire.
1999: Mac OS 9
La opción de tener varios usuarios en una Mac fue agregada en esta versión, permitía a los usuarios ingresar y tener sus propias configuraciones. AppleTalk sobre TCP/IP fue también implementado.
Software Update permitía a los usuarios tener las actualizaciones de softwares fuera de Internet, y podía informar a los usuarios de las nuevas actualizaciones cuando ellos salían.
• Mac OS 9.0.2 y 9.0.3, llegaron con sus modelos específicos, Mac OS 9.0.4 unificó todo nuevamente y es la única versión del Classic Mac OS compatible con el Entorno Classic del Mac OS X Public Beta.
• Mac OS 9.1, agregó estabilidad y la ventana de menú. Esto es lo mínimo del Classic enMac OS X 10.0 y 10.1.
• Mac OS 9.2, estaba disponible como pre-instalación del sistema iniciando con “Quicksilver” Power Mac G4s lanzado en el verano del 2001.
Mac OS X
Esta basado fuertemente en las PowerPC-port de OpenStep. Por eso Mac OS X hereda la memoria y procesador de Mach’s y el driver del dispositivo de la interfaz, BSD’s POSIX – UNIX Protocolo del programa que soporta y trabaja en interfaz de redes, también algunos elementos de la interfaz de NeXT’s.
Mac OS X, hoy en día este sistema operativo esta virtualmente en todas las Mac’s, y fue trabajado por una década para poder obtener el éxito que tiene ahora.
2001: Mac OS X 10.0 “Cheetah”
Mac OS X 10.0 fue lanzada el 24 de marzo del 2001, este incorporaba muchas características que fueron agregadas por las personas que colaboraron en Mac OS X Public Beta.
Mac OS X 10.0 también contenía todas características de un sistema operativo moderno, protegía la memoria, y así los programas no podían utilizar la información de otros programas, de esta forma el procesador no se bloqueaba, los drivers de los dispositivos podían ser cargados o descargados si eran necesario.
Mac OS X también agrego Cocoa, derivado de NeXT’s un muy sofisticado y desarrollado ambiente OpenSTEP. Existían algunos asuntos pendientes, como el original Mac OS. Los usuarios de Mac OS X iniciaron a crear una gran queja sobre nombre que tenia este sistema operativo “Cheetah” que era muy salvaje e inapropiado.
El ambiente Classic en 10.0, también era mejor que el Public Beta, aun tenia una extraña compatibilidad de problemas y conducta caprichosa. Los interfaz de Mac OS X se veía muy parecida a la interfaz de Mac OS y los usuarios creían que tenían las mismas características sin embargo no fue así y tuvieron que aprender nuevos hábitos y dejar los viejos.
2001: Mac OS X 10.1 “Puma”
Mac OS 10.1 fue lanzado luego de un año del 10.0, e incorporaba mejor desempeño especialmente en Macs G3. Las versiones 10.1.1, 10.1.2, 10.1.3, 10.1.4, y 10.1.5 todas tenían mejora en los errores, y actualizaciones en sus componentes. La mayoría de open source como utilidades de UNIX fueron incluidas en las Mac OS X y drivers adicionales para poder soportar mas dispositivos.
2002: Mac OS X 10.2 “Jaguar”
El 25 de agosto de 2002 fue lanzada esta versión y Apple prosiguió con la andadura de su sistema operativo con el lanzamiento de Mac OS X v10.2 “Jaguar”) y que contaba con un nuevo incremento en su rendimiento, un nuevo y depurado look y más de 150 mejoras, entre estas estaba el mayor soporte para redes de Microsoft Windows, Quartz Extreme para la composición de gráficos sea procesada directamente por la tarjeta de video y un filtro contra spam.
Apple Address Book para almacenar la información de contactos, tambien agregaba el sistema de red Rendezvous. iChat que consistía en un programa de chateo con soporte de AOL Instant Messenger, incluía así un renovado Finder con búsquedas integradas en cada ventana.
2003: Mac OS X 10.3 “Panther”
Mac OS X v10.3 “Panther” se lanzó el 24 de octubre de 2003. Además de tener un rendimiento mucho mayor, incorporó la mayor actualización en la interfaz de usuario, y muchas mejoras que Jaguar el año anterior. Esta versión ya no era compatible en los antiguos modelos G3.
Algunas de las mejoras de esta versión es que el Finder fue actualizado e incorpora una interfaz metálica y búsqueda rápida. Exposé permitía una nueva forma de manipular ventanas, también incorporo el Cambio Rápido de Usuarios, que permite tener sesiones con diferentes usuarios abiertas al mismo tiempo y pasar de una a otra rápidamente.
Ahora esta nueva versión incluía soporte integrado de fax. FileVault era un Sistema de cifrado en tiempo real del directorio privado de cada usuario. Incrementaba velocidad en todo el sistema con un mayor soporte para los G5.
2005: Mac OS X 10.4 “Tiger”
Mac OS X v10.4 “Tiger” fue lanzado el 29 de abril de 2005 y fue la versión disponible más reciente, contenía más de 200 nuevas mejoras, pero como sucedió con el lanzamiento de Panther, algunas máquinas antiguas no podían soportarlo, en particular, cualquier equipo Apple que no contara con conexión FireWire no podía ser soportado en Tiger.
Esta versión incluya nuevas características como Spotlight un sistema de búsqueda basado en contenidos y metadatos, así también Dashboard se encontraban widgets, unas miniaplicaciones que permiten realizar tareas comunes y ofrecen acceso instantáneo a la información.
QuickTime 7 era la nueva versión que incluía soporte para H.264 y un interfaz completamente rediseñada. Safari como una nueva versión del navegador por defecto del sistema incorpora soporte para RSS, mayor velocidad y seguridad, etc.Esta versión tenía soporte de memoria de 64 bits para los nuevos G5, usando el sistema LP64.
2006: Mac OS X 10.5 “Leopard”
Mac OS X v10.5 “Leopard” es lanzada hoy 26 de Octubre de 2007. Esta versión es compatible con las PowerPC y con la nueva tecnología Intel. Entre las características de la nueva versión encontramos:
• Time Machine: da la posibilidad de poder volver en el tiempo a una versión especifica de los contenidos de una carpeta, del disco duro completo, de un sólo archivo, de un rollo de fotos en iPhoto, etc.
• Mail 3: es la tercera versión de este programa de correo electrónico de Apple ahora incluye Notas y To-Dos así como variados Templates para enviar email HTML.
• iChat: da la posibilidad de chatear con tabs o de tener iconos animados, ahora también se tiene muchas funciones adicionales para los vídeochats. Desde presentar vídeos, compartir el escritorio, etc.
• El Dashboard: trae una herramienta llamada Dashcode para crear Widgets fácilmente. Adicionalmente Safari tiene un botón “Webclip” que permite tomar cualquier fragmento de una página que se esté viendo y convertirla en un Widget. Accesibilidad, se crearon mejoras en las funciones de accesibilidad para que “todos puedan usar un Mac”.
• El Finder: ahora con CoverFlow similar al de iTunes, tiene una función denominada QuickLook la cual permite abrir varios archivos a la vez con diferentes extensiones y no hay necesidad de abrir el programa, incluso los usuarios podrán hacer búsquedas en otras Mac conectadas en red.
• El Dock: parece una bandeja de vidrio que recibe reflejos, cuenta con un stacks que permite apilar una serie de elementos y cuando se hace clic sobre él se despliegan en un abanico de opciones.
La mayor de ellas siendo un gran avance en las funciones de texto-a-voz con una nueva voz sintetizada llamada Alex, que incluso puede hablar claramente a altas velocidades. Además, trae soporte para pantallas Braille.
2009: Mac OS X 10.6 “Snow Leopard”
UPDATE: La más reciente versión del sistema operativo de Mac, apodado Snow Leopard, fue lanzado el 28 de agosto de 2009 y es más rápido que sus predecesores, además de tener varias nuevas características interesantes:
• Nuevo exposé integrado en el Dock.
• Es posible utilizar el touchpad para insertar caracteres chinos.
• La zona horaria se ajusta automáticamente.
• Ofrece soporte para conectarse a los servidores Microsoft Exchange 2007.
• Menor consumo de espacio en disco duro y soporte (teórico) para un máximo de 16TB de RAM.
También hay que destacar las siguientes innovaciones:
• Grand Central es una tecnología de programación que permite utilizar los procesadores multinúcleo y optimizar el rendimiento.
• Quicktime X tendrá soporte optimizado para códecs actuales.
• OpenCL (Open Computing Language) permitirá programar aplicaciones que utilicen la unidad de procesamiento gráfico para usos no gráficos.
Leer Mas......
miércoles, 19 de mayo de 2010
expr:id='"post-" + data:post.id'>
HISTORIA Y EVOLUCION DE LOS SISTEMAS OPERATIVOS
expr:id='"post-" + data:post.id'>
CUESTIONARIO
CARRERA:
INGENIERIA EN SISTEMAS COMPUTACIONALES.
PROFESOR:
LIC. ULISES BARRADAS.
ALUMNO:
MARIO SILVA RODRIGUREZ.
FECHA DE ENTREGA:
CUESTIONARIO ENTREGA PARA EL 22 DE MAYO DEL 2010.
descargar archivo en word
1 ¿Que es un bit ?
Bit es el acrónimo de Binary digit. (dígito binario). Un bit es un dígito del sistema de numeración binario.
Mientras que en el sistema de numeración decimal se usan diez dígitos, en el binario se usan sólo dos dígitos, el 0 y el 1. Un bit o dígito binario puede representar uno de esos dos valores, 0 ó 1.
Se puede imaginar un bit, como una bombilla que puede estar en uno de los siguientes dos estados:
apagada o encendida
Memoria de computadora de 1980 donde se pueden ver los bits físicos. Este conjunto de unos 4x4 cm. corresponden a 512 bytes.
El bit es la unidad mínima de información empleada en informática, en cualquier dispositivo digital, o en la teoría de la información. Con él, podemos representar dos valores cuales quiera, como verdadero o falso, abierto o cerrado, blanco o negro, norte o sur, masculino o femenino, rojo o azul, etc. Basta con asignar uno de esos valores al estado de "apagado" (0), y el otro al estado de "encendido" (1).
2 ¿Que es un nibble ?
Se denomina nibble o cuarteto al conjunto de cuatro dígitos binarios (bits) o medio octeto. Su interés se debe a que cada cifra enhexadecimal (0, 1, 2,..., 9, A, B, C, D, E, F) se puede representar con un cuarteto, puesto que 24=16. También el cuarteto es la base del sistema de codificación BCD. A continuación se muestra la correspondencia entre las dieciséis cifras hexadecimales y sus correspondientes representaciones binarias en forma de cuarteto:
0000 = 0,
0001 = 1,
0010 = 2,
0011 = 3,
0100 = 4,
0101 = 5,
0110 = 6,
0111 = 7,
1000 = 8,
1001 = 9,
1010 = A,
1011 = B,
1100 = C,
1101 = D,
1110 = E,
1111 = F.
De acuerdo con la anterior correspondencia, es posible codificar números decimales o hexadecimales en BCD según se muestra en los siguientes ejemplos:
0110 1101= 6D (decimal = 50);
0001 0001 0010 = 112 (decimal = 274);
0101 1001 0001 0000 0111 = 5 9107 (decimal = 364807);
Un byte completo está representado por dos dígitos hexadecimales, por tanto, es común visualizar un byte de información como dos nibbles. El nibble a menudo se llama semiocteto o cuarteto en un contexto de redes o telecomunicaciones. En inglés hay un juego de palabrasgastronómico con nibble (que significa mordisqueo), en comparación con bite/byte (bocado) y bit (trozo pequeño).
También podemos encontrar aplicaciones binarias interesantes como el "Tratado Sobre las Células Binarias" creado por el español Pedro Luis Asensio Álvarez, que trata sobre las propiedades, evoluciones genéticas, relaciones externas y creaciones espontáneas de estos números o bits en un medio tecnológico creado por el hombre.
El nibble se utiliza para describir la cantidad de memoria utilizada para almacenar un dígito de un número almacenado en BCD en una mainframe de IBM. Esta técnica se utiliza para reducir los requisitos de espacio, haciendo la computación más rápida y la depuración más sencilla. Un byte de 8 bits es dividido en mitades y cada nibble se utiliza para almacenar un dígito. El último nibble de la variable se reserva para el signo. Así una variable que puede almacenar más de nueve dígitos se "empaquetaría" en 5 bytes. Fácil de depurar resultaban los números que son legibles en un hex dump donde dos números hexadecimales se utilizan para representar el valor de un byte, ya que 16×16 = 28 = 256.
Historicamente, ha habido casos donde el término "nybble" se ha utilizado para un conjunto de bits inferior a 8, pero no necesariamente 4. En la línea Apple II, muchos de los drivers de control de disco se implementaron en software. La escritura de datos en disco se hizo convirtiendo páginas de 256 bytes en conjuntos de 5 bits, o después en nibbles de 6 bits. Los datos cargados del disco necesitaban lo contrario. Hay que notar que el término byte también tiene esta ambigüedad, a la vez, byte significa un conjunto de bits pero no necesariamente 8.
Hoy, los términos "byte" y "nibble" generalmente se refieren a colecciones de 8 y 4 bits, respectivamente y no se utilizan a menudo para otros tamaños.El nibble se usa también cuando aparecen los primeros microprocesadores a principios de los años 1970, ya que dichos dispositivos trabajaban con microinstrucciones las cuales estaban constituidas por grupos de 4 bits. Sin embargo cuando llega la comercialización de los microprocesadores, estos ya pueden trabajar con grupos de 8 bits y es así como inicia la popularidad del Byte en el ámbito de los sistemas digitales y de la informática.En algunos lenguajes, un nibble es llamado un tetrade - del Griego tetra ("cuatro"). Esta utilización refleja el número de bits - cuatro - en medio byte (considerando 1 byte = 8 bits).
3 ¿Con que tipo de señales trabajan los circuitos digitales ?
La señal digital es un tipo de señal generada por algún tipo de fenómeno electromagnético en que cada signo que codifica el contenido de la misma puede ser analizado en término de algunas magnitudes que representan valores discretos, en lugar de valores dentro de un cierto rango. Por ejemplo, el interruptor de la luz sólo puede tomar dos valores o estados: abierto o cerrado, o la misma lámpara: encendida o apagada (véase circuito de conmutación). Esto no significa que la señal físicamente sea discreta ya que los campos electromagnéticos suelen ser continuos, sino que en general existe una forma de discretizarla unívocamente.
Los sistemas digitales, como por ejemplo el ordenador, usan lógica de dos estados representados por dos niveles de tensión eléctrica, uno alto, H y otro bajo, L (de High y Low, respectivamente, en inglés). Por abstracción, dichos estados se sustituyen por ceros y unos, lo que facilita la aplicación de la lógica y la aritmética binaria. Si el nivel alto se representa por 1 y el bajo por 0, se habla de lógica positiva y en caso contrario de lógica negativa.
Cabe mencionar que, además de los niveles, en una señal digital están las transiciones de alto a bajo y de bajo a alto, denominadas flanco de bajada y de subida, respectivamente. En la figura se muestra una señal digital donde se identifican los niveles y los flancos.
Señal digital: 1) Nivel bajo, 2) Nivel alto, 3) Flanco de subida y 4) Flanco de bajada.
Señal digital con ruido
Es conveniente aclarar que, a pesar de que en los ejemplos señalados el término digital se ha relacionado siempre con dispositivos binarios, no significa que digital y binariosean términos intercambiables. Por ejemplo, si nos fijamos en el código Morse, veremos que en él se utilizan, para el envío de mensajes por telégrafo eléctrico, cinco estados digitales, que son:
punto, raya, espacio corto (entre letras), espacio medio (entre palabras) y espacio largo (entre frases)
Referido a un aparato o instrumento de medida, decimos que es digital cuando el resultado de la medida se representa en un visualizador mediante números (dígitos) en lugar de hacerlo mediante la posición de una aguja, o cualquier otro indicador, en una escala.
Una señal analógica es un tipo de señal generada por algún tipo de fenómeno electromagnético y que es representable por una función matemática continua en la que es variable
su amplitud y periodo(representando un dato de información) en función del tiempo. Algunas magnitudes físicas comúnmente portadoras de una señal de este tipo son eléctricas como la intensidad, la tensión y la potencia, pero también pueden ser hidráulicas como la presión, térmicas como la temperatura, mecánicas, etc. Lamagnitud también puede ser cualquier objeto medible como los beneficios o pérdidas de un negocio.
En la naturaleza, el conjunto de señales que percibimos son analógicas, así la luz, el sonido, la energíaetc, son señales que tienen una variación continua. Incluso la descomposición de la luz en el arcoiris vemos como se realiza de una forma suave y continúa.
Una onda senoidal es una señal analógica de una sola frecuencia. Los voltajes de la voz y del video son señales analógicas que varían de acuerdo con el sonido o variaciones de la luz que corresponden a la información que se está transmitiendo.
Un ejemplo de sistema electrónico analógico es el altavoz, que se emplea para amplificar el sonido de forma que éste sea oído por una gran audiencia. Las ondas de sonido que son analógicas en su origen, son capturadas por un micrófono y convertidas en una pequeña variación analógica de tensión denominada señal de audio. Esta tensión varía de manera continua a medida que cambia el volumen y la frecuencia delsonido y se aplica a la entrada de un amplificador lineal. La salida del amplificador, que es la tensión de entrada amplificada, se introduce en el altavoz. Éste convierte, de nuevo, la señal de audio amplificada en ondas sonoras con un volumen mucho mayor que el sonido original captado por el micrófono
4 ¿Define que es un circuito integrado?
Los avances que hicieron posible el circuito integrado han sido, fundamentalmente, los desarrollos en la fabricación de dispositivos semiconductores a mediados del siglo XX y los descubrimientos experimentales que mostraron que estos dispositivos podían reemplazar las funciones de las válvulas o tubos de vacío, que se volvieron rápidamente obsoletos al no poder competir con el pequeño tamaño, el consumo de energía moderado, los tiempos de conmutación mínimos, la confiabilidad, la capacidad de producción en masa y la versatilidad de los CI.
Entre los circuitos integrados más avanzados se encuentran los microprocesadores, que controlan todo desde computadoras hasta teléfonos móviles y hornos microondas. Los chips de memorias digitales son otra familia de circuitos integrados que son de importancia crucial para la moderna sociedad de la información. Mientras que el costo de diseñar y desarrollar un circuito integrado complejo es bastante alto, cuando se reparte entre millones de unidades de producción el costo individual de los CIs por lo general se reduce al mínimo. La eficiencia de los CI es alta debido a que el pequeño tamaño de los chips permite cortas conexiones que posibilitan la utilización de lógica de bajo consumo (como es el caso de CMOS) en altas velocidades de conmutación.
Con el transcurso de los años, los CI están constantemente migrando a tamaños más pequeños con mejores características, permitiendo que mayor cantidad de circuitos sean empaquetados en cada chip (véase la ley de Moore). Al mismo tiempo que el tamaño se comprime, prácticamente todo se mejora (el costo y el consumo de energía disminuyen a la vez que aumenta la velocidad). Aunque estas ganancias son aparentemente para el usuario final, existe una feroz competencia entre los fabricantes para utilizar geometrías cada vez más delgadas. Este proceso, y el esperado proceso en los próximos años, está muy bien descrito por la International Technology Roadmap for Semiconductors, oITRS.
Popularidad de los CI
Solo ha trascurrido medio siglo desde que se inició su desarrollo y los circuitos integrados se han vuelto casi omnipresentes. Computadoras,teléfonos móviles y otras aplicaciones digitales son ahora partes inextricables de las sociedades modernas. La informática, lascomunicaciones, la manufactura y los sistemas de transporte, incluyendo Internet, todos dependen de la existencia de los circuitos integrados. De hecho, muchos estudiosos piensan que la revolución digital causada por los circuitos integrados es uno de los sucesos más significativos de la historia de la humanidad.
5 ¿Caules son los tipos de tecnologia de fabricación en un circuito integrado?
Circuitos monolíticos: Están fabricados en un solo monocristal, habitualmente de silicio, pero también existen en germanio, arseniuro de galio, silicio-germanio, etc.
Circuitos híbridos de capa fina: Son muy similares a los circuitos monolíticos, pero, además, contienen componentes difíciles de fabricar con tecnología monolítica. Muchos conversores A/D y conversores D/A se fabricaron en tecnología híbrida hasta que los progresos en latecnología permitieron fabricar resistencias precisas.
Circuitos híbridos de capa gruesa: Se apartan bastante de los circuitos monolíticos. De hecho suelen contener circuitos monolíticos sin cápsula (dices), transistores, diodos, etc, sobre un sustrato dieléctrico, interconectados con pistas conductoras. Las resistencias se depositan por serigrafía y se ajustan haciéndoles cortes con láser. Todo ello se encapsula, tanto en cápsulas plásticas como metálicas, dependiendo de la disipación de potencia que necesiten. En muchos casos, la cápsula no está "moldeada", sino que simplemente consiste en una resina epoxi que protege el circuito. En el mercado se encuentran circuitos híbridos para módulos de RF, fuentes de alimentación, circuitos de encendido para automóvil, etc.
Leer Mas......
INGENIERIA EN SISTEMAS COMPUTACIONALES.
PROFESOR:
LIC. ULISES BARRADAS.
ALUMNO:
MARIO SILVA RODRIGUREZ.
FECHA DE ENTREGA:
CUESTIONARIO ENTREGA PARA EL 22 DE MAYO DEL 2010.
descargar archivo en word
1 ¿Que es un bit ?
Bit es el acrónimo de Binary digit. (dígito binario). Un bit es un dígito del sistema de numeración binario.
Mientras que en el sistema de numeración decimal se usan diez dígitos, en el binario se usan sólo dos dígitos, el 0 y el 1. Un bit o dígito binario puede representar uno de esos dos valores, 0 ó 1.
Se puede imaginar un bit, como una bombilla que puede estar en uno de los siguientes dos estados:
apagada o encendida
Memoria de computadora de 1980 donde se pueden ver los bits físicos. Este conjunto de unos 4x4 cm. corresponden a 512 bytes.
El bit es la unidad mínima de información empleada en informática, en cualquier dispositivo digital, o en la teoría de la información. Con él, podemos representar dos valores cuales quiera, como verdadero o falso, abierto o cerrado, blanco o negro, norte o sur, masculino o femenino, rojo o azul, etc. Basta con asignar uno de esos valores al estado de "apagado" (0), y el otro al estado de "encendido" (1).
2 ¿Que es un nibble ?
Se denomina nibble o cuarteto al conjunto de cuatro dígitos binarios (bits) o medio octeto. Su interés se debe a que cada cifra enhexadecimal (0, 1, 2,..., 9, A, B, C, D, E, F) se puede representar con un cuarteto, puesto que 24=16. También el cuarteto es la base del sistema de codificación BCD. A continuación se muestra la correspondencia entre las dieciséis cifras hexadecimales y sus correspondientes representaciones binarias en forma de cuarteto:
0000 = 0,
0001 = 1,
0010 = 2,
0011 = 3,
0100 = 4,
0101 = 5,
0110 = 6,
0111 = 7,
1000 = 8,
1001 = 9,
1010 = A,
1011 = B,
1100 = C,
1101 = D,
1110 = E,
1111 = F.
De acuerdo con la anterior correspondencia, es posible codificar números decimales o hexadecimales en BCD según se muestra en los siguientes ejemplos:
0110 1101= 6D (decimal = 50);
0001 0001 0010 = 112 (decimal = 274);
0101 1001 0001 0000 0111 = 5 9107 (decimal = 364807);
Un byte completo está representado por dos dígitos hexadecimales, por tanto, es común visualizar un byte de información como dos nibbles. El nibble a menudo se llama semiocteto o cuarteto en un contexto de redes o telecomunicaciones. En inglés hay un juego de palabrasgastronómico con nibble (que significa mordisqueo), en comparación con bite/byte (bocado) y bit (trozo pequeño).
También podemos encontrar aplicaciones binarias interesantes como el "Tratado Sobre las Células Binarias" creado por el español Pedro Luis Asensio Álvarez, que trata sobre las propiedades, evoluciones genéticas, relaciones externas y creaciones espontáneas de estos números o bits en un medio tecnológico creado por el hombre.
El nibble se utiliza para describir la cantidad de memoria utilizada para almacenar un dígito de un número almacenado en BCD en una mainframe de IBM. Esta técnica se utiliza para reducir los requisitos de espacio, haciendo la computación más rápida y la depuración más sencilla. Un byte de 8 bits es dividido en mitades y cada nibble se utiliza para almacenar un dígito. El último nibble de la variable se reserva para el signo. Así una variable que puede almacenar más de nueve dígitos se "empaquetaría" en 5 bytes. Fácil de depurar resultaban los números que son legibles en un hex dump donde dos números hexadecimales se utilizan para representar el valor de un byte, ya que 16×16 = 28 = 256.
Historicamente, ha habido casos donde el término "nybble" se ha utilizado para un conjunto de bits inferior a 8, pero no necesariamente 4. En la línea Apple II, muchos de los drivers de control de disco se implementaron en software. La escritura de datos en disco se hizo convirtiendo páginas de 256 bytes en conjuntos de 5 bits, o después en nibbles de 6 bits. Los datos cargados del disco necesitaban lo contrario. Hay que notar que el término byte también tiene esta ambigüedad, a la vez, byte significa un conjunto de bits pero no necesariamente 8.
Hoy, los términos "byte" y "nibble" generalmente se refieren a colecciones de 8 y 4 bits, respectivamente y no se utilizan a menudo para otros tamaños.El nibble se usa también cuando aparecen los primeros microprocesadores a principios de los años 1970, ya que dichos dispositivos trabajaban con microinstrucciones las cuales estaban constituidas por grupos de 4 bits. Sin embargo cuando llega la comercialización de los microprocesadores, estos ya pueden trabajar con grupos de 8 bits y es así como inicia la popularidad del Byte en el ámbito de los sistemas digitales y de la informática.En algunos lenguajes, un nibble es llamado un tetrade - del Griego tetra ("cuatro"). Esta utilización refleja el número de bits - cuatro - en medio byte (considerando 1 byte = 8 bits).
3 ¿Con que tipo de señales trabajan los circuitos digitales ?
La señal digital es un tipo de señal generada por algún tipo de fenómeno electromagnético en que cada signo que codifica el contenido de la misma puede ser analizado en término de algunas magnitudes que representan valores discretos, en lugar de valores dentro de un cierto rango. Por ejemplo, el interruptor de la luz sólo puede tomar dos valores o estados: abierto o cerrado, o la misma lámpara: encendida o apagada (véase circuito de conmutación). Esto no significa que la señal físicamente sea discreta ya que los campos electromagnéticos suelen ser continuos, sino que en general existe una forma de discretizarla unívocamente.
Los sistemas digitales, como por ejemplo el ordenador, usan lógica de dos estados representados por dos niveles de tensión eléctrica, uno alto, H y otro bajo, L (de High y Low, respectivamente, en inglés). Por abstracción, dichos estados se sustituyen por ceros y unos, lo que facilita la aplicación de la lógica y la aritmética binaria. Si el nivel alto se representa por 1 y el bajo por 0, se habla de lógica positiva y en caso contrario de lógica negativa.
Cabe mencionar que, además de los niveles, en una señal digital están las transiciones de alto a bajo y de bajo a alto, denominadas flanco de bajada y de subida, respectivamente. En la figura se muestra una señal digital donde se identifican los niveles y los flancos.
Señal digital: 1) Nivel bajo, 2) Nivel alto, 3) Flanco de subida y 4) Flanco de bajada.
Señal digital con ruido
Es conveniente aclarar que, a pesar de que en los ejemplos señalados el término digital se ha relacionado siempre con dispositivos binarios, no significa que digital y binariosean términos intercambiables. Por ejemplo, si nos fijamos en el código Morse, veremos que en él se utilizan, para el envío de mensajes por telégrafo eléctrico, cinco estados digitales, que son:
punto, raya, espacio corto (entre letras), espacio medio (entre palabras) y espacio largo (entre frases)
Referido a un aparato o instrumento de medida, decimos que es digital cuando el resultado de la medida se representa en un visualizador mediante números (dígitos) en lugar de hacerlo mediante la posición de una aguja, o cualquier otro indicador, en una escala.
Una señal analógica es un tipo de señal generada por algún tipo de fenómeno electromagnético y que es representable por una función matemática continua en la que es variable
su amplitud y periodo(representando un dato de información) en función del tiempo. Algunas magnitudes físicas comúnmente portadoras de una señal de este tipo son eléctricas como la intensidad, la tensión y la potencia, pero también pueden ser hidráulicas como la presión, térmicas como la temperatura, mecánicas, etc. Lamagnitud también puede ser cualquier objeto medible como los beneficios o pérdidas de un negocio.
En la naturaleza, el conjunto de señales que percibimos son analógicas, así la luz, el sonido, la energíaetc, son señales que tienen una variación continua. Incluso la descomposición de la luz en el arcoiris vemos como se realiza de una forma suave y continúa.
Una onda senoidal es una señal analógica de una sola frecuencia. Los voltajes de la voz y del video son señales analógicas que varían de acuerdo con el sonido o variaciones de la luz que corresponden a la información que se está transmitiendo.
Un ejemplo de sistema electrónico analógico es el altavoz, que se emplea para amplificar el sonido de forma que éste sea oído por una gran audiencia. Las ondas de sonido que son analógicas en su origen, son capturadas por un micrófono y convertidas en una pequeña variación analógica de tensión denominada señal de audio. Esta tensión varía de manera continua a medida que cambia el volumen y la frecuencia delsonido y se aplica a la entrada de un amplificador lineal. La salida del amplificador, que es la tensión de entrada amplificada, se introduce en el altavoz. Éste convierte, de nuevo, la señal de audio amplificada en ondas sonoras con un volumen mucho mayor que el sonido original captado por el micrófono
4 ¿Define que es un circuito integrado?
Los avances que hicieron posible el circuito integrado han sido, fundamentalmente, los desarrollos en la fabricación de dispositivos semiconductores a mediados del siglo XX y los descubrimientos experimentales que mostraron que estos dispositivos podían reemplazar las funciones de las válvulas o tubos de vacío, que se volvieron rápidamente obsoletos al no poder competir con el pequeño tamaño, el consumo de energía moderado, los tiempos de conmutación mínimos, la confiabilidad, la capacidad de producción en masa y la versatilidad de los CI.
Entre los circuitos integrados más avanzados se encuentran los microprocesadores, que controlan todo desde computadoras hasta teléfonos móviles y hornos microondas. Los chips de memorias digitales son otra familia de circuitos integrados que son de importancia crucial para la moderna sociedad de la información. Mientras que el costo de diseñar y desarrollar un circuito integrado complejo es bastante alto, cuando se reparte entre millones de unidades de producción el costo individual de los CIs por lo general se reduce al mínimo. La eficiencia de los CI es alta debido a que el pequeño tamaño de los chips permite cortas conexiones que posibilitan la utilización de lógica de bajo consumo (como es el caso de CMOS) en altas velocidades de conmutación.
Con el transcurso de los años, los CI están constantemente migrando a tamaños más pequeños con mejores características, permitiendo que mayor cantidad de circuitos sean empaquetados en cada chip (véase la ley de Moore). Al mismo tiempo que el tamaño se comprime, prácticamente todo se mejora (el costo y el consumo de energía disminuyen a la vez que aumenta la velocidad). Aunque estas ganancias son aparentemente para el usuario final, existe una feroz competencia entre los fabricantes para utilizar geometrías cada vez más delgadas. Este proceso, y el esperado proceso en los próximos años, está muy bien descrito por la International Technology Roadmap for Semiconductors, oITRS.
Popularidad de los CI
Solo ha trascurrido medio siglo desde que se inició su desarrollo y los circuitos integrados se han vuelto casi omnipresentes. Computadoras,teléfonos móviles y otras aplicaciones digitales son ahora partes inextricables de las sociedades modernas. La informática, lascomunicaciones, la manufactura y los sistemas de transporte, incluyendo Internet, todos dependen de la existencia de los circuitos integrados. De hecho, muchos estudiosos piensan que la revolución digital causada por los circuitos integrados es uno de los sucesos más significativos de la historia de la humanidad.
5 ¿Caules son los tipos de tecnologia de fabricación en un circuito integrado?
Circuitos monolíticos: Están fabricados en un solo monocristal, habitualmente de silicio, pero también existen en germanio, arseniuro de galio, silicio-germanio, etc.
Circuitos híbridos de capa fina: Son muy similares a los circuitos monolíticos, pero, además, contienen componentes difíciles de fabricar con tecnología monolítica. Muchos conversores A/D y conversores D/A se fabricaron en tecnología híbrida hasta que los progresos en latecnología permitieron fabricar resistencias precisas.
Circuitos híbridos de capa gruesa: Se apartan bastante de los circuitos monolíticos. De hecho suelen contener circuitos monolíticos sin cápsula (dices), transistores, diodos, etc, sobre un sustrato dieléctrico, interconectados con pistas conductoras. Las resistencias se depositan por serigrafía y se ajustan haciéndoles cortes con láser. Todo ello se encapsula, tanto en cápsulas plásticas como metálicas, dependiendo de la disipación de potencia que necesiten. En muchos casos, la cápsula no está "moldeada", sino que simplemente consiste en una resina epoxi que protege el circuito. En el mercado se encuentran circuitos híbridos para módulos de RF, fuentes de alimentación, circuitos de encendido para automóvil, etc.
Leer Mas......
miércoles, 12 de mayo de 2010
expr:id='"post-" + data:post.id'>
INTRODUCCION A LOS SISTEMAS OPERATIVOS UNIDADES 1-2-3
CARRERA: INGENIERIA EN SISTEMAS COMPUTACIONALES.
PROFESOR:LIC. ULISES BARRADAS.
ALUMNOS:TAYDE A. JIMÉNEZ VELÁZQUEZ, MARIO SILVA RODRIGUREZ.
FECHA DE ENTREGA:22 DE MAYO DEL 2010.
VIDEOS RELACIONADOS
descarga archivo en word
UNIDAD 1 “INTRODUCCION A LOS SISTEMAS OPERATIVOS”
1.0 CONCEPTO DE SISTEMA OPERATIVO……………………………………..5
1.1 sistema operativo ……………………………………………….…………………..5
1.1.1 llamadas al sistema……………………………………………….........................5
1.1.2 intérprete de comandos…………………………………………...........................5
1.1.3 núcleo (o kernel)………………………………………………….........................5
1.1.4 programas del sistema…………………………………………….........................5
1.2 programas de aplicación………………………………………….………………..5
1.3 resumen ( sistema operativo) ………………………………………………………6
2.0 TIPOS DE SISTEMAS OPERATIVOS……………………………………….....6
3.0 ESTRUCTURA BASICA DE UN SISTEMA OPERATIVO…………………...6
3.1 cargador………………………………………………………………………..……6
3.1.1 cargador para el sistema operativo………………………………………….……6
3.1.2 cargador incluido en el sistema operativo………………………………….…….6
3.2 supervisor (ejecutivo o monitor)……………………………………………….…..7
3.3 lenguaje de comunicación……………………………………………………….…7
3.4 utileria de sistema……………………………………………………………….….7
4.0 FUNCIONES BASICAS DE UN SISTEMA OPERATIVO…………………....7
4.1 programas de control……………………………………………………………....7
4.1.1 administracion de trabajos…………………………………………………….….7
4.1.2 administracion de recursos…………………………………………………….…7
4.1.3 control de operaciones de entrada y salida…………………………………….…7
4.1.4 administracion de la memoria……………………………………………………7
4.1.5 recuperacion de errores…………………………………………………………..7
4.1.6 programas de proceso…………………………………………………………….8
4.1.6.1 utilerias del sistema…………………………………………………………...8
4.1.6.2 utilerias para archivos………………………………………………………...8
4.1.6.3 utilerias independientes……………………………………………………....8
4.2 TIPOS DE SISTEMA OPERATIVO……………………………………………..8
5.0 ESTRUCTURAS DE SISTEMAS OPERATIVOS ……………………..……8
5.1 la estructura del sistema operativo dos ……………………………………..…8
5.3 estructura del sistema operativo os/2…………………………………………..….9
5.4 estructura del sistema operativo novell – netware………………………………..10
5.5 estructura del sistema operativo windows 95…………………………………….10
5.6 estructura del sistema operativo windows nt…………………………………..…10
6.0 HISTORIA DE LOS SISTEMAS OPERATIVOS …………………….…….11
6.1 historia del sistema operativo ms-dos …………………………………………….11
6.2 historia del sistema operativo unix ……………………………………………….12
6.3 historia del sistema operativo netware de novell………………………………….14
7.0 HARDWARE, SOFTWARE Y FIRMWARE………………………………..14
7.1 hardware………………………………………………………………………….14
7.1.1 placa base o placa madre……………………………………………………….14
7.1.2 grupos de hardware…………………………………………………………….14
7.1.3 dispositivos de entrada………………………………………………………....15
7.1.4 chipset (circuito integrado auxiliar)……………………………………………15
7.1.5 unidad central de procesamiento (cpu)………………………………………....15
7.1.6 unidad de control………………………………………..……………………..15
7.1.7 unidad aritmético-lógica………………………………………….……………15
7.1.8 unidad de almacenamiento…………………………………………………….15
7.1.9 memoria principal o primaria (ram – rom)……………………………………16
7.1.10 memoria secundaria (disco duro, disco flexibles, etc.)………………………16
7.1.11 dispositivos de salida…………………………………………………………16
7.2 software……………………………………………………………………….…16
7.2.2 sistema operativo………………………………………………………………17
7.2.3 controladores de dispositivos……………………………………………….…17
7.2.4 programas utilitarios……………………………………………………..…….17
7.2.5 software de aplicación…………………………………………..…………….17
7.2.6 software de programación…………………………………………..…………17
7.3 firmware………………………………………………………………………….18
UNIDAD 2 “ADMINISTRACION DE PROCESOS”
8.0 DEFINICIÓN Y CONTROL DE PROCESOS………………………………19
8.1 ¿ qué es un proceso ?............................................................................................19
8.2 estados de un proceso y transiciones de estado de los procesos …………..….19
8.3 descripción de un proceso ……………………………………………………….21
8.4 el bloque de control de proceso……………………………………………..….21
8.5 control de un proceso …………………………………………………..………24
8.5.1 modos de ejecución………………………………………………………...…24
8.5.2 cambio de proceso……………………………………………………………25
8.5.3 cambio de contexto………………………………………………………..….26
9.0 COMUNICACIÓN Y SINCRONIZACIÓN DE PROCESOS
9.1 comunicación y sincronización de procesos ……………………….……………28
9.1.1 cooperación entre procesos………………………………………………..…..28
9.1.2 competencia entre los procesos…………………………….…………………..29
9.1.3 requisitos para la exclusión mutua……………………………..………………30
9.2 utilizando memoria compartida……………………………………….…………30
9.2.1 soluciones software al problema de la exclusión mutua…………………….…31
9.2.2 soluciones hardware a la exclusión mutua ……………………..……………..40
9.3 sin utilizar memoria compartida. mensajes………………………………………41
9.4 problemas clásicos de comunicación entre procesos……………………….……45
9.4.1 el problema de la cena de los filósofos………………………….…………….45
9.4.2 el problema de los lectores y los escritores……………………………………48
9.5 un ejemplo de aplicación cliente-servidor…………………………………..….50
10.0 INTERBLOQUEOS…………………………………………………..……..57
10.4.1 Desentenderse. El Algoritmo de la Avestruz ……………..…………62
10.4.2 Prevención de Interbloqueos………………………..………………..63
10.4.3 Evitación de Interbloqueos ………………….……………………….66
10.4.4 Detección y Recuperación de Interbloqueos……………………..….71
10.4 Estrategias para Resolver Interbloqueos……………………………….74
10.5 Interbloqueos: Sistemas Actuales/Sistemas Futuros……………….…..75
UNIDAD 3
11.0 “ADMISTRACIÓN DE LA MEMORIA”
11.1 La organización y gestión de la memoria. Conceptos generales……….77
11.2 Gestión de la memoria en los sistemas monoprogramados………..…..79
11.3 Gestión de la memoria en los sistemas multiprogramados…………….80
11.4 Asignación de memoria contigua………………………………………81
11.4.1 Particiones estáticas………………………………………………….81
11.4.2 Particiones dinámicas…………………………………………………83
11.4.3 Estrategias de colocación……………….…………..………….……..86
11.4.4 Intercambio (swapping)…………………………..…………………..87
11.5 Asignación de memoria no contigua………………………….………..89
11.5.1 Esquema general de traducción ………………………….…………..91
11.5.2 Paginación ……………………………………………………....……94
11.5.2.1 Memoria asociativa…………………………………….…………..97
11.5.2.2 Páginas compartidas………………………………………………..100
11.5.2.3 Protección………………………………………………….………102
11.5.2.4 Dos visiones de la memoria……………………………….………102
11.5.3 Segmentación …………………………………………..……………103
11.5.3.1 Visión del usuario de la memoria………………………………….104
11.5.3.2 Hardware…………………………………………………………..105
11.5.3.3 Implementación de tablas de segmentos……………………………106
11.5.3.4 Compartición y protección……………………………….…………107
11.5.3.5 Fragmentación…………………………………………….………..109
11.5.4 Segmentación paginada………………………………………………110
UNIDAD 1
“INTRODUCCION A LOS SISTEMAS OPERATIVOS”
1.0 CONCEPTO DE SISTEMA OPERATIVO
Conjunto de programas que se integran con el hardware para facilitar al usuario, el aprovechamiento de los recursos disponibles. Algunos de sus objetivos principales son:
Provee de un ambiente conveniente de trabajo.
Hace uso eficiente del Hardware.
Provee de una adecuada distribución de los recursos.
Para un Sistema Operativo real deberá satisfacer las siguientes funciones:
Gobierna el Sistema.
Asigna los recursos.
Administra y controlar la ejecución de los programas.
Un sistema de computo en muchos casos cuenta con demasiados recursos para ser utilizados por un solo usuario, es en estos casos cuando se puede dar servicio a varios procesos.
1.1 Sistema Operativo
1.1.1 Llamadas al Sistema
El Sistema Operativo en conjunto con el Hardware aparecen al usuario como un solo dispositivo con un conjunto de instrucciones más flexibles y variadas a las que se conoce como Llamadas al Sistema (System Callings).
1.1.2 Intérprete de Comandos
También conocido por su nombre en inglés, Shell, es un programa que interpreta las órdenes del usuario y las convierte en Llamadas al Sistema.
1.1.3 Núcleo (o Kernel)
Es la parte del Sistema Operativo que se encarga de sincronizar la activación de los procesos y definir prioridades.
1.1.4 Programas del Sistema
Son programas de servicio que debe ser solicitados explícitamente por los usuarios. Como ejemplos de estos tenemos:
Compiladores
Son programas que traducen Programas Fuente en programas Objeto.
Ensambladores
Traducen programas escritos con mnemónicos a lenguaje de máquina.
Editores
Son programas que permiten escribir textos y guardarlos en memoria secundaria.
Utilerías de Archivos
Programas para dar mantenimiento a los archivos.
Bibliotecas
Programas que contienen rutinas para realizar funciones frecuentemente requeridas. Estas funciones pueden ser ligadas a los programas escritos por el usuario.
1.2 Programas de Aplicación
Programas externos al sistema, utilizados para realizar tareas específicas como simulación, creación y edición de gráficas e imágenes, etc..
1.3 Resumen ( Sistema Operativo)
Es el programa o programas que tienen todas las computadoras modernas, el usuario de un equipo de computo no tiene que preocuparse de como funciona, por ejemplo, una unidad lectora de disco, sólo necesita pedirle al sistema operativo que lo lea o escriba en el disco mediante un comando. El más comúnmente usado es el MS-DOS.
Conjunto de programas que sirven como interfaz entre el usuario (Sirve como agente de intercambio de información entre la computadora y el usuario.) y la computadora, además de que administran los recursos de la misma (Entendiéndose como recursos: Memoria, Disco Duro, Procesador, Monitor, Etc.).
2.0 TIPOS DE SISTEMAS OPERATIVOS
Existen dos tipos generales de sistemas operativos: Los basados en caracteres y los de interfaz gráfica (ambientes amigables). El sistema basado en caracteres es ejemplificado perfectamente con el sistema operativo utilizado por las computadoras IBM y compatibles. El MS-DOS está listo para recibir un comando desplegando el tipo de indicador (A> o C>) en la pantalla; en donde el usuario escribe carácter por carácter el comando que se desea ejecutar.
Ante las justificadas quejas de los usuarios por la falta de programas amigables, los desarrolladores de software respondieron añadiendo menús y mensajes en pantalla. Los menús mejoran en mucho la cordialidad de los programas, reduciendo el número de comandos que se necesitan conocer.
La Macintosh logró crear la primera interfaz gráfica, posteriormente Microsoft introdujo la interfaz gráfica Windows para las computadoras IBM y compatibles.
Cada programa en Windows tiene reservada un área de la pantalla conocida con el nombre de ventana.
Un sistema operativo que se opera mediante el uso de imágenes y símbolos en vez de palabras se denomina interfaz gráfica para el usuario, o GUI (Graphic User Interface).
3.0 ESTRUCTURA BASICA DE UN SISTEMA OPERATIVO
3.1 CARGADOR
Cualquier programa que requiere ser ejecutado en la computadora, deberá ser transferido desde su lugar de residencia a la memoria principal.
3.1.1 CARGADOR PARA EL SISTEMA OPERATIVO
Este programa se encarga de transferir desde algún medio de almacenamiento externo (disco, cinta o tambor) a la memoria principal, los programas del sistema operativo que tienen como finalidad establecer el ambiente de trabajo del equipo de cómputo. Existe un programa especial almacenado en memoria ROM que se encarga de accesar a este programa cargador. Cuando el sistema operativo esta cargado en memoria toma el control absoluto de las operaciones del sistema.
3.1.2 CARGADOR INCLUIDO EN EL SISTEMA OPERATIVO
Su función es cargar a memoria todos los archivos necesarios para la ejecución de un proceso.
3.2 SUPERVISOR (EJECUTIVO O MONITOR)
Es el administrador del sistema que controla todo el proceso de la información por medio de un gran número de rutinas que entran en acción cuando son requeridos. Funge como enlace entre los programas del usuario y todas las rutinas que controlan los recursos requeridos por el programa para posteriormente continuar con su ejecución.
El supervisor también realiza otras funciones como son:
- Administra la memoria.
- Administración de las rutinas que controlan el funcionamiento de los recursos de la computadora.
- Manejo de Archivos
- Administración y control de la ejecución de los programas.
3.3 LENGUAJE DE COMUNICACION
Es el medio a través del cual el usuario interactúa directamente con el sistema operativo y esta formado por comandos que son introducidos a través de algún dispositivo. Generalmente un comando consta de dos partes, la primera formada por una palabra que identifica el comando y la acción a realizar y la segunda parte por un conjunto de valores o parámetros que permiten seleccionar diversas operaciones de entre los que dispone el comando.
3.4 UTILERIA DE SISTEMA
Son programas o rutinas del sistema operativo que realizan diversas funciones de uso común o aplicación frecuente como son: clasificar, copiar e imprimir información.
4.0 FUNCIONES BASICAS DE UN SISTEMA OPERATIVO
4.1 PROGRAMAS DE CONTROL
4.1.1 ADMINISTRACION DE TRABAJOS
Cuando existen varios programas en espera de ser procesados, el sistema operativo debe decidir el orden de procesamiento de ellos, así como asignar los recursos necesarios para su proceso.
4.1.2 ADMINISTRACION DE RECURSOS
Mediante está función el sistema operativo esta en capacidad de distribuir en forma adecuada y en el momento oportuno los diferentes recursos (memoria, dispositivos, etc.,...) entre los diversos programas que se encuentran en proceso, para esto, lleva un registro que le permite conocer que recursos están disponibles y cuales están siendo utilizados, por cuanto tiempo y por quien, etc.
4.1.3 CONTROL DE OPERACIONES DE ENTRADA Y SALIDA
Mediante esta actividad el sistema operativo decide que proceso hará uso del recurso, durante cuánto tiempo y en que momento.
4.1.4 ADMINISTRACION DE LA MEMORIA
Supervisa que áreas de memoria están en uso y cual están libre, determina cuanta memoria asignará a un proceso y en que momento, además libera la memoria cuando ya no es requerida para el proceso.
4.1.5 RECUPERACION DE ERRORES
El sistema operativo contiene rutinas que intentan evitar perder el control de una tarea cuando se suscitan errores en la trasferencia de información hacia y desde los dispositivos de entrada / salida.
4.1.6 PROGRAMAS DE PROCESO
El sistema operativo contiene programas de servicios que sirven de apoyo al procesamiento de los trabajos, se conocen también como utilerías y se pueden clasificar en tres tipos:
4.1.6.1 UTILERIAS DEL SISTEMA
Se ejecutan bajo el control del sistema operativo y se utilizan para preparar algunos recursos usados por el sistema. Son de uso interno.
4.1.6.2 UTILERIAS PARA ARCHIVOS
Manejan información de los archivos tales como imprimir, clasificar, copiar, etc.
4.1.6.3 UTILERIAS INDEPENDIENTES
Realizar funciones que se relacionan con la iniciación de dispositivos de Entrada/Salida, carga del sistema operativo, etc.
4.2 TIPOS DE SISTEMA OPERATIVO
El sistema operativo como controlador y supervisor de todas las actividades que realiza la computadora tiene características que le permiten soportar técnicas avanzadas de procesamiento de datos como:
- La utilización de Lenguaje de Alto Nivel.
- Tiempo Compartido.
- Multiprogramación.
- Memoria Virtual.
5.0 ESTRUCTURAS DE SISTEMAS OPERATIVOS
5.1 La estructura del sistema operativo DOS
Es representada en la siguiente figura:
Como puede verse en primer término, rodeando al hardware se encuentra una parte del software denominada BIOS residente en memoria de sólo lectura ROM, cuyas misiones son las siguientes:
Realizar un test de todo el equipo en cada proceso de arranque donde se examinan todos los elementos conectados y en qué estado se encuentran.
Hacer de interfaz entre el software de los niveles superiores y el hardware a través de una serie de rutinas, cada una de ellas con una misión específica.
El siguiente nivel corresponde al núcleo del sistema operativo, que permanece constantemente en la memoria desde que se enciende en el equipo. Esta compuesto por el programa intérprete de comandos (COMMAND.COM) que lleva consigo la carga de una serie de comandos residentes permanentes en memoria y dos archivos de los denominados ocultos, pues no aparecen en el directorio del disco que los contienen pero que se encuentran presentes. Estos archivos tienen rutinas que permiten ampliar y actualizar (evolución de las versiones DOS) las rutinas de la ROM-BIOS.
5.2 ESTRUCTURA DEL SISTEMA OPERATIVO UNIX
El sistema operativo UNIX es un sistema de tiempo compartido y, por tanto multiusuario, en el que existe portabilidad para la implantación en distintas computadoras.
Esta formado por una serie de elementos que pueden representarse en esta fo rma de capas concentricas donde, en primer lugar, alrededor del hardware de la máquina se encuentran el núcleo (kernel), que interactuán directamente con el hardware, aislando a este de los usuarios, además de adaptar el resto del sistema operativo a la máquina debido a la portabilidad que existe en el mismo.
En una segunda capa se encuentran los comandos, que no son otra cosa que el interface entre los programas de aplicación y el núcleo del sistema operativo. La última de las capas contiene los programas de aplicación.
5.3 ESTRUCTURA DEL SISTEMA OPERATIVO OS/2
El sistema operativo OS/2 al trabajar en modo real para la ejecución del programa DOS ya existentes, deja libertad al proceso para acceder a la memoria, utilizar dispositivos, entre otros.
El modo protegido para los programas de OS/2 en el que varios de ellos pueden estar coexistiendo en la memoria y compartiendo recursos del sistema, tiene una estructura a través de la cual el propio sistema ejerce el control de los procesos.
Para que exista compatibilidad con el software DOS, el sistema OS/2 posee dos modos de ejecución de sus programas:
Proceso en modo real. En el una computadora puede acceder al hardware directamente, realizar operaciones de entrada/salida de bajo nivel y controlar todos los recursos de la computadora, no existiendo interferencias entre un programa y otro, es decir se ejecuta un solo programa.
Proceso en modo protegido. Es el modo que permite la ejecución de programas en multiprogramación o multitarea.
El sistema operativo OS/2 precisa una configuración mínima del hardware para su funcionamiento. Las nuevas incorporaciones del OS/2 frente al DOS se encuentran en aspectos relacionados con:
Multiprogramación o Multitarea.
Gestión de memoria virtual.
Utilización de dispositivos virtuales.
Comunicación entre procesos concurrentes.
Interconexión en redes.
Gráficos avanzados.
Interfaz potente con el usuario.
5.4 ESTRUCTURA DEL SISTEMA OPERATIVO NOVELL - NETWARE
Novell netware, es una red Novell. Una red de área local que es controlada por alguno de los sistemas operativos Netware de Novell.
Netware, es una familia de sistemas operativos de redes Novell. Que se ejecuta desde una PC 286, 386,486; soporta a los sistemas operativos DOS, OS/2, estaciones de trabajo y una variedad de métodos de accesos de red de área local. Netware de Novell es uno de los programas de control de redes más usado.
5.5 ESTRUCTURA DEL SISTEMA OPERATIVO WINDOWS 95
Windows 95, es un sistema operativo de desarrollo abierto y gráfico, este sistema operativo se clasifica como multiusuario y multitarea, ya que permite la ejecución de procesos en forma simultánea, es decir realiza las operaciones en forma paralela. Este sistema operativo nos brinda el servicio de acceso a la información que requiere el usuario para compartir archivos desde distintas estaciones de trabajo, además de un ambiente de desarrollo Cliente-Servidor. que permite el acceso a Internet, al correo electrónico, entre otros.
El sistema operativo Windows 95 es una aplicación de 32 bits, que maneja simultáneamente aplicaciones de 16 a 32 bits.
5.6 ESTRUCTURA DEL SISTEMA OPERATIVO WINDOWS NT
La aparición de sistemas operativos de 32 bits es ya el presente. Windows NT ofrece, además, un sistema integrado de red que lo distinguirá de sus competidores y puede gestión del sistema.
El núcleo de Windows NT está enfocado para dar todo el soporte necesario y hacerlo con unos niveles de seguridad, desconocidos hasta el presente nivel de computadores personales.
Windows NT proporciona un sistema avanzado en el que se ha pretendido integrar funcionalidades tales como capacidad de conexión Peer-to-Peer, nivel de seguridad C2 o un amplio espectro de compatibilidades con redes existentes (a nivel de protocolos y adaptadores).
6.0 HISTORIA DE LOS SISTEMAS OPERATIVOS
6.1 HISTORIA DEL SISTEMA OPERATIVO MS-DOS
Con la aparición de la computadora personal de IBM en 1981, se desarrollo el sistema operativo (DOS), siendo sus creadores las empresas Microsoft Corporation e IBM. En aquel año se utilizaban dos versiones similares, una de cada empresa denominadas MS-DOS 1.0 Y PC-DOS 1.0, que permitían a los usarios del PC (computadora personal) una serie de órdenes básicas para su funcionamiento. La característica principal de estas primeras versiones era la utilización de un subsistema de archivos que ha permitido compatibilizar éstos en las sucesivas versiones así como en otros sistemas operativos como el OS/2. Otra característica de esta primera versión era la utilización de disquetes de 5.25 pulgadas de una sola cara con una capacidad de 160K.
En el año 1982, la empresa mejoró el sistema operativo permitiendo el uso de los disquetes de doble cara con una capacidad de 360K. Esta visión fue la del MS-DOS 1.25.
En 1983, las empresas Microsoft e IBM mejoran notablemente el sistema operativo dotándole de una buena gestión de archivos (aparición de subdirectorios, etc.), ampliando el conjunto de órdenes y mejorando algunos de las existentes. Las versiones surgidas en aquel año fueron 2.0, 2.01, 2.10, 2.11 y 2.25.
En el año 1984 y con la aparición del modelo PC-AT, se desarrollaron dos nuevas versiones. La DOS 3.0, que incorpora la utilización de discos de 5.25 pulgadas de alta densidad (1.4 Mbytes) y discos fijos también de gran capacidad y la versión DOS 3.1, que permite la conexión de computadoras personales bajo DOS en redes de área local y su utilización como servidores en entornos multiusuarios.
La versión DOS 3.2, aparecida en 1986, además de la mejora en cuanto a órdenes, introdujo la posibilidad de utilización de disquetes de 3.5 pulgadas tanto en baja (720K) como de alta densidad (1.2 Mbytes).
En 1987, con la aparición de otras arquitecturas de computadoras personales (80286, 80386, etc.) compatibles con las anteriores pero con importantes mejoras tecnológicas, se comercializo la versión DOS 3.3, capaz de ser implantado en la nueva serie de computadores personales PS/2 de IBM.
En 1988, aparece la versión DOS 4.X, de características superiores a las anteriores.
En 1989, se tienen versiones DOS 5.X . Actualmente se encuentran ya en el mercado la versión 6.X.
6.2 HISTORIA DEL SISTEMA OPERATIVO UNIX
1965: Las empresas Bell Telephone Laboratories y General Electric Company intervienen enm el proyecto MAC para desarrollar un nuevo sistema operativo denominado MULTICS, cuyo objetivo fue el ofrecer un sistema multiusuario de gran potencia de proceso, gran capacidad de almacenamienmto y con grandes facilidades para compartir datos entre procesos.
1969: Vistos los resultados poco satisfactorios del MULTICS, la Bell Telephone Laboratories se retira del proyecto y desarrolla un sistema de tiempo compartido con paginación por demanda para uso interno de la empresa sobre la computadora PDP-7 de Digital, siendo los artífices del mismo un equipo encabezado por Ken Thompson y Denis Ritchie. Este sistema operativo constituyó la primera versión de UNIX, que solo permitía la explotación en monoprogramación.
1971: El resultado del sistema anterior tuvo tanto éxito que la compañía puso a disposición de Thompson y Ritchie una computadora más potente, que fue la PDP-11 de Digital. En ella Thompson desarrollo el lenguaje de programación B inspirandose en el BCPL y en el FORTRAN, y a continuación Ritchie creo el lenguaje C, con el que consiguió la generación de código de máquina, descripción de tipo de datos y de estructuras.
1973: Se reescribe en C la versión de UNIX desarrollada en ensamblador y que prácticamente es la que ha mantenido hasta hoy. Aparece una versión de UNIX conocida por Programmer's Workbench (PWB).
1974: Se introduce el sistema operativo UNIX en las Universidades norteamericanas con fines educativos.
1977: Se construye la primera versión comercial del UNIX, conocida como versión 6, implantándose por primera vez en una computadora distinta de la PDP, que fue la INTERDATA 8/32.
1979: aparece la versión 7 de UNIX para PDP y una versión para la computadora VAX de digital (32 bits) conocida como 32V.
1981: Nace la primera versión de UNIX para computadoras personales con el nombre de XENIX.
1982: Para la distribución externa los laboratorios Bell desarrollan el UNIX System III, que no es más que el original con algunas pequeñas variantes. Por otra parte la Universidad de Berkeley desarrolla una variante del UNIX 32V para computadoras VAX con mejoras en cuanto a comandos y gestión de la memoria virtual paginada, denominada 4.1 BSD.
1983: La empresa AT&T anuncia una nueva versión denominada UNIX System V, que es el sistema actual y que presenta importantes mejoras de rendimiento, comunicaciones, etc.
1984: La Universidad de Brekeley presenta la versión 4.2 BSD para computadoras VAX, que también se aplica en estaciones de trabajo SUN 2/3 de SUN MICROSYSTEMS.
En la actualidad se utilizan fundamentalmente dos versiones del sistema operativo:
UNIX System V.
SCO UNIX System V.
UNIX
El Sistema Operativo Unix fue diseñado originalmente a finales de los años sesenta y principios de los años setenta por AT&T.
Su sencillez y elegancia llamaron la atención de investigadores de las universidades y la industria. UNIX ha alcanzado una posición de extraordinaria importancia, siendo el único sistema operativo que las compañías parecen dispuestas a aceptar como estándar preferido de sistema operativo. UNIX es el único sistema operativo que se ha instalado en todo tipo de computadores, desde los micro hasta los supercomputadores, y es el único sistema operativo que implanta casi todos los fabricantes importantes de computadores.
La estandarización de UNIX se ha convertido en un tema cada vez mas debatido. Parece poco probable que en el futuro surja una norma UNIX única. AT&T continua promoviendo su UNIX System, muy utilizado en la industria. Las universidades siguen prefiriendo el UNIX de Berkeley. La comunidad UNIX ha cooperado en el desarrollo de una especificación estandarizado del sistema denominado POSIX que es un subconjunto de los principales sistemas UNIX. La fundación de sistemas de Software se constituyo para producir una versión de UNIX basada en gran medida en la AIX de IBM, sistema parecido a UNIX.
Pasará muchos años antes de que aparezca un solo UNIX estandarizado, si es que se consigue alguna vez.. Tal vez no exista un diseño de sistemas opertivos capaz de satisfacer las diversas necesidades de la comunidad informática mundial.
6.4 HISTORIA DEL SISTEMA OPERATIVO NETWARE DE NOVELL
ELS Netware (Entry Level System- sistema de nivel de entrada). Fue el primer sistema de igual a igual (peer to peer) de Novell que soporta hasta ocho estaciones de trabajo y ha sido reemplazado por Netware Lite.
Netware 2.x ( el primer Netware 286 avanzado) se ejecuta en un servidor de archivos y soporta hasta 100 usuarios. Es el único programa de control en el servidor. Netware 3.x (el primer Netware 386) se ejecuta en servidores 386 y superiores y se aprovecha de 32 bits. Las versiones 3.x están disponibles de 10 a 4.000 nodos.
Netware 4.0, previsto para 1993, es de compatibilidad descendente con Netware 2.x y 3.x e incluye el servidor de nombrado NDS (Netware Directory Service - servicio de directorios Netware) que proporciona compatibilidad X.500.
SFT Netware (System Fault Tolerant-tolerante a fallos del sistema). Proporciona recuperación automática de un mal funcionamiento de la red.
Netware para VMS proporciona conectividad Netware a redes VAX, portable Netware facilita código fuente Netware para conversión a otras plataformas.
Netware Lite se ha diseñado para redes pequeñas de PC de igual a igual con migración ascendente a sistemas más grandes de Novell. El conjunto de arranque conecta dos PC.
El sistema Operativo de Red Netware 4.1, es la culminación de 12 de años de mejoramiento continuo de los standares en la industria de sistema operativos de red. El servidor Windows NT ha sido desarrollado como muchos otros: un sistema desktop o de escritorio, un servidor de aplicaciones. El servidor de Netware aventaja al de Windows NT, en 5 áreas específicas.
Netware 4.1 ofrece un servicio de directorio Netware NDS, diseñado para proporcionar un entorno administrativo centralizado, seguro y escaleable para la distribución global de la red.
7.0 HARDWARE, SOFTWARE Y FIRMWARE
7.1 Hardware
Los componentes y dispositivos del Hardware se dividen en Hardware Básico yHardware Complementario
El Hardware Básico: son las piezas fundamentales e imprescindibles para que la computadora funcione como son: Placa base, monitor, teclado y ratón.
El Hardware Complementario: son todos aquellos dispositivos adicionales no esenciales como pueden ser: impresora, escáner, cámara de vídeo digital, webcam, etc.
7.1.1 Placa Base o Placa Madre
Los componentes Hardware más importantes de la computadora y esenciales para su funcionamiento se encuentran en la Placa Base (también conocida como Placa Madre), que es una placa de circuito impreso que aloja a la Unidad Central de Procesamiento (CPU) o microprocesador, Chipset (circuito integrado auxiliar), Memoria RAM, BIOS o Flash-ROM, etc., además de comunicarlos entre sí.
7.1.2 Grupos de Hardware
Según sus funciones, los componentes y dispositivos del hardware se dividen en varios grupos y en el siguiente orden:
Dispositivos de Entrada
Chipset (Circuito Integrado Auxiliar)
Unidad Central de Procesamiento (CPU)
Unidad de Control
Unidad Aritmético-Lógica
Unidad de Almacenamiento
Memoria Principal o Primaria (RAM – ROM)
Memoria Secundaria o Auxiliar (Disco Duro, Flexible, etc.)
Dispositivos de Salida
7.1.3 Dispositivos de Entrada
Los Dispositivos de Entrada son aquellos a través de los cuales se envían datos externos a la unidad central de procesamiento, como el teclado, ratón, escáner, o micrófono, entre otros.
7.1.4 Chipset (Circuito Integrado Auxiliar)
El Chipset o Circuito Integrado Auxiliar es la médula espinal de la computadora, integrado en la placa base, hace posible que esta funcione como eje del sistema permitiendo el tráfico de información entre el microprocesador (CPU) y el resto de componentes de la placa base, interconectándolos a través de diversos buses que son: el Northbridge (Puente Norte) y el Southbridge (Puente Sur).
El Northbridge o Puente Norte es un circuito integrado que hace de puente de enlace entre el microprocesador y la memoria además de las tarjetas gráficas o de vídeo AGP o PCI-Express, así como las comunicaciones con el Puente Sur.
El Southbridge o Puente Sur (también conocido como Concentrador de Controladores de Entrada/Salida), es un circuito integrado que coordina dentro de la placa base los dispositivos de entrada y salida además de algunas otras funcionalidades de baja velocidad. El Puente Sur se comunica con la CPU a través delPuente Norte.
7.1.5 Unidad Central de Procesamiento (CPU)
La CPU (Central Processing Unit o Unidad Central de Procesamiento) puede estar compuesta por uno o varios microprocesadores de circuitos integrados que se encargan de interpretar y ejecutar instrucciones, y de administrar, coordinar y procesar datos, es en definitiva el cerebro del sistema de la computadora. además, la velocidad de la computadora depende de la velocidad de la CPU o microprocesador que se mide en Mhz (unidad de medida de la velocidad de procesamiento). Se divide en varios registros:
7.1.6 Unidad de Control
La Unidad de Control es la encargada de controlar que las instrucciones se ejecuten, buscándolas en la memoria principal, decodificándolas (interpretándolas) y que después serán ejecutadas en la unidad de proceso.
7.1.7 Unidad Aritmético-Lógica
La Unidad Aritmético-Lógica es la unidad de proceso donde se lleva a cabo la ejecución de las instrucciones con operaciones aritméticas y lógicas.
7.1.8 Unidad de Almacenamiento
La Unidad de Almacenamiento o Memoria guarda todos los datos que son procesados en la computadora y se divide en Memoria Principal y Memoria Secundaria o Auxiliar.
7.1.9 Memoria Principal o Primaria (RAM – ROM)
En la Memoria Principal o Primaria de la computadora se encuentran las memoriasRAM, ROM y CACHÉ.
La Memoria RAM (Random Access Memory o Memoria de Acceso Aleatorio) es un circuito integrado o chip que almacena los programas, datos y resultados ejecutados por la computadora y de forma temporal, pues su contenido se pierde cuando esta se apaga. Se llama de acceso aleatorio - o de acceso directo - porque se puede acceder a cualquier posición de memoria sin necesidad de seguir un orden. LaMemoria RAM puede ser leída y escrita por lo que su contenido puede ser modificado.
La Memoria ROM (Read Only Memory o Memoria de sólo lectura) viene grabada en chips con una serie de programas por el fabricante de hardware y es sólo de lectura, por lo que no puede ser modificada - al menos no muy rápida o fácilmente - y tampoco se altera por cortes de corriente. En esta memoria se almacenan los valores correspondientes a las rutinas de arranque o inicio del sistema y a su configuración.
La Memoria Caché o RAM Caché es una memoria auxiliar de alta velocidad, que no es más que una copia de acceso rápido de la memoria principal almacenada en los módulos de RAM.
7.1.10 Memoria Secundaria (Disco Duro, Disco Flexibles, etc.)
La Memoria Secundaria (también llamada Periférico de Almacenamiento) está compuesta por todos aquellos dispositivos capaces de almacenar datos en dispositivos que pueden ser internos como el disco duro, o extraíble como los discos flexibles (disquetes), CDs, DVDs, etc.
7.1.11 Dispositivos de Salida
Los Dispositivos de Salida son aquellos que reciben los datos procesados por la computadora y permiten exteriorizarlos a través de periféricos como el monitor, impresora, escáner, plotter, altavoces,etc.
Dispositivos de Entrada/Salida (Periféricos mixtos): Hay dispositivos que son tanto de entrada como de salida como los mencionados periféricos de almacenamiento, CDs, DVDs, así como módems, faxes, USBs, o tarjetas de red.
7.2 Software
El Software es el soporte lógico e inmaterial que permite que la computadora pueda desempeñar tareas inteligentes, dirigiendo a los componentes físicos o hardware con instrucciones y datos a través de diferentes tipos de programas.
El Software son los programas de aplicación y los sistemas operativos, que según las funciones que realizan pueden ser clasificados en:
Software de Sistema
Software de Aplicación
Software de Programación
7.2.1 Software de Sistema
Se llama Software de Sistema o Software de Base al conjunto de programas que sirven para interactuar con el sistema, confiriendo control sobre el hardware, además de dar soporte a otros programas.
El Software de Sistema se divide en:
Sistema Operativo
Controladores de Dispositivos
Programas Utilitarios
7.2.2 Sistema operativo
El Sistema Operativo es un conjunto de programas que administran los recursos de la computadora y controlan su funcionamiento.
Un Sistema Operativo realiza cinco funciones básicas: Suministro de Interfaz al Usuario, Administración de Recursos, Administración de Archivos, Administración de Tareas y Servicio de Soporte.
Suministro de interfaz al usuario: Permite al usuario comunicarse con la computadora por medio de interfaces que se basan en comandos, interfaces que utilizan menús, e interfaces gráficas de usuario.
Administración de recursos: Administran los recursos del hardware como la CPU, memoria, dispositivos de almacenamiento secundario y periféricos de entrada y de salida.
Administración de archivos: Controla la creación, borrado, copiado y acceso de archivos de datos y de programas.
Administración de tareas: Administra la información sobre los programas y procesos que se están ejecutando en la computadora. Puede cambiar la prioridad entre procesos, concluirlos y comprobar el uso de estos en la CPU, así como terminar programas.
Servicio de soporte: Los Servicios de Soporte de cada sistema operativo dependen de las implementaciones añadidas a este, y pueden consistir en inclusión de utilidades nuevas, actualización de versiones, mejoras de seguridad, controladores de nuevos periféricos, o corrección de errores de software.
7.2.3 Controladores de Dispositivos
Los Controladores de Dispositivos son programas que permiten a otros programa de mayor nivel como un sistema operativo interactuar con un dispositivo de hardware.
7.2.4 Programas Utilitarios
Los Programas Utilitarios realizan diversas funciones para resolver problemas específicos, además de realizar tareas en general y de mantenimiento. Algunos se incluyen en el sistema operativo.
7.2.5 Software de Aplicación
El Software de Aplicación son los programas diseñados para o por los usuarios para facilitar la realización de tareas específicas en la computadora, como pueden ser las aplicaciones ofimáticas (procesador de texto, hoja de cálculo, programa de presentación, sistema de gestión de base de datos...), u otros tipos de software especializados como software médico, software educativo, editores de música, programas de contabilidad, etc.
7.2.6 Software de Programación
El Software de Programación es el conjunto de herramientas que permiten al desarrollador informático escribir programas usando diferentes alternativas y lenguajes de programación.
Este tipo de software incluye principalmente compiladores, intérpretes, ensambladores, enlazadores, depuradores, editores de texto y un entorno de desarrollo integrado que contiene las herramientas anteriores, y normalmente cuenta una avanzada interfaz gráfica de usuario (GUI).
7.3 FIRMWARE.
Es un programa almacenado en un chip de memoria flash de un dispositivo de hardware cuya función es asegurar su correcto funcionamiento. Firmware o Programación en Firme, es un bloque de instrucciones de programa para propósitos específicos, grabado en una memoria tipo ROM, que establece la lógica de más bajo nivel que controla los circuitos electrónicos de un dispositivo de cualquier tipo. Al estar integrado en la electrónica del dispositivo es en parte hardware, pero también es software, ya que proporciona lógica y se dispone en algún tipo de lenguaje de programación. Funcionalmente, el firmware es el intermediario (interfaz) entre las órdenes externas que recibe el dispositivo y su electrónica, ya que es el encargado de controlar a ésta última para ejecutar correctamente dichas órdenes externas.
Encontramos Firmware en memorias ROM de los sistemas de diversos dispositivos
UNIDAD 2 “ADMINISTRACION DE PROCESOS”
8.0 DEFINICIÓN Y CONTROL DE PROCESOS
Los sistemas operativos multiprogramados necesitan del concepto de proceso. El sistema operativo debe entremezclar la ejecución de un número de procesos para maximizar la utilización de los recursos del ordenador. Al mismo tiempo, los sistemas de tiempo compartido deben proporcionar un tiempo de respuesta razonable. El sistema operativo debe asignar recursos a los procesos de acuerdo a una política específica (ciertas funciones o aplicaciones son de mayor prioridad), mientras impide los interbloqueos. Por último, el sistema operativo debe ofrecer un soporte para llevar a cabo la comunicación entre procesos.
El concepto de proceso es clave en los sistemas operativos modernos. La gestión del procesador mediante multiprogramación, revolucionó la concepción de los sistemas operativos, e introdujo el término proceso como elemento necesario para realizar dicha gestión. Por lo demás, este tema trata sobre la definición de proceso, el estudio de sus propiedades, y la gestión que realiza el sistema operativo para crear la abstracción de proceso, aunque esto último se completará en el tema de planificación. Por último, descubriremos que el concepto de proceso encierra, en realidad, dos características potencialmente independientes: por un lado, es una unidad a la que se le asigna y posee recursos y, por otro, es una unidad planificable. Basándonos en esta distinción emprenderemos el estudio de los threads (hebra o hilo), o también llamados procesos ligeros.
8.1 ¿ Qué es un proceso ?
Hasta ahora hemos utilizado siempre el término programa. A partir de ahora distinguiremos entre programa y proceso. Un programa es una secuencia de instrucciones escrita en un lenguaje dado. Un proceso es una instancia de ejecución de un programa, caracterizado por su contador de programa, su palabra de estado, sus registros del procesador, su segmento de texto, pila y datos, etc. Un programa es un concepto estático, mientras que un proceso es un concepto dinámico. Es posible que un programa sea ejecutado por varios usuarios en un sistema multiusuario, por cada una de estas ejecuciones existirá un proceso, con su contador de programa, registros, etc. El sistema operativo necesita el concepto de proceso para poder gestionar el procesador mediante la técnica de multiprogramación o de tiempo compartido, de hecho, el proceso es la unidad planificable, o de asignación de la CPU.
8.2 Estados de un proceso y Transiciones de estado de los procesos
Durante su vida, un proceso puede pasar por una serie de estados discretos, algunos de ellos son:
En ejecución: El proceso ocupa la CPU actualmente, es decir, se está ejecutando.
Listo o preparado: El proceso dispone de todos los recursos para su ejecución, sólo le falta la CPU.
Bloqueado: Al proceso le falta algún recurso para poder seguir ejecutándose, además de la CPU. Por recurso se pueden entender un dispositivo, un dato, etc. El proceso necesita que ocurra algún evento que le permita poder proseguir su ejecución.
Hay otros estados de los procesos, pero en la presente exposición se tratarán estos tres. Por sencillez, se considera un sistema con una sola CPU, aunque no es difícil la extensión a múltiples procesadores. Solamente puede haber un proceso en ejecución a la vez, pero pueden existir varios listos y varios pueden estar bloqueados. Así pues, se forman una lista de procesos listos y otra de procesos bloqueados. La lista de procesos listos se ordena por prioridad, de manera que el siguiente proceso que reciba la CPU será el primero de la lista. La lista de procesos bloqueados normalmente no está ordenada; los procesos no se desbloquean (es decir, no pasan a ser procesos listos) en orden de prioridad, sino que lo hacen en el orden de ocurrencia de los eventos que están esperando. Como se verá más adelante, hay situaciones en las cuales varios procesos pueden bloquearse esperando la ocurrencia del mismo evento; en tales casos es común asignar prioridades a los procesos que esperan.
Transiciones de estado de los procesos
A continuación se dan ejemplos de eventos que pueden provocar transiciones de estado en un proceso en este modelo de tres estados (ver figura 2.1). La mayoría de estos eventos se discutirán con profundidad a lo largo del curso:
De ejecución á Bloqueado: al iniciar una operación de E/S, al realizar una operación WAIT sobre un semáforo a cero (en el tema de procesos concurrentes se estudiarán los semáforos).
De ejecución á Listo: por ejemplo, en un sistema de tiempo compartido, cuando el proceso que ocupa la CPU lleva demasiado tiempo ejecutándose continuamente (agota su cuanto) el sistema operativo decide que otro proceso ocupe la CPU, pasando el proceso que ocupaba la CPU a estado listo.
De Listo á en ejecución: cuando lo requiere el planificador de la CPU (veremos el planificador de la CPU en el tema de planificación de procesos).
De Bloqueado á Listo: se dispone del recurso por el que se había bloqueado el proceso. Por ejemplo, termina la operación de E/S, o se produce una operación SIGNAL sobre el semáforo en que se bloqueó el proceso, no habiendo otros procesos bloqueados en el semáforo.
Obsérvese que de las cuatro transiciones de estado posibles, la única iniciada por el proceso de usuario es el bloqueo, las otras tres son iniciadas por entidades externas al proceso.
Figura 2.1 Transiciones de estado de los procesos.
Interpretación de la figura. Como podemos observar en esta figura tenemos una serie de transiciones posibles entre estados de proceso, representados a partir mediante una gama de colores. Estos colores hay que interpretarlos de forma que, el color del borde de los estados representa a dichos estados, los colores dentro de los circulos nos dicen las posibles alternativas de acceso hacia otro estado, y los colores de las flechas nos representan hacia que estado nos dirigimos si seguimos la misma.
8.3 Descripción de un proceso
De algún modo, debemos hacer una pregunta fundamental: ¿cuál es la manifestación física de un proceso? Como mínimo debe incluir un programa o conjunto de programas que sean ejecutados. Asociados a estos programas hay un conjunto de ubicaciones de datos para las variables locales y globales, y las constantes definidas. Así pues, un proceso constará, al menos, de la memoria suficiente para albergar los programas y los datos del proceso. Además, en la ejecución de un programa entra en juego normalmente una pila, que se utiliza para llevar la cuenta de las llamadas aprocedimientos y de los parámetros que se pasan entre los procedimientos. Por último, asociado a cada proceso hay una serie de atributos que utiliza el sistema operativo para el control del proceso. Estos atributos se recogen en una estructura de datos que se conoce como bloque de control de proceso (Process Control Block, PCB) o descriptor de proceso. A esta colección de programa, datos, pila y atributos se le llama imagen oentorno del proceso.
8.4 El bloque de control de proceso
El bloque de control de proceso es la estructura de datos central y más importante de un sistema operativo. Cada bloque de control de proceso contiene toda la información de un proceso que necesita un sistema operativo para su control. Estos bloques son leídos y/o modificados por casi todos los módulos de un sistema operativo, incluyendo aquellos que tienen que ver con la planificación, la asignación de recursos, el tratamiento deinterrupciones y el análisis y supervisión del rendimiento. Puede decirse que el conjunto de los bloques de control de procesos definen el estado del sistema operativo. El conjunto de todos los PCB’s se guarda en una estructura del sistema operativo llamada tabla de procesos, la cual se puede implementar como un vector o un lista enlazada. La tabla de procesos reside en memoria principal, debido a su alta frecuencia de consulta.
En un sistema de multiprogramación, se requiere una gran cantidad de información de cada proceso para su administración. Sistemas distintos organizarán esta información de modo diferente. En general, se puede agrupar la información de los PCB’s en tres categorías:
Identificación del proceso.
Información del estado del procesador.
Información de control del proceso.
Con respecto a la identificación del proceso, en casi todos los sistemas operativos se le asigna a cada proceso un identificador numérico único (ID). Este identificador nos servirá para localizarlo dentro de la tabla de procesos. Cuando se permite que los procesos creen otros procesos, se utilizan identificadores para señalar al padre y a los descendientes de cada proceso. Además de estos, un proceso también puede tener asignado un identificador de usuario que indica a quién pertenece el proceso (UID).
El siguiente conjunto de información es la información de estado del procesador. Básicamente, está formada por el contenido de los registros del procesador. Por supuesto, mientras el proceso está ejecutándose, la información está en los registros. Cuando se interrumpe el proceso, toda la información de los registros debe salvarse de forma que pueda restaurarse cuando el proceso reanude su ejecución. La naturaleza y número de registros involucrados depende del diseño del procesador. Normalmente, en el conjunto de registros se incluyen los registros visibles para el usuario, los registros de control y de estado (contador de programa y palabra de estado) y los punteros a pila.
A la tercera categoría general de información del bloque de control de proceso se le podría llamar información de control del proceso. Esta es la información adicional necesaria para que el sistema operativo controle y coordine los diferentes procesos activos. Como, por ejemplo, información de planificación y estado (estado del proceso, su prioridad, información de planificación, suceso), apuntadores(punteros) a estructuras de datos (los procesos que esperan en un semáforo), punteros a zonas de memoria del proceso, recursos controlados por el proceso (ficheros abiertos), etc.
Así pues, el PCB es la entidad que define un proceso en el sistema operativo. Dado que los PCB necesitan ser manejados con eficiencia por el sistema operativo, muchos ordenadores tienen un registro hardware que siempre apunta hacia el PCB del proceso que se está ejecutando. A menudo existen instrucciones hardware que cargan en el PCB información sobre su entorno, y la recuperan con rapidez.
Operaciones con procesos
Los sistemas que administran procesos deben ser capaces de realizar ciertas operaciones sobre y con los procesos. Tales operaciones incluyen:
crear y destruir un proceso
suspender y reanudar un proceso
cambiar la prioridad de un proceso
bloquear y "desbloquear" un proceso
planificar un proceso (asignarle la CPU)
permitir que un proceso se comunique con otro (a esto se denomina comunicación entre procesos, y se estudiará en el tema deprocesos concurrentes).
Crear un proceso implica muchas operaciones, tales como:
buscarle un identificador
insertarlo en la tabla de procesos
determinar la prioridad inicial del proceso
crear el PCB
asignar los recursos iniciales al proceso
Un proceso puede crear un nuevo proceso. Si lo hace, el proceso creador se denomina proceso padre, y el proceso creado, proceso hijo. Sólo se necesita un padre para crear un hijo. Tal creación origina una estructura jerárquica de procesos, en la cual cada hijo tiene sólo un padre, pero un padre puede tener muchos hijos. En el sistema operativo UNIX la llamada al sistema ‘fork’ crea un proceso hijo.
Destruir un proceso implica eliminarlo del sistema. Se le borra de las tablas o listas del sistema, sus recursos se devuelven al sistema y su PCB se borra (es decir, el espacio de memoria ocupado por su PCB se devuelve al espacio de memoria disponible). La destrucción de un proceso es más difícil cuando éste ha creado otros procesos. En algunos sistemas un proceso hijo se destruye automáticamente cuando su padre es destruido; en otros sistemas, los procesos creados son independientes de su padre y la destrucción de este último no tiene efecto sobre sus hijos.
Un proceso suspendido o bloqueado no puede proseguir sino hasta que lo reanuda otro proceso. La suspensión es una operación importante, y ha sido puesta en práctica de diferentes formas en diversos sistemas. La suspensión dura por lo normal sólo periodos breves. Muchas veces, el sistema efectúa las suspensiones para eliminar temporalmente ciertos procesos, y así reducir la carga del sistema durante una situación de carga máxima. Cuando hay suspensiones largas se debe liberar los recursos del proceso. La decisión de liberar o no los recursos depende mucho de la naturaleza de cada recurso. La memoria principal debe ser liberada de inmediato cuando se suspenda un proceso; una unidad de cinta puede ser retenida brevemente por un proceso suspendido, pero debe ser liberada si el proceso se suspende por un periodo largo o indefinido. Reanudar (o activar) un proceso implica reiniciarlo a partir del punto en el que se suspendió.
Cambiar la prioridad de un proceso normalmente no implica más que modificar el valor de la prioridad en el PCB.
Suspensión y reanudación
Algunas líneas más arriba se presentaron los conceptos de suspensión y reanudación de un proceso. Estas operaciones son importantes por diversas razones.
Si un sistema está funcionando mal, y es probable que falle, se puede suspender los procesos activos para reanudarlos cuando se haya corregido el problema.
Un usuario que desconfíe de los resultados parciales de un proceso puede suspenderlo (en lugar de abortarlo) hasta que verifique si el proceso funciona correctamente o no.
Algunos procesos se pueden suspender como respuesta a las fluctuaciones (bajas y altas) a corto plazo de la carga del sistema, y reanudarse cuando las cargas vuelvan a niveles normales.
Interpretación de la figura. Como podemos observar en esta figura tenemos una serie de transiciones posibles entre estados de proceso, representados mediante una gama de colores. Estos colores hay que interpretarlos de forma que, el color del borde de los estados representa a dichos estados, los colores dentro de los circulos nos dicen las posibles alternativas de acceso hacia otro estado, y los colores de las flechas nos representan hacia que estado nos dirigimos si seguimos la misma.
Figura 3.1. Transiciones de estado de los procesos.
La figura 3.1 muestra el diagrama de transiciones de estado de los procesos, modificado para incluir las operaciones de suspensión y reanudación. Se han añadido dos estados nuevos, denominados suspendido_listo y suspendido_bloqueado; no hay necesidad de un estado suspendido_en_ejecución. El rango de procesos en el azul mantiene los estados activos, y debajo tenemos los estados suspendidos.
Una suspensión puede ser iniciada por el propio proceso o por otro. En un sistema con un sólo procesador, el proceso en ejecución puede suspenderse a sí mismo; ningún otro proceso podría estar en ejecución al mismo tiempo para realizar la suspensión (aunque otro proceso sí podría solicitar la suspensión cuando se ejecute). En un sistema de múltiples procesadores, un proceso en ejecución puede suspender a otro que se esté ejecutando en ese mismo momento en un procesador diferente.
Solamente otro proceso puede suspender un proceso listo. Un proceso puede hacer que otro proceso que se encuentre en el estado suspendido_listo pase al estado listo. Un proceso puede suspender a otro proceso que esté bloqueado, y hacerlo pasar de suspendido_bloqueado a bloqueado. Se podría alegar que en lugar de suspender un proceso bloqueado, sería mejor esperar hasta que ocurriera el evento que esperaba; entonces el proceso podría suspenderse y pasarse al estado suspendido_listo. Por desgracia, puede ser que nunca ocurra el evento o que se postergue indefinidamente. Así pues, el diseñador debe decidir si realiza la suspensión del proceso bloqueado o establece un mecanismo mediante el cual se realice la suspensión desde el estado listo cuando ocurra la finalización de la operación. Como la suspensión es, por lo normal, una actividad de alta prioridad, se debe realizar de inmediato. Cuando ocurre finalmente el evento, el proceso suspendido_bloqueado pasa a suspendido_listo.
En el tema de planificación y de gestión de memoria se analiza la forma en que el sistema operativo utiliza las operaciones de suspensión y reanudación para equilibrar la carga del sistema.
8.5 control de un proceso
8.5.1 Modos de Ejecución
Antes de continuar la discusión sobre la forma en que el sistema operativo gestiona los procesos, hace falta distinguir entre el modo de ejecución del procesador que normalmente se asocia con el sistema operativo y el modo que normalmente se asocia con los programas de usuario. Ciertasinstrucciones máquina pueden ejecutarse sólo en modo privilegiado. Entre éstas están la lectura o modificación de registros de control (como lapalabra de estado), instrucciones primitivas de E/S e instrucciones relativas a la gestión de memoria. Y solamente se puede acceder a ciertas zonas de memoria en el modo privilegiado. El modo de menor privilegio se conoce como modo usuario, y el de mayor privilegio como modo de sistema, supervisor o núcleo.
La razón por la que se usan dos modos debe quedar clara. Es necesario proteger al sistema operativo y a las estructuras de datos importantes, tales como los bloques de control de procesos, de las inferencias de los programas de usuario. En el modo núcleo o privilegiado, el software tiene control completo del procesador y de todas las instrucciones, registros y memoria.
Surgen dos preguntas: ¿cómo conoce el procesador en qué modo va a ejecutar?, ¿cómo se cambia de modo? Para la primera pregunta, hay un bit en la PSW( palabra de estado ), que indica el modo de ejecución. El bit se cambia como respuesta a ciertos sucesos tales como una llamada al sistema y, así, se cambia de modo.
8.5.2 Cambio de Proceso
A primera vista, la función de cambio de proceso parece sencilla. En cierto momento, un proceso que se está ejecutando se interrumpe, el sistema operativo pone a otro proceso en el estado de ejecución y pasa el control a dicho proceso. Sin embargo, surgen diversas cuestiones de diseño. En primer lugar, ¿qué sucesos provocan un cambio de proceso? Otra cuestión es que se debe hacer una distinción entre cambio de contexto y cambio de proceso. Por último, ¿qué debe hacer el sistema operativo con las diferentes estructuras de datos bajo su control para llevar a cabo un cambio de proceso?
¿Qué eventos provocan el cambio de proceso?
Un cambio de proceso puede suceder en cualquier instante en el que el sistema operativo gana el control de la CPU.
En primer lugar, se van a tener en cuenta las interrupciones del sistema. Se pueden distinguir dos clases de interrupciones del sistema. La primera es originada por algún tipo de suceso que es externo e independiente del proceso que se está ejecutando, como la culminación de una E/S. La segunda tiene que ver con una condición de error o excepción generada dentro del proceso que se está ejecutando, como un intento ilegal de acceso a un fichero, una división entre cero, una instrucción máquina con código de operación no contemplado. En una interrupción ordinaria, el control se transfiere primero al gestor de interrupciones, quien lleva a cabo algunas tareas básicas y, después, se salta a la rutina del sistema operativo que se ocupa del tipo de interrupción que se ha producido. Algunos ejemplos de estas interrupciones son:
Interrupción de reloj: Un reloj es un dispositivo que genera interrupciones periódicamente. Ante una interrupción de este tipo, un sistema operativo de tiempo compartido, entre otras cosas, determina si el proceso en ejecución ha alcanzado el máximo tiempo de ejecución que se le concedió. Si es así, el proceso pasará a estado listo, y se asignará la CPU a otro proceso.
Interrupción de E/S: El sistema operativo determina exactamente qué acción de E/S ha ocurrido. Si se trata de un evento o suceso por el que esperaban uno o más procesos, entonces el sistema operativo traslada todos los procesos bloqueados en dicho evento al estado listo, y determina (dependiendo de la política de planificación, que se verá en el próximo tema) si reanuda la ejecución del proceso interrumpido o pasa a otro de mayor prioridad.
Falta de memoria: Un proceso hace una referencia a una dirección que no se encuentra en memoria y que debe traerse de memoria secundaria (esta posibilidad se estudiará en el módulo de gestión de la memoria). Después de hacer la solicitud de E/S para traer esa o esas direcciones de memoria, el sistema operativo lleva a cabo un cambio de contexto (próximo apartado) para reanudar la ejecución de otro proceso; el proceso que cometió la falta de memoria se pasa al estado bloqueado. Después de que las direcciones aludidas se carguen en memoria, dicho proceso se pondrá en estado listo.
En una interrupción del segundo tipo, el sistema operativo determina si el error es fatal. Si lo es, el proceso que se estaba ejecutando es eliminado, y se produce un cambio de proceso. Si no es fatal, la acción del sistema operativo dependerá de la naturaleza del error y del diseño del sistema operativo. Se puede hacer un cambio de proceso o, simplemente, reanudar el mismo proceso que se estaba ejecutando.
Finalmente, el sistema operativo puede activarse mediante una llamada al sistema desde el programa que se está ejecutando. Por ejemplo, está ejecutándose un proceso de usuario y se llega a una instrucción que solicita una operación de E/S, tal como abrir un fichero. Esta llamada provoca la transferencia a una rutina que forma parte del código del sistema operativo. Por lo general (aunque no siempre) el uso de una llamada al sistema hace que el proceso de usuario pase al estado bloqueado.
8.5.3 Cambio de Contexto
Si existe una interrupción pendiente es necesario:
Salvar el contexto (PC, registros del procesador, información de la pila) del programa en ejecución.
Poner en el PC la dirección del programa de tratamiento de la interrupción, que suele constar de unas pocas tareas básicas.
Una pregunta que puede plantearse es: ¿qué es lo que constituye el contexto que se debe salvar? La respuesta es que se debe incluir información que pueda ser necesaria para reanudar el programa interrumpido. Así pues, debe guardarse la parte del bloque de control del proceso denominada información de estado del procesador. Esto incluye al contador de programa, otros registros del procesador y la información de la pila.
¿Se tiene que hacer algo más? Ello dependerá de lo que ocurra a continuación. La rutina de tratamiento de la interrupción es normalmente un programa corto que lleva a cabo unas pocas tareas básicas relacionadas con una interrupción. Por ejemplo, se marca el indicador que señala la presencia de una interrupción, puede enviar un acuse de recibo a la entidad que produjo la interrupción (como un módulo de E/S) y puede hacer algunas tareas básicas relacionadas con los efectos del suceso que causó la interrupción. Por ejemplo, si la interrupción está relacionada con un suceso de E/S, el gestor de interrupciones comprobará condiciones de error. Si se ha producido un error, la rutina de tratamiento puede enviar una señal al proceso que solicitó originalmente la operación de E/S.
¿Hay que hacer algo más? Pues depende de si la interrupción va a venir seguida de un cambio de proceso o no. La ocurrencia de una interrupción no siemprecausa el cambio de proceso. Es posible que después de que el gestor de interrupciones se haya ejecutado, el proceso que estaba ejecutándose reanude su ejecución. En tal caso, tan sólo hay que guardar la información de estado del procesador y restaurarla para que pueda reanudarse correctamente el proceso interrumpido (estas funciones son realizadas en hardware).
Por tanto, el cambio de contexto es un concepto distinto al cambio de un proceso. Puede ocurrir un cambio de contexto sin cambiar el estado del proceso que está actualmente en estado de ejecución. En tal caso, salvar el contexto y restaurarlo posteriormente involucra un pequeño coste extra. Sin embargo, si el proceso que estaba ejecutándose tiene que pasar a otro estado (listo o bloqueado), el sistema operativo tiene que llevar a cabo cambios substanciales en su entorno( contexto ). Los pasos involucrados en un cambio completo de proceso son los siguientes:
1.Salvar el contexto del procesador, incluyendo el contador de programa y otros registros.
2.Actualizar el PCB que estaba en estado de ejecución. Esto implica cambiar el estado del proceso a alguno de los otros estados (listo, bloqueado, suspendido_listo). También se tienen que actualizar otros campos, como uno en el que se guarde la razón por la que se abandona el estado de ejecución y otros con información de contabilidad.
3.Mover el PCB a la cola apropiada (listos, bloqueados por el suceso i, suspendido_listo).
4.Seleccionar otro proceso para ejecución (como veremos en el tema de Planificación de Procesos).
5.Actualizar el PCB seleccionado. Cambiar, por ejemplo, su estado a ‘en ejecución’.
6.Actualizar las estructuras de datos de gestión de la memoria. Esto puede hacer falta dependiendo de cómo se gestione la traducción de direcciones (lo dejaremos para los temas sobre memoria).Restaurar el contexto del procesador a aquél que existía en el momento en el que el proceso seleccionado dejó por última vez el estado de en ejecución, cargando los valores previos del contador de programa y de otros registros.
Así pues, el cambio de proceso, que implica un cambio de contexto, requiere un esfuerzo considerablemente superior al de un cambio de contexto.
8.6 Procesos y Threads
El concepto de proceso es más complejo y sutil que el presentado hasta ahora. Engloba dos conceptos separados y potencialmente independientes: uno relativo a la propiedad de recursos y otro que hace referencia a la ejecución.
Unidad que posee recursos: A un proceso se le asigna un espacio de memoria y, de tanto en tanto, se le puede asignar otros recursos como dispositivos de E/S o ficheros.
Unidad a la que se le asigna el procesador: Un proceso es un flujo de ejecución (una traza) a través de uno o más programas. Esta ejecución se entremezcla con la de otros procesos. De tal forma, que un proceso tiene un estado (en ejecución, listo, etc) y una prioridad de expedición u origen. La unidad planificada y expedida por el sistema operativo es el proceso.
En la mayoría de los sistemas operativos, estas dos características son, de hecho, la esencia de un proceso. Sin embargo, son independientes, y pueden ser tratadas como tales por el sistema operativo. Esta distinción ha conducido en los sistemas operativos actuales a desarrollar la construcción conocida como thread, cuyas traducciones más frecuentes son hilo, hebra y proceso ligero. Si se tiene esta división de características, la unidad de asignación de la CPU se conoce como hilo, mientras que a la unidad que posee recursos se le llama proceso.
Dentro de un proceso puede haber uno o más hilos de control cada uno con:
Un estado de ejecución (en ejecución, listo, bloqueado).
Un contexto de procesador, que se salva cuando no esté ejecutándose.
Una pila de ejecución.
Algún almacenamiento estático para variables locales.
Acceso a la memoria y a los recursos de ese trabajo que comparte con los otros hilos.
Los beneficios clave de los hilos se derivan de las implicaciones del rendimiento: se tarda menos tiempo en crear un nuevo hilo de un proceso que ya existe, en terminarlo, y en hacer un cambio de contexto entre hilos de un mismo proceso. Al someter a un mismo proceso a varios flujos de ejecución se mantiene una única copia en memoria del código, y no varias.
Un ejemplo de aplicación que podría hacer uso de los hilos es un servidor de ficheros de una red de área local. Cada vez que llega una solicitud de una operación sobre un fichero, se puede generar un nuevo hilo para su gestión. El servidor gestiona multitud de solicitudes, por tanto, se pueden crear y destruir muchos hilos en poco tiempo para dar servicio a estas
9.1 Comunicación y Sincronización de Procesos
Puede verse la concurrencia de procesos como la ejecución simultánea de varios procesos. Si tenemos un multiprocesador o un sistema distribuido(tema 1) la concurrencia parece clara, en un momento dado cada procesador ejecuta un proceso. Se puede ampliar el concepto de concurrencia si entendemos por procesado concurrente (o procesado paralelo) la circunstancia en la que de tomar una instantánea del sistema en conjunto, varios procesos se vean en un estado intermedio entre su estado inicial y final. Esta última definición incluye los sistemas multiprogramadosde un único procesador que estudiamos en los temas anteriores.
Los distintos procesos dentro de un ordenador no actúan de forma aislada. Por un lado, algunos procesos cooperan para lograr un objetivo común. Por otro lado, los procesos compiten por el uso de unos recursos limitados, como el procesador, la memoria o los ficheros. Estas dos actividades de cooperación y competición llevan asociada la necesidad de algún tipo de comunicación entre los procesos. Parte de este tema lo dedicaremos a estudiar mecanismos de comunicación entre los procesos.
Para aclarar un poco todo esto, supongamos que en un entorno UNIX se ejecuta la orden
cat tema1 tema2 tema3 | wc -l
Esta orden va a provocar que el intérprete de órdenes cree dos procesos concurrentes, el primero ejecutará el programa cat, que concatenará el contenido de los ficheros de texto tema1, tema2 y tema3. El segundo ejecutará el programa wc, que contará el número de líneas de la salida producida por cat. Estos dos procesos cooperan, y será preciso algún tipo de sincronización entre ellos, concretamente hasta que cat no produzca alguna salida wc debería bloquearse.
9.1.1 Cooperación entre Procesos
La velocidad de un proceso con respecto a otro es impredecible ya que depende de la frecuencia de la interrupción asociada a cada uno de ellos y cuán a menudo y de por cuánto tiempo tiene asignado cada proceso un procesador. Diremos, pues, que un proceso se ejecuta asíncronamente con respecto a otro, es decir, sus ejecuciones son independientes. Sin embargo, hay ciertos instantes en lo que los procesos deben sincronizar sus actividades. Son estos puntos a partir de los cuales un proceso no puede progresar hasta que otro haya completado algún tipo de actividad.
Los procesos también necesitan comunicarse entre sí. Por ejemplo, para leer de un fichero, los procesos de usuario deben decir al proceso que gestiona los ficheros lo que desean. Este, a su vez, debe pedirle al proceso de disco que lea los bloques necesarios. Cuando el shell conecta dos procesos con un tubo, los datos de salida del primer proceso se transfieren al segundo. Se necesita que los procesos se comuniquen entre sí, con un mecanismo bien estructurado y no por medio de interrupciones.
9.1.2 Competencia entre los procesos
Los recursos de un sistema pueden clasificarse como compartibles, lo que significa que pueden ser utilizados por varios procesos de forma concurrente, o no compartibles, lo que equivale a que su uso se restrinja a un sólo proceso a la vez. El hecho de que un recurso no sea compartible deriva de una de las dos razones siguientes:
La naturaleza física del recurso hace que sea imposible compartirlo. Un ejemplo lo constituye una impresora, si una impresora fuera utilizada por varios procesos simultáneamente sus salidas se entremezclarían en el papel.
El recurso es tal que si es usado por varios procesos de forma concurrente la acción de uno de ellos puede interferir con la de otro. Un ejemplo común lo constituye un fichero que contiene unos datos accesibles desde más de un proceso, y modificables al menos por uno de ellos. Por ejemplo, supongamos un fichero que contiene registros con la siguiente información sobre una cuenta bancaria:
CLAVE SALDO
Supongamos también dos procesos que se ejecutan concurrentemente y que actualizan una misma cuenta, el proceso P1 añade al saldo el valor de la nómina y el proceso P2 descuenta del saldo una factura domiciliada. El código de los procesos es el siguiente:
El resultado final de la ejecución de los dos procesos debería actualizar el saldo añadiéndole la nómina, y descontándole la factura. Sin embargo, la secuencia de ejecución en el procesador de las instrucciones a1b1b2b3a2a3, que puede darse debido a un cambio de proceso, hace que no se descuente la factura.
Dentro de la categoría de recursos no compartibles se incluirán la mayoría de los periféricos (los discos no), los ficheros de escritura y las zonas de memoria sujetas a modificación. Los recursos compartibles incluirán la CPU (en los temas previos vimos cómo compartir la CPU entre los procesos introduciendo el concepto de PCB), los ficheros de lectura, y las zonas de memoria que contengan rutinas puras o bien datos que no están sujetos a modificación.
9.1.3 Requisitos para la Exclusión Mutua
Los recursos no compartibles, ya sean periféricos, ficheros, o datos en memoria, pueden protegerse del acceso simultáneo por parte de varios procesos evitando que éstos ejecuten de forma concurrente sus fragmentos de código a través de los cuales llevan a cabo este acceso. Estos trozos de código reciben el nombre de secciones o regiones críticas, pudiéndose asimilar el concepto de exclusión mutua en el uso de estos recursos a la idea de exclusión mutua en la ejecución de las secciones críticas. Así, por ejemplo, puede implementarse la exclusión mutua de varios procesos en el acceso a una tabla de datos mediante el recurso de que todas las rutinas que lean o actualicen la tabla se escriban como secciones críticas, de forma que sólo pueda ejecutarse una de ellas a la vez. En el ejemplo previo de la cuenta bancaria los fragmentos de códigoa1a2a3 y b1b2b3 constituyen dos secciones críticas mutuamente excluyentes, esto significa que una vez que se ha comenzado la ejecución de una sección crítica, no se puede entrar en otra sección crítica mutuamente excluyente.
Idear soluciones que garanticen la exclusión mutua es uno de los problemas fundamentales de la programación concurrente. Muchas son las alternativas y tipos de mecanismos que se pueden adoptar. A lo largo de este tema veremos diferentes soluciones software y alguna hardware ; unas serán sencillas y otras complejas, algunas requieren la cooperación voluntaria de los procesos y otras que exigen un estricto ajuste a rígidos protocolos. La selección de las operaciones primitivas adecuadas para garantizar la exclusión mutua de las secciones críticas es una decisión primordial en el diseño de un sistema operativo. Al menos, una solución apropiada debería cumplir las cuatro condiciones siguientes:
1. Que no haya en ningún momento dos procesos dentro de sus respectivas secciones críticas.
2. Que no hagan suposiciones a priori sobre las velocidades relativas de los procesos o el número de procesadores disponibles.
3. Que ningún proceso que esté fuera de su sección crítica pueda bloquear a otros.
4. Que ningún proceso tenga que esperar un intervalo de tiempo arbitrariamente grande para entrar en su sección crítica.
9.2 Utilizando Memoria Compartida
A partir de aquí, iremos haciendo un estudio progresivo sobre las posibles soluciones de todo tipo que intentarán resolver la exclusión mutua y el sincronismo entre procesos. Muchas de estas soluciones fracasarán en su intento. Otras lo lograrán, pero mostrarán ciertas deficiencias que nos llevarán a pensar en nuevas primitivas de concurrencia.
Nuestro viaje comenzará con las soluciones que utilizan memoria compartida. Dentro de este grupo, distinguiremos entre mecanismos software y hardware que emplean espera ocupada, y los que usan espera bloqueada (semáforos y monitores).
9.2.1 Soluciones Software al Problema de la Exclusión Mutua
En esta sección se van a estudiar varios métodos que intentan resolver el problema de la ejecución en exclusión mutua de las secciones críticas de los procesos. En primer lugar, introduciremos algunos métodos que no producen una solución aceptable, sin embargo, nos ayudarán a comprender mejor el problema.
Desactivación de las interrupciones
La solución más sencilla es que cada proceso prohiba todas las interrupciones justo antes de entrar en su región crítica y las permita de nuevo justo antes de salir. Esto funciona correctamente, pues el código del sistema operativo sólo se activa como consecuencia de la ocurrencia de interrupciones. Si el sistema operativo no puede ejecutarse mientras se ejecuta la sección crítica, es obvio que no podrá realizar un cambio de proceso en la CPU, por lo tanto, la sección crítica se ejecutará en exclusión con todo proceso.
Pero con las interrupciones prohibidas no se servirá ni la interrupción de reloj ni ninguna otra. Dado que la asignación del procesador a los diferentes procesos sólo cambia como consecuencia de una interrupción, sea de reloj o de cualquier otra clase, el prohibir interrupciones hace que no pueda conmutarse el procesador a otro proceso.
Esta solución es poco atrayente porque le da a los procesos de usuario la capacidad de prohibir las interrupciones. Si no las vuelve a habilitar, sería el fin del sistema. Además, si el computador tuviera dos o más procesadores, la desactivación de las interrupciones sólo afectaría al procesador que ejecutó la instrucción. El resto de los procesadores continuarían normalmente y podrían acceder a la memoria compartida sin mayor problema.
Sin embargo, a veces es conveniente que el propio sistema operativo prohiba las interrupciones mientras está actualizando sus variables o listas. La prohibición de interrupciones es un mecanismo adecuado para garantizar la exclusión mutua dentro del núcleo, pero poco recomendable para procesos de usuario.
Variable de cerradura
Analicemos una solución mediante software. Consiste en tener una variable de cerradura compartida por los procesos. Antes de que un proceso entre en su sección crítica comprueba el valor de la cerradura. Si ésta vale 0, el proceso cambia el valor a 1 y entra en la sección crítica. Si ésta ya vale 1, el proceso espera hasta que la variable valga 0. Por lo tanto, un 0 indica que ningún proceso se encuentra en una sección crítica y un 1 indica que algún proceso está en una sección crítica. A continuación se presenta el fragmento del código (en lenguaje C) de un proceso que quiere entrar en una sección crítica. A las instrucciones, relativas a proporcionar la exclusión mutua, que se ejecutan antes de entrar en la sección crítica, se les llama protocolo de entrada; a las que se ejecutan después de ejecutar el código de la sección crítica se les llama protocolo de salida. En este caso el protocolo de entrada lo constituyen la conjunción de las instrucciones while y ‘cerrado = 1'. El protocolo de salida lo conforma la instrucción ‘cerrado = 0'.
Esta solución no funciona. Suponga que un proceso lee la cerradura y comprueba que tiene un valor 0. Antes de que pueda ponerla a 1 se planifica otro proceso. Éste comprueba el valor de cerrado, al ser 0 entra en su sección crítica. Si antes de que este proceso termine la sección crítica se vuelve a planificar al primer proceso no se habrá logrado la exclusión mutua. El problema proviene de que el protocolo de entrada es una sección crítica más, pues se dedica a modificar una variable compartida (la variable cerrado). Obsérvese que si el protocolo de entrada se pudiera ejecutar sin cambios de proceso la solución sería efectiva.
Algunos intentos para especificar el código de las primitivas de exclusión mutua
Acabamos de ver cómo el uso de una variable de cerradura fracasa en su intento. Analicemos otras posibles soluciones software. Necesitamos unas primitivas de exclusión mutua que protejan el acceso a las secciones críticas. Utilizaremos el siguiente esquema general (figura 4.2) : tendremos una pareja de construcciones entrar_exclusión_mutua y salir_exclusión_mutua que encapsulan el código de cada proceso que tiene acceso a la variable compartida. La construcción parbegin/parend hace que proceso_uno y proceso_dos operen como procesos concurrentes. Cada uno de estos procesos se encuentra dentro de un ciclo infinito, entrando una y otra vez en sus secciones críticas.
Fig 4.2. Esquema general del uso de primitivas de exclusión mutua.
Primera tentativa
La variable compartida número_proceso, con un valor inicial 1, mantiene un registro del turno para entrar en la sección crítica. El Proceso_uno ejecuta el ciclo while do. Como en un principio número_proceso vale 1, proceso_uno entra en la sección crítica. Proceso_dos encuentra que número_proceso equivale a 1 y se mantiene dentro de su ciclo while do. Cada vez que el proceso_dos obtiene el procesador, se limita a repetir el ciclo en espera de que número_proceso valga 2, de manera que proceso_dos no entra en su sección crítica y la exclusión mutua está garantizada. El procesador está en uso mientras proceso_dos no hace nada (excepto verificar el valor de número_proceso), esto se conoce como espera ocupada o activa. La espera activa se considera una técnica aceptable cuando las esperas anticipadas son cortas; de lo contrario, la espera activa puede resultar costosa.
La exclusión mutua está garantizada, pero a un precio alto. Los procesos deben entrar y salir de su sección crítica de manera estrictamente alterna. Si un proceso es más corto que otro, la velocidad de uno de ellos condicionará al otro. Si uno de los procesos termina, el otro no podrá continuar. Esta primera solución utiliza una variable global, y ella ocasiona el problema de la sincronización con alternancia estricta.
Fig 4.3 Primera versión de las primitivas de exclusión mutua.
Segunda Tentativa
Por ello, en la segunda versión se usan dos variables: p1dentro, que es cierta si el proceso uno está en su sección crítica y, p2dentro, que también será cierta si el proceso dos está en su sección crítica.
P1 y P2 son concurrentes e intentarán entrar simultáneamente en su sección crítica. No está garantizada la exclusión mutua. El problema se debe a que, entre el momento en que un proceso determina que puede seguir y el momento en que se asigna cierto a su bandera ( variable centinela), hay tiempo suficiente para que el otro verifique su bandera y entre en su sección crítica.
Por tanto, en el momento en que realiza su verificación deberá estar seguro de que el otro proceso no podrá pasar su verificación.
Fig 4.4. Segunda versión de las primitivas de exclusión mutua.
Tercera Tentativa
Ahora cambiamos la bandera antes de realizar la verificación, indicando su deseo de ejecutar la sección crítica. Se puede producir un bloqueo mutuo, los dos procesos entrarán en un ciclo infinito. Esto se debe a que cada uno de los procesos se puede bloquear en su verificación.
Fig 4.5. Tercera versión de las primitivas de exclusión mutua.
Cuarta Tentativa
En la anterior versión quedábamos atrapados en la verificación, por tanto, ahora intentaremos escapar de ella. Una manera de hacerlo es retardando la verificación, para comprobar si el otro también desea entrar. La exclusión mutua está garantizada y no ocurre bloqueo mutuo, pero puede ocurrir un aplazamiento indefinido. Un aplazamiento indefinido o inanición es una situación en la que se posterga indefinidamente el progreso en la ejecución de uno o más procesos. Veamos cómo puede suceder: puesto que no podemos hacer suposiciones sobre sus velocidades podría suceder que se ejecutasen en tándem, esto es, uno ejecuta una instrucción y el otro, a continuación, la correspondiente. Luego, cada proceso puede asignar el valor cierto a su bandera, realizar la verificación, entrar en el cuerpo del 'ciclo while', asignar el valor falso a su bandera, asignar el valor cierto a su bandera y después repetir la secuencia comenzando con la verificación (esto no se puede consentir para ciertas aplicaciones que deben ejecutar en un tiempo concreto como el software de control de vuelo, un marcapasos o un sistema de control de tráfico aéreo...).
Fig 4.6. Cuarta versión de las primitivas de exclusión mutua.
Algoritmo de Dekker
Gestiona elegantemente la exclusión mutua. Utiliza, además de las banderas de intención de entrar, una variable turno (proceso_favorecido) que resuelve en caso de conflicto. Da la posibilidad de que el otro proceso entre en su sección crítica una segunda vez si lo hace antes que el proceso que acaba de dejar el bucle de espera, asigne el valor cierto a su intención de entrar. Pero cuando de nuevo tiene el procesador, realiza la asignación y es su turno, así que se ejecuta. En consecuencia, no produce aplazamiento indefinido (figura 4.7).
Fig 4.7. Algoritmo de Dekker
Algoritmo de Peterson
Simplifica el algoritmo de Dekker. El protocolo de entrada es más elegante con las mismas garantías de exclusión mutua, imposibilidad de bloqueo mutuo y de aplazamiento indefinido.
Fig 4.8 Algoritmo de Peterson
9.2.2 Soluciones hardware a la exclusión mutua
Se estudia ahora una solución que requiere apoyo del hardware. Muchos ordenadores, en particular aquellos diseñados teniendo en mente varios procesadores, tienen una instrucción TEST AND SET LOCK (TSL). Esta instrucción máquina provoca la lectura del contenido de una palabra de la memoria en un registro, y el almacenamiento de un valor distinto de cero en dicha palabra de memoria. Al ser una instrucción máquina, las operaciones de lectura y escritura de la palabra tienen la garantía de ser indivisibles (atómicas). Además, ninguno de los demás procesadores puede tener acceso a la palabra hasta terminar la instrucción. El procesador que ejecuta la instrucción TSL cierra el bus de la memoria para prohibir a los demás el acceso a la memoria hasta el término de la instrucción.
A continuación se muestra una solución al problema de la exclusión mutua que se basa en la instrucción TSL. La solución viene expresada en un lenguaje ensamblador ficticio (pero típico). Existen dos subrutinas que los procesos llamarán como protocolos de entrada y salida:
La variable cerrado es una variable compartida que se utiliza para coordinar el acceso a las secciones críticas. Cuando vale 0 se permite el acceso y cuando vale 1 no. Cuando un proceso quiera entrar a una sección crítica llamará a la subrutina entrar_sección. Esta subrutina estará ejecutando un ciclo hasta que cerrado valga 0. Obsérvese que esta solución funciona, mientras que la solución de la variable cerradura no funcionaba. La clave está en que la instrucción TSL realiza atómicamente el comprobar que cerrado vale 0 y el asignarle el valor 1.
Fig 5.8. Instrucción TSL
9.3 Sin Utilizar Memoria Compartida. Mensajes
Los monitores y los semáforos se diseñaron para resolver problemas de sincronización en un sistema mono o multiprocesador, es decir, un sistema con una o varias CPU's que tienen acceso a una memoria compartida. La comunicación se logra compartiendo una zona de memoria donde los procesos guardan información, los semáforos y monitores se utilizan para sincronizar el acceso a dicha zona. Si pasamos a un sistema distribuido, con varias CPU's, cada una con su memoria privada, unidas mediante una red, estos mecanismos de comunicación entre procesos ya no se pueden aplicar. Además, estos dos mecanismos sirven para la sincronización, pero no para el intercambio de información entre procesos. En el siguiente apartado veremos un mecanismo que solventa ambos problemas.
Transferencia de mensajes
Este mecanismo de comunicación entre procesos se basa en dos primitivas: send y receive, las cuales, al igual que los semáforos, y a diferencia de los monitores, son servicios (llamadas al sistema) proporcionados por el sistema operativo. Los lenguajes de programación tendrán rutinas de biblioteca para invocar tales servicios desde un programa. Dichas rutinas de biblioteca tendrán un formato parecido al siguiente:
send(mensaje, destino) ,y
receive(mensaje, origen)
La primera función envía un mensaje a un destino dado, y la segunda recibe un mensaje desde cierto origen (o desde cualquier origen, si al receptor no le importa el origen).
Los sistemas operativos suelen implementar dos tipos de comunicación basadas en transferencia de mensajes: la directa y la indirecta. El comportamiento de los procesos en cuanto a la sincronización es distinto en los dos tipos de comunicación. A continuación se exponen ambos.
Transferencia de mensajes con designación directa
En este sistema, tanto el proceso emisor como el proceso receptor deben especificar explícitamente el proceso destino y origen respectivamente. Las funciones tendrá un formato similar al siguiente:
send(mensaje, identificador proceso destino)
receive(mensaje, identificador proceso origen)
En cuanto a la sincronización, viene determinada por la ausencia de un lugar donde almacenar el mensaje. Si se ejecuta send antes de receive en el proceso destino, el proceso emisor se bloquea hasta la ejecución de receive, momento en el cual el mensaje se puede copiar de manera directa desde el emisor al receptor sin almacenamiento intermedio. Análogamente, si se ejecuta primero receive, el receptor se bloquea hasta que se ejecute una operación send en el proceso emisor. Este modo de sincronización se conoce como cita (rendezvous).
Transferencia de mensajes con designación indirecta
En este sistema, los mensajes se envían o reciben de unos objetos proporcionados por el sistema operativo denominados buzones. Un buzón es un lugar donde almacenar un número determinado de mensajes, la cantidad de mensajes que alberga el buzón se especifica al crearlo. Al utilizar buzones, los parámetros de dirección en las llamadas send y receive son buzones, y no procesos:
send(mensaje, buzón)
receive(mensaje, buzón)
El sistema operativo debe proporcionar servicios para la creación y destrucción de buzones, así como para la especificación de los usuarios y/o procesos que pueden utilizar un buzón.
En cuanto a la sincronización, un proceso que haga una operación send sobre un buzón, sólo se bloquea si dicho buzón está lleno. Un proceso que realice una operación receive sobre un buzón, sólo se bloquea si el buzón está vacío, es decir, no contiene mensajes.
Los sistemas de transferencia de mensajes con designación directa son más fáciles de implementar. Sin embargo, son menos flexibles, puesto que el emisor y el receptor deben estar ejecutándose simultáneamente. Si se utilizan buzones, el emisor puede almacenar sus mensajes en un buzón, pudiendo el receptor recuperarlos posteriormente.
Ejemplos de utilización de transferencia de mensajes
En este apartado vamos a ver cómo resolver los problemas de la exclusión mutua y de los productores y consumidores utilizando transferencia de mensajes con designación indirecta. En el apartado de Comunicación y Sincronización se emplea la designación directa para crear una aplicación cliente-servidor.
Exclusión mutua
Se necesita un proceso de inicialización, en el que se crea el buzón exmut con un tamaño de un mensaje, y tamaño de mensaje de un byte. A continuación se llena el buzón (el contenido del mensaje, el carácter '*', no es relevante). Para realizar la exclusión mutua en la sección crítica del proceso Pi se tiene en cuenta que la operación receive es indivisible, y representa un bloqueo potencial si el buzón está vacío. Obsérvese que la solución es análoga a la realizada mediante semáforos. En aquella se definía un semáforo de valor incial 1, representando este valor la ausencia de procesos dentro de una sección crítica. El cero representaba el que un proceso estaba en una sección crítica. En esta solución, se define un buzón de tamaño 1, la existencia de un mensaje en ese buzón significa la no existencia de procesos en una sección crítica. La ausencia de mensajes en el buzón implica que un proceso está en una sección crítica.
Productores y consumidores
Para la solución se crean dos buzones de tamaño N (longitud del buffer). El tamaño de un mensaje es sizeof(int), sizeof es una macro de C que sirve para calcular el número de bytes que ocupa el tipo de dato que representa su único parámetro (en este caso un entero). En el buzón esp habrá tantos mensajes (de valor insustancial 0) como espacios haya en el buzón ele. La información almacenada en el buzón ele sí es importante, son los elementos producidos por los productores.
Llamadas a procedimientos remotos
La noción de llamadas a procedimientos remotos (remote procedure calls, RPC) se introdujo con el objeto de ofrecer un mecanismo estructurado de alto nivel para realizar la comunicación entre procesos en sistemas distribuidos. Con una llamada a un procedimiento remoto, un proceso de un sistema puede llamar a un procedimiento de un proceso de otro sistema. El proceso que llama se bloquea esperando el retorno desde el procedimiento llamado en el sistema remoto y después continúa su ejecución desde el punto que sigue a la llamada.
El procedimiento llamado y el que llama residen en máquinas distintas, con espacios de direcciones distintos, no existe la noción de variables globales compartidas, como en los procedimientos normales dentro de un proceso. Las RPC transfieren la información a través de parámetros de la llamada. Una RPC se puede realizar con los mecanismo del tipo enviar/recibir.
send(proceso_remoto,parámetros_entrada);
receive(proceso_remoto, parámetros_salida);
Una llamada a procedimiento remoto debería ser igual a una llamada a un procedimiento local, desde el punto de vista del usuario. Una llamada por valor es más fácil enviando copias de los datos mediante mensajes. Las llamadas por referencia son más difíciles, porque una RPC cruza a otro espacio de direcciones. Los formatos internos de los datos pueden cambiar en una red de máquinas heterogéneas; requieren conversiones complejas y un considerable trabajo adicional. Deben tenerse en cuenta la posibilidad de transmisiones defectuosas y la pérdida de mensajes en la red.
9.4 Problemas Clásicos de Comunicación entre Procesos
9.4.1 El problema de la cena de los filósofos
En 1965 Dijkstra planteó y resolvió un problema de sincronización llamado el problema de la cena de los filósofos, que se puede enunciar como sigue. Cinco filósofos se sientan a la mesa, cada uno con un plato de espaghetti. El espaghetti es tan escurridizo que un filósofo necesita dos tenedores para comerlo. Entre cada dos platos hay un tenedor. En la figura 4.15 se muestra la mesa.
Fig 4.15. Los filósofos se disponen a comer
La vida de un filósofo consta de periodos alternos de comer y pensar. Cuando un filósofo tiene hambre, intenta obtener un tenedor para su mano derecha, y otro para su mano izquierda, cogiendo uno a la vez y en cualquier orden. Si logra obtener los dos tenedores, come un rato y después deja los tenedores y continúa pensando. La pregunta clave es: ¿ puede el lector escribir un programa para cada filósofo que permita comer equitativamente a los filósofos y no se interbloquee ?
Figura 4.16. Una no-solución al problema de la cena de los filósofos
La figura 4.16 muestra una solución obvia. El procedimiento coger_tenedor espera hasta que el tenedor especificado esté disponible y lo coge. Por desgracia la solución obvia es incorrecta. Supongamos que los cinco filósofos cogen sus tenedores izquierdos de forma simultánea. Ninguno podría coger su tenedor derecho, lo que produciría un interbloqueo.
Se podría modificar el programa de forma que después de coger el tenedor izquierdo, el programa verificara si el tenedor derecho está disponible. Si no lo está, el filósofo deja el izquierdo, espera cierto tiempo y vuelve a repetir el proceso. Esta propuesta también falla, aunque por razones distintas. Con un poco de mala suerte todos los filósofos podrían empezar el algoritmo de forma simultánea, por lo que cogerían sus tenedores izquierdos, verían que los derechos no están disponibles, esperarían, volverían a coger sus tenedores izquierdos simultáneamente, etc. eternamente. Esto implica un aplazamiento indefinido.
Figura 4.17. Una solución al problema de la cena de los filósofos
El lector podría pensar: "si los filósofos esperaran un tiempo arbitrario, en vez del mismo tiempo, después de que no pudieran coger el tenedor derecho, la probabilidad de que todo quedara bloqueado, incluso una hora, sería muy pequeña". Esta observación es correcta, pero en ciertas aplicaciones se desea una solución que funcione siempre, y no que pueda funcionar bien con gran probabilidad. (Piense en el control de seguridad de una planta nuclear).
Una mejora a la figura 4.16, que no tiene interbloqueos ni aplazamiento indefinido, es la protección de los cinco enunciados siguientes a la llamada al procedimiento pensar mediante un semáforo binario exmut. Antes de empezar a coger los tenedores, un filósofo haría un wait sobre exmut. Desde el punto de vista teórico esta solución es adecuada. Desde el punto de vista práctico presenta un error de eficiencia: en todo instante existirá a lo sumo un filósofo comiendo. Si se dispone de cinco tenedores, se debería permitir que dos filósofos comieran al mismo tiempo.
La solución que aparece en la figura 4.17 es correcta, y permite el máximo paralelismo para un número arbitrario de filósofos. Utiliza un vector,estado, para llevar un registro de la actividad de un filósofo: si está comiento, pensando o hambriento (estado que indica que quiere coger los tenedores). Un filósofo puede comer únicamente si los vecinos no están comiendo. Los vecinos del i-ésimo filósofo se definen en las macros IZQ yDER. En otras palabras, si i= 2, entonces IZQ = 1, y DER = 3.
El programa utiliza un vector de semáforos, uno por filósofo, de forma que los filósofos hambrientos puedan bloquearse si los tenedores necesarios están ocupados. Observe que cada proceso ejecuta el procedimiento filósofo como programa principal, pero los demás procedimientos,coger_tenedores, dejar_tenedores y prueba, son procedimientos ordinarios y no procesos separados.
9.4.2 El problema de los lectores y los escritores
El problema de la cena de los filósofos es útil para modelar procesos que compiten por el acceso exclusivo a un número limitado de recursos, como una unidad de cinta u otro dispositivo de E/S. Otro problema famoso es el de los lectores y escritores (Courtois et al., 1971), que modela el acceso a una base de datos. Supóngase una base de datos, con muchos procesos que compiten por leer y escribir en ella. Se puede permitir que varios procesos lean de la base de datos al mismo tiempo, pero si uno de los procesos está escribiendo (es decir, modificando) la base de datos, ninguno de los demás debería tener acceso a ésta, ni siquiera los lectores. La pregunta es ¿ cómo programaría los lectores y escritores ? La solución se muestra en la figura 4.18.
En esta solución, el primer lector que obtiene el acceso a la base de datos realiza un wait sobre el semáforo bd. Los lectores siguientes sólo incrementan un contador, nl. Al salir los lectores, éstos decrementan el contador, y el último en salir realiza un signal sobre el semáforo, lo que permite entrar a un escritor bloqueado, si existe.
Una hipótesis implícita en esta solución es que los lectores tienen prioridad sobre los escritores. Si surge un escritor mientras varios lectores se encuentran en la base de datos el escritor debe esperar. Pero si aparecen nuevos lectores, y queda al menos un lector accediendo a la base de datos, el escritor deberá esperar hasta que no haya más lectores interesados en la base de datos.
Figura 4.18. Una solución al problema de los lectores y escritores
9.5 Un ejemplo de aplicación cliente-servidor
En este apéndice vamos a ver cómo se pueden utilizar las primitivas de mensajes con designación directa proporcionadas por el sistema operativo para crear un servidor de ficheros, y un cliente que solicita sus servicios para copiar un fichero. Previamente se muestra cómo se puede realizar un programa que copie un fichero en un sistema en el que las operaciones con ficheros las proporciona el sistema operativo, y no un proceso de usuario como será el servidor de ficheros.
Comencemos estudiando cómo realizar un programa sencillo en C para MS DOS que copia un fichero fuente a un fichero destino. El listado del programa es el siguiente:
El programa tiene una funcionalidad mínima y un informe de los errores raquítico. El programa copyfile se puede llamar, por ejemplo, mediante la línea de órdenes:
para copiar el fichero abc a xyz. Si xyz ya existe, se escribe sobre él. En caso contrario, se crea. El programa debe invocarse con dos argumentos, dados por dos nombres válidos de ficheros.
Los enunciados #include hacen que un gran número de definiciones y prototipos de funciones se incluyan en el programa. La línea siguiente es un prototipo de función para main, necesario para ANSI C.
El enunciado #define es una definición de macro para la cadena BUF_SIZE, el cual se expande en el número 4096. El programa leerá y escribirá en bloques de 4096 bytes.
El programa principal se llama main y tiene dos argumentos, argc y argv. Estos son proporcionados por el sistema operativo cuando se llama al programa. El primer argumento indica el número de palabras presentes en la línea de órdenes, que debe ser tres. El segundo es un vector de punterosa los argumentos. En este ejemplo de llamada los elementos de este vector contienen punteros a los valores siguientes:
argv[0] = "copyfile"
argv[1] = "abc"
argv[2] = "xyz"
Mediante esta vía el programa tiene acceso a sus argumentos.
Se declaran cinco variables. Las dos primeras, src y dst, contienen los descriptores de fichero, son enteros pequeños asignados al abrir un fichero. Las dos siguientes, in y out son los contadores de bytes devueltos por las llamadas al sistema READ y WRITE respectivamente. La última, buf, es elbuffer utilizado para almacenar los datos leídos, y proporcionar los datos a escribir.
La primera instrucción condicional verifica si argc = 3. Si no es así, se termina el programa con código de estado 1. Por convención, un código de estado distinto de 0 indica la aparición de un error. El código de estado es el único informe de error presente en este programa. Una versión comercial mostraría también mensajes de error.
Después se intenta abrir el fichero fuente y crear el fichero destino. Si el fichero fuente se puede abrir, el sistema asigna un entero pequeño a src, para identificación del fichero. Las llamadas al sistema posteriores deben incluir este entero, de forma que el sistema operativo sepa con qué fichero se desea trabajar. Análogamente, si se puede crear el destino, se le da un valor a dst para identificarlo. Si la apertura o la creación fallan, el descriptor correspondiente toma el valor -1, y el programa termina con un código de error.
Después viene el ciclo de copiado, el cual comienza leyendo los datos en bloques de 4K hacia buf. Esto se realiza mediante la función de bibliotecaread, la cual utiliza la llamada al sistema READ. El primer parámetro especifica el fichero, el segundo el buffer, y el tercero el número de bytes a leer. La función read devuelve el número de bytes leídos (esto se guarda en in). Por lo general, este número es 4096, excepto en el caso de que en el fichero queden por leer menos de esos bytes. Cuando se llega al final del fichero, dicho número es 0. Si in es 0 o negativo, la copia no puede continuar, por lo que se ejecuta el enunciado break para finalizar el ciclo (que de otro modo continuaría de forma indefinida).
La llamada a write hace que el contenido del buffer pase al fichero destino. El primer parámetro identifica al fichero, el segundo al buffer, y el tercero indica el número de bytes a escribir, de forma análoga a read. Observe que el número de bytes que realmente se leen está dado por el contador de bytes, y no por BUF_SIZE. Esto es importante, puesto que el último buffer no será de tamaño 4096, a menos que el fichero tenga una longitud múltiplo de 4K.
Después de procesar todo el fichero, la siguiente llamada hace in = 0, con lo que se sale del ciclo. En este punto, se cierran los dos ficheros, y el programa finaliza con un código que indica su conclusión normal.
El ejemplo cliente servidor
En este punto se presenta una visión general de un servidor de ficheros, y un cliente que solicita sus servicios para copiar un fichero. Ambos programas están escritos en C. El cliente y el servidor deben compartir algunas definiciones, éstas se reunen en el fichero header.h, que se muestra en la figura 4.19. Tanto el cliente como el servidor lo incluyen mediante el uso del enunciado:
#include
Analizaremos primero header.h. Empieza con la definición de dos constantes, MAX_PATH y BUF_SIZE, las cuales determinan el tamaño de dos vectores necesarios en el mensaje. El primero indica el número de caracteres máximo que puede tener una trayectoria de fichero (como /etc/passwd). El segundo fija la cantidad de datos que se pueden leer o escribir en una operación, al establecer el tamaño del buffer. La constante siguiente,FILE_SERVER, proporciona la dirección en la red del servidor de ficheros, de forma que los clientes le puedan mandar mensajes.
Figura 4.19. El fichero header.h que utilizan el cliente y el servidor.
El segundo grupo de constantes define los números de operación, necesarios para garantizar que el cliente y el servidor estén de acuerdo en el código que representará una operación. Aquí sólo se muestran cuatro, en un sistema real lo normal es que sean más.
Toda respuesta contiene un código de resultado. Si la operación tiene éxito, es frecuente que este código contenga información útil (como el número de bytes que se leen en realidad). Si no existe un valor por devolver (como cuando se crea un fichero), se emplea el valor OK. Si por alguna razón la operación fracasa, el código de resultado indica por qué, mediante códigos tales como E_BAD_OPCODE, E_BAD_PARAM, etc.
Por último llegamos a la parte más importante de header.h, la definición del propio mensaje. En nuestro ejemplo, es una estructura o registro de 10 campos. Todas las solicitudes del cliente al servidor utilizan este formato, al igual que lo hacen las respuestas. En un sistema real tal vez no se tenga un formato fijo (puesto que no se necesitan los campos en todos los casos), pero esto hace más sencilla la explicación. Los campos source y destidentifican al emisor y al receptor respectivamente. El campo opcode es una de las operaciones definidas antes; es decir, CREATE, READ, WRITE oDELETE. Los campos count y offset se utilizan como parámetros, y otros dos campos, extra1 y extra2, se definen para disponer de un espacio adicional en el caso de que el servidor se modifique posteriormente. El campo result no se utiliza en las solicitudes del cliente al servidor, se utiliza para devolver un resultado en las respuestas del servidor al cliente. Por último, tenemos dos vectores. El primero, name, contiene la trayectoria del fichero al que se accede. El segundo, data, almacena los datos que se envían de vuelta como respuesta a un READ, o los datos que se envían al servidor en un WRITE.
Analicemos ahora el código de la figura A.20. En a) tenemos el servidor; en b) el cliente. El servidor es directo. El ciclo principal comienza con una llamada a receive para obtener un mensaje de solicitud. El primer parámetro identifica a quién hizo la llamada, mediante su dirección, el segundo apunta a un buffer de mensajes donde se guarda el mensaje que llegará. El procedimiento de biblioteca receive realiza una llamada al sistema para que se bloquee el servidor hasta que llegue un mensaje. Cuando llega una, el servidor se desbloquea y se encarga del tipo de opcode. Para cada opcode se llama a un procedimiento distinto. Se dan como parámetros el mensaje de entrada y un buffer para el mensaje de salida. El procedimiento examina el mensaje de entrada, m1, y construye la respuesta en m2. También devuelve el valor del resultado en el campo result. Después de terminar send, el servidor vuelve a la parte superior del ciclo para ejecutar receive y esperar a que llegue el siguiente mensaje.
En la figura 4.20 b) se ve un procedimiento para copiar un fichero utilizando el servidor. Su cuerpo consta de un ciclo que lee un bloque del fichero fuente y lo escribe en el fichero destino. El ciclo se repite hasta copiar todo el fichero fuente, lo cual se indica mediante un código de retorno de lectura nulo o negativo.
La primera parte del ciclo se encarga de construir un mensaje para la operación READ y enviarla al servidor. Después de recibir la respuesta, se entra en la segunda parte del ciclo, que toma los datos recién recibidos y los envía de vuelta al servidor en un WRITE al fichero destino. Los programas de la figura 4.20 son únicamente un bosquejo del código. Se han omitido muchos detalles. Por ejemplo, no se muestran los procedimientos do_xxx y no se realiza una verificación de los errores. Aún así, debe quedar clara la idea de la interacción del cliente y el servidor.
Fig 4.20 .Ejemplo Cliente_Servidor.
Del código del servidor se deduce que solamente puede atender a una petición a la vez. Si el servicio de una petición es muy lento, porque, por ejemplo, precisa realizar entradas/salidas, se pueden demorar las solicitudes de otros clientes. Una solución, en un sistema operativo que posea el concepto de hilo, es que el servidor al aceptar una petición cree un hilo para que la sirva, siendo éste el responsable de contestar al cliente. Así se pueden atender varias solicitudes concurrentemente, un hilo pueden aprovechar las E/S de los otros hilos para ejecutar su código. Hay que decir que algunos sistemas operativos no permiten la creación dinámica (en tiempo de ejecución) de hilos, y de estar permitida existe un máximo de hilos por proceso. Si la creación es estática (en tiempo de compilación), se pueden crear, por ejemplo, 5 hilos, y que cada uno reciba una solicitud, la tramite y responda a ella.
En este apartado, y en los dos siguientes, vamos a exponer tres ejemplos clásicos de
sincronización entre procesos, proponiendo su solución utilizando semáforos. El problema de los productores y los consumidores ejemplifica la sincronización de varios procesos "productores" y "consumidores", los procesos de un grupo controlan tanto el progreso de los procesos de su grupo como los del otro grupo.
Especifiquemos el problema. Un conjunto de procesos "productores" y un conjunto de procesos "consumidores" se comunican entre sí a través de unbuffer, en el que los productores van depositando elementos, y del cual, los consumidores los van sacando. Los productores llevan a cabo de forma continua un ciclo "producir un elemento - guardar el elemento en el buffer", y los consumidores repiten un ciclo parecido: "sacar un elemento del buffer- consumir el elemento". Un productor típico puede ser un proceso de tipo computacional que vaya colocando líneas de resultados en un buffer, mientras que el consumidor correspondiente puede ser el proceso que imprime estas líneas. El buffer tiene una capacidad limitada, pudiendo almacenar sólo N elementos del mismo tamaño. La sincronización que se requiere en este caso es doble: en primer lugar, los productores no pueden colocar elementos en el buffer si éste está lleno, y en segundo lugar, los consumidores no pueden sacar elementos del buffer si éste está vacío.
Además, el buffer y las variables compartidas deben protegerse del acceso concurrente por parte de los distintos procesos, pues son zonas compartidas de memoria modificables por los procesos. De ahí que el acceso al buffer y a las variables compartidas se realice en exclusión mutua.
La solución que se presenta utiliza un buffer circular, cuyos elementos son enteros, dos variables compartidas, que controlan dónde insertar o sacar elementos del buffer, y tres semáforos. Los programas se expresan en un lenguaje similar a C.
La sincronización se logra mediante los semáforos espacio y elementos, la exclusión mutua mediante el semáforo exmut. El operador % realiza la operación módulo (resto de la división entera).
10.0 INTERBLOQUEOS
10.1 Definiciones Previas
Cuando un proceso de un sistema de multiprogramación espera en balde a que se presente un evento específico, se dice que se encuentra en un estado de interbloqueo o bloqueo mutuo. Los procesos que pueden encontrase en esta situación pueden ser uno o varios.
En los sistemas de multiprogramación, compartir recursos es uno de los principales objetivos del sistema operativo. Cuando se comparten recursos entre una población de usuarios o procesos, cada uno de los cuales mantiene un control exclusivo sobre ciertos recursos asignados a él, es posible que se produzcan bloqueos mutuos que impedirán la terminación de algunos de los procesos del sistema.
Todos los interbloqueos suponen demandas contradictorias de recursos por parte de dos o más procesos. La figura 5.1 ilustra este conflicto de forma abstracta en el caso de dos procesos y dos recursos. Los dos ejes del diagrama representan el avance de los dos procesos en términos de instrucciones ejecutadas. El avance conjunto de los dos procesos se representa entonces con una secuencia discreta de puntos en el espacio. Las líneas horizontales o verticales representan el intervalo de tiempo en el que sólo uno de los procesos está ejecutándose (intercalado); una línea diagonal significa ejecución simultánea (solapamiento). Supóngase que existe un punto en la ejecución de cada proceso en el que se requiere el uso exclusivo de ambos recursos, R1 y R2, para continuar. En el ejemplo, llega un punto en el que el proceso P1 ha adquirido el recurso R1 y el proceso P2 ha adquirido el recurso R2, y cada proceso necesita el otro recurso. Este es el punto de interbloqueo.
En este tema se analizará el problema del interbloqueo y las distintas alternativas de solución que se pueden adoptar clasificadas en las siguientes cuatro áreas : prevención, evitación, detección y recuperación del bloqueo mutuo. Para cada una de las estrategias adoptadas, se analizará el equilibrio entre la sobrecarga debida a los mecanismos de corrección del interbloqueo y los beneficios que reportan. En algunos casos es excesivo el precio (gasto extra) que hay que pagar para conseguir a toda costa que no se produzcan interbloqueos. Sin embargo, en algunos casos, como en los sistemas de tiempo real, no hay más alternativa que pagar el precio, ya que puede resultar catastrófico permitir la posibilidad de un bloqueo mutuo.
Un problema afín : el aplazamiento indefinido
En cualquier sistema que mantenga los procesos en espera mientras se les asigna un recurso o se toman decisiones de planificación, la programación de un proceso puede postergarse indefinidamente mientras otro recibe la atención del sistema. Tal situación se conoce con varios nombres, entre los que se incluyen aplazamiento indefinido, bloqueo indefinido e inanición, y puede resultar tan peligrosa como el interbloqueo.
El aplazamiento indefinido puede ocurrir debido a predisposiciones en las políticas de planificación de recursos del sistema. Cuando los recursos se planifican por prioridad, es posible que un proceso dado espere de forma indefinida un recurso porque siguen llegando otros procesos con mayor prioridad. Los sistemas deben diseñarse para administrar los procesos en espera de manera justa además de eficiente. En algunos sistemas, el aplazamiento indefinido se evita aumentando la prioridad del proceso mientras espera (técnica de envejecimiento). En algún momento la prioridad de ese proceso superará la prioridad de los entrantes y el proceso en espera será atendido.
10.2 Casos de Interbloqueos
El caso más simple de interbloqueo sería el de un sólo proceso que espera la ocurrencia de un evento y, sin embargo, el sistema no incluye la posibilidad de señalar dicha ocurrencia. Es muy difícil detectar los bloqueos mutuos de esta naturaleza. La mayor parte de los bloqueos mutuos implican una competencia entre varios procesos por varios recursos.
Holt (1972) utilizó grafos dirigidos para representar situaciones de interbloqueo. Estos grafos tienen dos tipos de nodos : procesos, que se representan con círculos, y recursos, representados por cuadrados. Si in proceso está utilizando un recurso, previamente solicitado y concedido, se traza un arco desde el nodo del recurso (cuadrado) hasta el proceso (círculo). En la figura 2, el recurso R está en ese momento asignado al proceso A. En b), el proceso B está solicitando el recurso s. Por último en c) se representa un situación de interbloqueo : el proceso C está a la espera del recurso T, que está asignado al proceso D. El proceso D no ha dejado T, porque está esperando a que quede libre el recurso U, que, a su vez, está siendo utilizado por C. Ambos esperarán indefinidamente.
El siguiente ejemplo servirá para ilustrar el empleo de grafos de recursos. Supongamos que tenemos tres procesos, A, B y C, y tres recursos, R, S, y T. La figura 5.2 representa las secuencias de petición y liberación que realizan los tres procesos. El sistema operativo tiene en todo momento completa libertad para ejecutar cualquiera de los procesos que no estén bloqueados, así que, por ejemplo, podría decidirse a ejecutar A hasta que éste terminara su trabajo, después B hasta que acabe y, finalmente C.
Este secuenciamiento no produce interbloqueo, ( ya que no se compite por los recursos), pero suprime completamente el paralelismo. Además de pedir y liberar recursos, los procesos también realizan E/S y procesamiento de datos. Si se ejecutan uno tras otro, se elimina completamente la posibilidad de que, mientras uno de ellos está esperando que acabe una E/S, otro pueda utilizar el procesador.
Supongamos, sin embargo, que los procesos realizan tanto E/S como procesamiento de datos, de forma que la planificación por turno rotatorio es la más adecuada. En este caso, la secuencia de petición de recursos podría ser la representada en la figura 3 (d). Si las seis peticiones se llevan a cabo en ese orden, se producirían los seis grafos de los casos (e)-(j). Después de la petición 4, A está bloqueado en espera de captar S, como se muestra en (h). Los procesos B y C se bloquean en las dos etapas siguientes, lo que conduce finalmente a un bucle cerrado y al correspondiente interbloqueo representado en (j).
Figura 5.3 Ejemplo de Interbloqueo y como evitarlo.
El sistema operativo no está obligado a ejecutar los procesos en ningún orden en particular. En concreto, si la concesión de un recurso a un proceso determinado puede provocar interbloqueo, el sistema operativo es muy libre de suspender al proceso y no atender su petición hasta que esté seguro de que esto no conduce a una situación problemática. En la figura 5.3, por ejemplo, si el sistema operativo supiera que se avecinaba un interbloqueo, podría decidir suspender al proceso B antes de concederle el recurso S. La ejecución sólo de los procesos A y C produciría las secuencias de petición y liberación de la figura 5.3 (k), en lugar de las de la figura 5.3 (d). Esta secuencia de ejecución produce los grafos de recursos (l)-(q), y no produce interbloqueo.
Después de la etapa (q), no hay ningún problema en conceder S a B, ya que A ha terminado y C tiene todo lo que necesita. Aunque B se bloqueara al solicitar T, no se produciría interbloqueo; B simplemente esperaría hasta que terminara C.
10.3 Condiciones Necesarias para Producir un Interbloqueo
Coffman, Elphick y Shoshani (71) establecen que deben darse las siguientes cuatro condiciones necesarias para que ocurra un bloqueo mutuo.
Condición de exclusión mutua : los procesos exigen un control exclusivo de los recursos que necesitan.
Condición de espera : los procesos mantienen la posesión de los recursos ya asignados a ellos mientras esperan recursos adicionales.
Condición de no apropiación : los recursos no pueden arrebatarse a los procesos a los cuales están asignados hasta que termine su utilización.
Condición de espera circular : existe una cadena circular de procesos en la que cada proceso tiene uno o más recursos que son requeridos por el siguiente proceso en la cadena.
Como dichas condiciones son necesarias para que se presente un interbloqueo, la existencia de un bloqueo mutuo implica que se han dado todas y cada una de las cuatro condiciones. Como se verá más adelante, tener en mente semejante observación será de gran ayuda para desarrollar esquemas que eviten los interbloqueos.
10.4 Estrategias para Resolver Interbloqueos
Los resultados de la investigación sobre el bloqueo mutuo han sido satisfactorios en cuanto a que se han encontrado métodos limpios y rápidos para manejar la mayoría de los problemas más comunes. Existen cuatro áreas de interés relacionadas con los interbloqueos que pueden resumirse como prevención, técnicas para evitarlos, detección y recuperación de los mismos.
En la prevención del interbloqueo interesa ajustar el sistema para eliminar toda posibilidad de que ocurra un bloqueo mutuo. La prevención suele funcionar pero sus métodos ocasionan, en general, un aprovechamiento pobre de los recursos. No obstante, estos métodos se utilizan con frecuencia.
Las técnicas que tienen como objetivo evitar el interbloqueo imponen condiciones menos atractivas que en la prevención, para tratar de obtener un aprovechamiento de los recursos. No elimina como las técnicas de prevención todas las posibilidades de que se produzca un bloqueo mutuo, pero se esquiva cuanto está a punto de suceder (algoritmo del banquero de Dijkstra).
Los métodos de detección del interbloqueo es utilizan en sistemas que permiten la ocurrencia de los mismos, ya sea de manera voluntaria o involuntaria. Su objetivo es determinar si ha ocurrido un bloqueo mutuo y saber exactamente cuáles son los procesos y recursos implicados en él.
Los métodos de recuperación están íntimamente ligados a los de detección. Sirven para eliminar los interbloqueos detectados en un sistema para poder seguir trabajando y para que los procesos implicados puedan terminar su ejecución y liberen sus recursos. La recuperación es un problema complejo, en el mejor de los casos, los sistemas se recuperan de un bloqueo mutuo eliminando completamente uno o varios de los procesos implicados. Después, se inician de nuevo los procesos eliminados, perdiéndose la mayor parte o todo el trabajo previo realizado por el proceso.
10.4.1 Desentenderse. El Algoritmo de la Avestruz
La estrategia más sencilla es el algoritmo del avestruz : esconder la cabeza bajo tierra y pretender que el problema no existe. La gente reacciona a esta estrategia de distintos modos según su formación. Los matemáticos consideran que es inaceptable y argumentan que los interbloqueos se deben evitar a toda costa. Los ingenieros se interrogan sobre la frecuencia del problema, la frecuencia con el que el sistema se para por otras causas y la importancia de los interbloqueos. Si éstos se presentan de una vez cada cinco años, y los sistemas se paran una vez al mes por errores en el hardware, en elcompilador o en el sistema operativo, a casi ningún ingeniero le gustaría tener que sufrir una degradación seria de las prestaciones del sistema para garantizar la eliminación de los interbloqueos.
Por ejemplo, Unix pude sufrir interbloqueos que ni siquiera se detectan, y que, por supuesto, no se eliminan automáticamente. El número total de procesos en el sistema viene determinado por el número de posiciones de la tabla de procesos, que, en definitiva, constituye un recurso limitado. Supongamos ahora que un sistema Unix con 100 posiciones en la tabla de procesos tiene ejecutándose diez programas, cada uno de los cuales ha de crear 12 subprocesos. Después de que cada proceso haya creado otros 9, los 10 procesos originales y los 90 nuevos llenarán por completo la tabla. Los 10 procesos originales se encontrarán ahora en un bucle infinito intentando crear un nuevo proceso sin poder : se ha producido un interbloqueo. Otros ejemplos de recursos que suelen ser limitados son : el número máximo de ficheros que pueden estar abiertos está limitado, el área en el disco para intercambio con memoria principal. En realidad, casi todas las tablas del sistema operativo representan recursos limitados, ¿deberíamos, por tanto, limitar estos recursos para no producir un interbloqueo?
La estrategia UNIX es simplemente desentenderse del problema, suponiendo que la mayoría de los usuarios preferirán un interbloqueo ocasional antes que la imposición de que cada usuario pueda crear un solo proceso, abrir un solo fichero y usar sólo una unidad de lo que sea. Veremos a continuación que se puede adoptar alguna estrategia adecuada que nos permitirá prevenir, evitar o detectar y recuperar situaciones de interbloqueo.
10.4.2 Prevención de Interbloqueos
La estrategia empleada con más frecuencia por los diseñadores para tratar el bloqueo mutuo es la prevención. En esta sección se examinan los métodos de prevención, junto con los efectos que tienen sobre los usuarios y los sistemas, sobre todo desde la perspectiva del rendimiento.
Havender (68) llegó a la conclusión de que si falta alguna de las cuatro condiciones necesarias no puede haber un interbloqueo. Este autor sugiere las siguientes estrategias para negar varias de esas condiciones :
Cada proceso deberá pedir todos sus recursos al mismo tiempo y no podrá seguir la ejecución hasta haberlos recibido todos.
Si a un proceso que tiene recursos se le niegan los demás, ese proceso deberá liberar sus recursos y, en caso necesario, pedirlos de nuevo junto con los recursos adicionales.
Se impondrá un ordenamiento lineal de los tipos de recursos en todos los procesos ; es decir, si a un proceso le han sido asignados recursos de un tipo específico, en lo sucesivo sólo podrá pedir aquellos recursos que siguen en el ordenamiento.
Como vemos Havender presenta tres estrategias y no cuatro. Cada una de ellas, está diseñada para negar una de las condiciones necesarias. La primera de estas condiciones, esto es, que los procesos exijan el uso exclusivo de los recursos que requieren, es una condición que no es deseable impedir, porque específicamente queremos permitir la existencia de recursos no compartibles o dedicados.
Negación de la condición de espera
La primera de las estrategias requiere que los recursos que necesita un proceso sean pedidos de una sola vez. El sistema debe proporcionarlos según el principio de todo o nada. Si está disponible el conjunto de los recursos que necesita un proceso, entonces el sistema puede asignarle todos los recursos y éste seguir su ejecución. Si no está disponible alguno de ellos, el proceso debe esperar. Mientras espera no puede tener ningún recurso. Con esto se elimina la condición de espera y no puede ocurrir un interbloqueo.
Todo esto suena bien, pero puede llevar a un grave desperdicio de recursos. Supongamos que un proceso necesita diez unidades de un determinado recurso para su ejecución. Como debe solicitarlas todas antes de comenzar, los mantendrá en su poder durante toda su ejecución. Pudiera suceder, que el programa únicamente utilice estos recursos al principio de su ejecución, por tanto, los recursos están ociosos el resto del tiempo.
Dividir el programa en varios pasos que se ejecuten de manera relativamente independiente es una técnica empleada con frecuencia para conseguir una mejor utilización de los recursos en estas circunstancias. La asignación de recursos se controla por etapas. Esta solución reduce el desperdicio pero implica mucho trabajo extra tanto en el diseño de las aplicaciones como en al ejecución.
Por otro lado, esta estrategia puede provocar un aplazamiento indefinido, pues los recursos requeridos pueden no estar disponibles todos al tiempo. El sistema podría, entonces, permitir que se fueran acumulando recursos hasta conseguir todos los que necesita un proceso. Pero mientras se acumulan no se pueden asignar a otros procesos y volvemos a infrautilizarlos.
Negación de la condición de no apropiación
La segunda estrategia de Havender consiste en liberar los recursos que un proceso tiene asignados cuando se le niegan peticiones de recursos adicionales. De esta forma, se anula la condición de no apropiación. Los recursos se pueden quitar al proceso que los tiene antes de que termine su ejecución.
En este caso también existe un costo excesivo. Cuando un proceso libera recursos puede perder todo el trabajo realizado hasta ese momento. El costo puede parecer muy alto, pero la pregunta es : ¿con qué frecuencia ha de pagarse ese precio ? Si ocurre de tarde en tarde, entonces éste parece ser un buen método para prevenir el interbloqueo. Si, por el contrario, es muy frecuente, entonces el costo es sustancial y sus efectos demasiado perjudiciales (por ejemplo, para procesos de alta prioridad o plazo fijo).
Esta estrategia también adolece de aplazamiento indefinido. Un proceso puede aplazarse continuamente mientras pide y libera muchas veces los mismo recursos. Si esto ocurre, el sistema puede verse obligado a eliminar el proceso para que otros puedan ejecutarse.
Negación de la condición de espera circular
La tercera estrategia de Havender anula la posibilidad de un espera circular. Como todos los recursos tienen una numeración única y como los procesos deben pedir los recursos en un orden lineal ascendente, es imposible que se presente una espera circular (figura 5.4). Esta estrategia presenta las siguientes dificultades :
Los recursos deben pedirse en un orden ascendente por número de recursos. El número de recurso es asignado por la instalación y debe tener un tiempo de vida largo (meses o años) . Si se agregan nuevos tipos de recursos, puede ser necesario reescribir los programas y los sistemas.
Lógicamente, cuando se asignan los números de recursos, éstos deben reflejar el orden normal en que los usan la mayoría de las tareas. Pero los procesos que necesiten los recursos en un orden diferente que el previsto por el sistema, los deberán adquirir y conservar, quizá durante tiempo antes de utilizarlos realmente, lo que significa un desperdicio considerable.
Una de las metas más importantes de los sistemas operativos actuales es crear ambientes amables con el usuario. Los usuarios deben ser capaces de desarrollar sus aplicaciones sin tener en cuenta molestas restricciones de hardware y software. El ordenamiento lineal impide al usuario escribir sus códigos libremente.
10.4.3 Evitación de Interbloqueos
Aún presentándose las condiciones para un interbloqueo, todavía es posible evitarlo mediante una asignación cuidadosa de los recursos. Tal vez el algoritmo más famoso para evitar el interbloqueo sea el algoritmo del banquero de Dijkstra (73), cuyo interesante nombre se debe a que atañe a un banquero que otorga préstamos y recibe pagos a partir de una determinada fuente de capital.
Algoritmo del Banquero
En principio, estudiaremos este algoritmo suponiendo que todos los recursos del mismo tipo. Considérese la asignación de una cantidad t, de unidades de cintas idénticas.
Un sistema operativo comparte un número fijo, t, de unidades de cinta entre un número fijo de, p, de procesos. Cada proceso especifica por adelantado el número máximo de unidades de cinta que necesitará durante su ejecución. El sistema operativo aceptará la petición de un usuario si la necesidad máxima de ese proceso no es mayor que t. Un proceso puede obtener o liberar unidades de cinta una a una. Algunas veces un usuario puede verse obligado a esperar para obtener una unidad adicional, pero el sistema operativo garantiza una espera finita. El número real de unidades asignadas a un proceso nunca será superior a la necesidad máxima declarada por ese usuario. Si el sistema operativo es capaz de satisfacer la necesidad máxima del proceso, entonces éste debe garantizar al sistema operativo que las unidades de cinta serán utilizadas y liberadas en un tiempo finito.
Se dice que el estado del sistema es seguro si el sistema operativo puede garantizar que todos los procesos terminan en un tiempo finito. En otro caso, el sistema está en un estado inseguro.
Sea préstamo (i) la representación del préstamo actual de unidades de cinta para el proceso i. Sea máx(i) la necesidad máxima de cintas de un proceso y, por último, sea petición (i) la petición actual del usuario, que es igual a su necesidad máxima menos el préstamo actual. Por ejemplo, el proceso 7 tiene una necesidad máxima de 6 unidades y un préstamo actual de 5, entonces tiene
petición(7) = máx(7) - préstamo(7) = 6 - 5 = 2
El sistema operativo controla t unidades de cinta. Sea a el número de unidades de cinta todavía disponibles para asignar. Entonces a es igual a t menos la suma de los préstamos de los usuarios.
El algoritmo del banquero permite la asignación de unidades de cinta a los usuarios solamente cuando la asignación conduzca a estados seguros, y no a estados inseguros. Un estado seguro es una situación tal en la que todos los procesos son capaces de terminar en algún momento. Un estado inseguro es aquel en el cual puede presentarse un bloqueo mutuo.
Ejemplo de estado seguro
Supóngase que un sistema tiene doce unidades de cinta y tres procesos que las comparten.
La tabla anterior representa un estado seguro porque el proceso 2 tiene un préstamo de 4 unidades y necesita como máximo 6, o sea, 2 más. El sistema tiene 12 de las cuales 10 están en uso y mantiene 2 disponibles. Si las que están disponible se asignan al proceso 2, cubriendo su demanda máxima, este proceso podrá terminar. Al acabar, devolverá todos los recursos, 6 unidades de cinta, y el sistema podrá asignarlas al proceso 1 y al 3. De esta forma, la clave de un estado seguro es que exista al menos una forma en la que terminen todos los procesos.
Ejemplo de estado inseguro
Ahora 11 de las 12 unidades de cinta están asignadas y solamente hay una disponible. En este momento, no se puede garantizar que terminen los tres procesos. Si el proceso 1 pide y obtiene la última unidad de cinta y los tres vuelven a solicitar una unidad de cinta más se produciría un bloqueo triple.
Es importante señalar, que un estado inseguro no implica la existencia, ni siquiera eventual, de un interbloqueo. Lo que sí implica un estado inseguro es la posibilidad de que ocurra por una desafortunada secuencia de eventos.
Ejemplo de transición de estado seguro a estado inseguro
Saber que un estado es seguro no implica que serán seguros todos los estados futuros. La política de asignación de recursos debe considerar cuidadosamente todas las peticiones antes de satisfacerlas. Por ejemplo supongamos la situación que se muestra en la siguiente tabla.
Ahora supóngase que el proceso 3 pide un recurso más. Si el sistema satisface esta petición, el nuevo estado será el que se muestra en la tabla de abajo.
Según vemos, aunque, en principio el sistema no estaba bloqueado, ha pasado de un estado seguro a uno inseguro. La última de las tablas caracteriza un sistema en el cual no puede garantizarse la terminación de todos los procesos. Solamente hay un recurso disponible, pero deben estarlo al menos dos para asegurar que el proceso 2 o el 3 puedan terminar, devolver sus recursos al sistema y permitir que los otros procesos acaben.
Algoritmo del banquero para múltiples recursos
Figura 5.5 Algoritmo del banquero para múltiples recursos
La figura 5.5 representa dos matrices. La de la izquierda muestra el número de recursos asignados en ese instante (préstamo actual) a cada uno de los cinco procesos. En la derecha aparece el número de recursos que todavía necesita cada proceso para llevar a cabo su función (petición). Al igual que el caso de un único recurso, los procesos deben comunicar sus necesidades máximas antes de empezar a ejecutarse, de forma que en todo momento el sistema pueda calcular la matriz de la derecha.
Para describir los recursos existentes en el sistema, los que están en posesión y los que están disponibles, emplearemos tres vectores como los siguientes : E =(6342), P=(5322) y D=(1020). E indica que el sistema tiene 6 unidades de cinta, 3 trazadores, 4 impresoras y 2 cdrom. De ellos se están utilizando 5 unidades de cinta, tres trazadores gráficos, dos impresoras y dos cdrom. Esto se puede deducir sin más que sumar las cuatro columnas de recursos en préstamo de la matriz izquierda. El vector de recursos disponibles es simplemente la diferencia ente lo que el sistema tiene y lo que está usando en ese momento.
Ahora estamos en condiciones de describir en qué consiste el algoritmo de comprobación de estado seguro :
1.-Buscar una fila, F, cuyas necesidades de recursos sean menores o iguales a D. Si no existe tal fila, el sistema puede interbloquearse, ya que ningún proceso puede ejecutarse hasta el final.
2.-Suponer que el proceso de la fila seleccionada solicita todos los recursos que necesita, y termina. Marcar el proceso como terminado y añadir sus recursos al vector D.
3.-Repetir las etapas 1 y 2 hasta que se vayan marcando todos los procesos como terminados (en cuyo caso el estado inicial era seguro) o hasta que se llegue a una situación de interbloqueo (en cuyo caso no lo era).
En el caso de que se pueda seleccionar más de un proceso en el paso 1, la elección sería indiferente: en cualquier caso, el conjunto de recursos disponibles aumenta o, en el peor de los casos, se queda igual.
Volviendo al ejemplo de la figura 5.5 . El estado actual es seguro. Supongamos que el proceso B solicita la impresora. Dado que el estado resultante es todavía seguro, esta petición puede concederse (el proceso D puede terminar, seguido por los procesos A o E y a continuación el resto).
Imaginemos ahora que, después de que B obtiene una de las dos impresoras restantes, E solicita la última impresora. Si se le concede esta petición, el vector de recursos disponibles se reduciría a (1 0 0 0), situación que produce interbloqueo. Por lo tanto, la petición de E debe posponerse de momento.
Ahora debe estar claro cómo opera el algoritmo del banquero de Dijkstra cuando asigna recursos. Están permitidas las condiciones de espera circular, espera y no apropiación, pero los procesos sí exigen el uso exclusivo de los recursos que requieren. Los procesos pueden conservar recursos mientras piden y esperan recursos adicionales y los recursos no pueden arrebatarse a los procesos que los tienen. Los procesos facilitan el trabajo al sistema pidiendo un solo recurso a la vez. El sistema puede satisfacer o rechazar cada petición. Si una petición es rechazada, el proceso conserva los recursos que ya tiene asignados y espera un tiempo finito a que se satisfaga la petición. El sistema sólo satisface peticiones que llevan a estados seguros. Una petición que condujese a un estado inseguro se rechazaría repetidamente hasta que pueda quedar satisfecha. Como el sistema se mantiene en un estado seguro, tarde o temprano (en un tiempo finito) todas las peticiones podrán ser atendidas y los procesos terminarán.
Defectos del algoritmo del banquero
El algoritmo del banquero es interesante porque ofrece una forma de asignar los recursos que evita el interbloqueo. Permite ejecutar procesos que tendrían que esperar seguramente con alguna de las estrategias de prevención. Sin embargo, tiene varios defectos importantes :
El algoritmo requiere un número fijo de recursos asignables. Como los recursos a menudo requieren servicio, ya sea por algún fallo o por mantenimiento preventivo, no se puede contar con que será siempre constante.
El algoritmo requiere una población de usuarios constantes. En los sistemas multiprogramables y más en los de tiempo compartido, la población de usuarios cambia constantemente, incluso en cuestión de segundos.
El algoritmo requiere que el banquero satisfaga todas las peticiones en un tiempo finito. Es evidente que en los sistemas reales esto no es una garantía suficiente.
De manera similar, el algoritmo requiere que los procesos salden sus préstamos (es decir, devuelvan sus recursos) en un tiempo finito. Una vez más, esto es insuficiente para un sistema de tiempo real.
El algoritmo requiere que los usuarios declaren por anticipado sus necesidades máximas. A medida que la asignación de recursos se hace más dinámica, conocer las necesidades máximas de un usuario presenta mayor dificultad. De hecho, ahora que los sistemas ofrecen interfaces gráficas, cada vez es más común que los usuarios no tengan la menor idea de los recursos que necesitan.
En resumen, los métodos descritos anteriormente en el apartado de prevención son demasiado restrictivos, mientras que los de evitación que acabas de estudiar requieren información de la que, generalmente, no se dispone.
10.4.4 Detección y Recuperación de Interbloqueos
La detección del bloqueo mutuo es el proceso de determinar si realmente existe un interbloqueo e identificar los procesos y recursos implicados en él. Los algoritmos de detección determinan por lo general si existe una espera circular.
El empleo de algoritmos de detección del interbloqueo implica cierto gasto extra durante la ejecución. Así pues, se presenta de nuevo la cuestión de costeabilidad, tan habitual en los sistemas operativos, ¿el gasto extra debido a los algoritmos de detección del bloqueo mutuo se justifica con los ahorros potenciales debidos a la localización y solución de los interbloqueos?
Para facilitar la detección de interbloqueos, se utilizará una notación en la que un grafo dirigido indica las asignaciones y peticiones de recursos. Los cuadrados representan procesos; los círculos grandes, clases de dispositivos idénticos; los círculos pequeños de color rojo en el interior de los grandes indican el número de dispositivos de cada clase. Por ejemplo, si un círculo grande etiquetado como R1 contiene tres círculos pequeños, significa que ya tres recursos del tipo R1 disponibles para asignación en este sistema.
Figura 5.6 Gráfica de Asignación y Petición de recursos.
La figura 5.6 muestra las relaciones que pueden indicarse en una gráfica de asignación y petición de recursos. Por ejemplo, en (a) el proceso P1 está pidiendo un recurso del tipo R1. La flecha que parte de P1 toca solamente el extremo del círculo grande, lo cual implica que se está estudiando la petición. En (b), el proceso P2 tiene asignado un recurso del tipo R2 (del cual existen dos unidades). La flecha va del círculo pequeño que se encuentra dentro del círculo grande R2 al cuadrado P2. En (c), el recurso R3 ha sido solicitado por el proceso P3, pero ya se ha asignado al proceso P4. Por último, en (d), se representa un interbloqueo. El proceso P5 tiene el recurso R5 que está siendo solicitado por el proceso P6, que tiene el recurso R4 que está siendo solicitado por el proceso P5 (una espera circular).
Reducción de las gráficas de asignación de recursos
Una técnica útil para detectar los interbloqueos consiste en ir reduciendo una gráfica determinando los procesos que pueden completar su ejecución. Si pueden atenderse las peticiones de recursos de un proceso, se dice que la gráfica puede ser reducida por ese proceso. Esta reducción es equivalente a mostrar la gráfica como si el proceso hubiese acabado y hubiera devuelto los recursos al sistema. Si una gráfica puede ser reducida por todos sus procesos, entonces no hay interbloqueo. Si una gráfica no puede ser reducida por todos sus procesos, los procesos irreductibles constituyen el conjunto de procesos en bloqueo mutuo de la gráfica (figura 5.7).
Cuando se ha bloqueado un sistema, el interbloqueo debe romperse mediante la eliminación de una o más de las condiciones necesarias. Por lo general, varios procesos perderán una parte o la totalidad del trabajo efectuado, pero el precio pagado puede ser pequeño, en comparación con las consecuencias de permitir que el sistema siga bloqueado. La recuperación después de un bloqueo mutuo se complica por varias razones :
Puede no estar claro que el sistema se haya bloqueado.
La mayor parte de los sistemas tienen medios muy deficientes para suspender indefinidamente un proceso, eliminarlo del sistema y reanudarlo más tarde. De hecho, algunos procesos como los de tiempo real, que deben funcionar continuamente, sencillamente no se pueden suspender y reanudar.
Aún cuando existieran medios efectivos de suspensión/reanudación, con toda seguridad implicarían un gasto extra considerable.
La recuperación después de un bloqueo mutuo de dimensiones modestas puede significar una cantidad razonable de trabajo, un interbloqueo a gran escala puede requerir una cantidad enorme de trabajo.
En los sistemas actuales la recuperación se suele realizar eliminado un proceso y arrebatándole sus recursos. Por lo general, el proceso eliminado se pierde pero ahora es posible concluir los procesos restantes. Algunas veces es necesario eliminar varios procesos hasta que se hayan liberado los recursos suficientes para que terminen los procesos restantes.
Los procesos pueden eliminarse de acuerdo con algún orden de prioridad. También existen dificultades para ello :
Es posible que no existan prioridades entre los procesos bloqueados, de modo que se tiene que adoptar una decisión arbitraria.
Las prioridades pueden ser incorrectas o un poco confusas debido a consideraciones especiales, como la planificación a plazo fijo, en la cual un proceso de prioridad relativamente baja tiene una prioridad temporal alta a causa de un fin de plazo inminente.
La determinación de una decisión óptima sobre los procesos que se deben eliminar puede requerir un esfuerzo considerable.
Parece ser que el enfoque más deseable para la recuperación después de un bloqueo mutuo sería un mecanismo efectivo de suspensión/reanudación. Ello implicaría suspender temporalmente los procesos y reanudarlos después sin pérdida de trabajo productivo. Para ello sería deseable la posibilidad de especificar puntos de verificación/reinicio. De este modo, se facilita la suspensión/reanudación, que se hará desde el último punto de verificación (es decir, la última grabación del estado del sistema). Pero muchos sistemas de aplicación se diseñan sin aprovechar las ventajas de las funciones de punto de verificación/reinicio. Por lo general, se requiere un esfuerzo consciente por parte de los diseñadores para incorporar la verificación/reinicio, y a menos que las tareas requieran muchas horas de ejecución, su uso es poco común.
10.4 Estrategias para Resolver Interbloqueos
Los resultados de la investigación sobre el bloqueo mutuo han sido satisfactorios en cuanto a que se han encontrado métodos limpios y rápidos para manejar la mayoría de los problemas más comunes. Existen cuatro áreas de interés relacionadas con los interbloqueos que pueden resumirse como prevención, técnicas para evitarlos, detección y recuperación de los mismos.
En la prevención del interbloqueo interesa ajustar el sistema para eliminar toda posibilidad de que ocurra un bloqueo mutuo. La prevención suele funcionar pero sus métodos ocasionan, en general, un aprovechamiento pobre de los recursos. No obstante, estos métodos se utilizan con frecuencia.
Las técnicas que tienen como objetivo evitar el interbloqueo imponen condiciones menos atractivas que en la prevención, para tratar de obtener un aprovechamiento de los recursos. No elimina como las técnicas de prevención todas las posibilidades de que se produzca un bloqueo mutuo, pero se esquiva cuanto está a punto de suceder (algoritmo del banquero de Dijkstra).
Los métodos de detección del interbloqueo es utilizan en sistemas que permiten la ocurrencia de los mismos, ya sea de manera voluntaria o involuntaria. Su objetivo es determinar si ha ocurrido un bloqueo mutuo y saber exactamente cuáles son los procesos y recursos implicados en él.
Los métodos de recuperación están íntimamente ligados a los de detección. Sirven para eliminar los interbloqueos detectados en un sistema para poder seguir trabajando y para que los procesos implicados puedan terminar su ejecución y liberen sus recursos. La recuperación es un problema complejo, en el mejor de los casos, los sistemas se recuperan de un bloqueo mutuo eliminando completamente uno o varios de los procesos implicados. Después, se inician de nuevo los procesos eliminados, perdiéndose la mayor parte o todo el trabajo previo realizado por el proceso.
10.5 Interbloqueos: Sistemas Actuales/Sistemas Futuros
En los sistemas actuales, el interbloqueo se ha considerado generalmente como una molestia limitada. La mayor parte de los sistemas siguen los métodos básicos de prevención sugeridos por Havender, y tales métodos parecen ser satisfactorios.
Sin embargo, en los sistemas futuros el bloqueo mutuo será una consideración mucho más importante por varias razones :
Los sistemas futuros estarán más orientados hacia operaciones asíncronas en paralelo que hacia las operaciones en serie. El multiprocesamiento es ya muy común y la computación paralela será dominante así como la proliferación de redes y sistema distribuidos. En pocas palabras, se realizarán más operaciones en paralelo, habrá más conflictos por los recursos y, por tanto, más oportunidad de que aparezca un interbloqueo.
En los sistemas futuros, la asignación tenderá a ser dinámica. Los procesos podrán adquirir y liberar recursos según sus necesidades. Los usuarios no necesitarán saber mucho acerca de sus requisitos de recursos antes de la ejecución de un programa. De hecho, con las interfaces cada vez más amables, la mayoría de los usuarios no se preocupan demasiado por el consumo de los recursos de sus procesos.
Con la creciente tendencia de los diseñadores de sistemas operativos a contemplar los datos como un recurso más, aumentará notablemente el número de recursos que debe administrar un sistema operativo.
Por lo tanto, la tarea de asignar recursos sin la posibilidad de interbloqueos en los sistemas de cómputo recaerá sobre el sistema operativo. Con el abaratamiento y la creciente potencia de los recursos, es razonable que se amplíen las funciones de la computadora y del sistema operativo.
UNIDAD 3 11.0 “ADMISTRACIÓN DE LA MEMORIA”
11.1 La organización y gestión de la memoria. Conceptos generales
Para que un proceso pueda ejecutarse debe estar ubicado en la memoria principal del ordenador. Una parte del sistema operativo se va a encargar de gestionar la memoria principal, de forma que los procesos puedan residir en la memoria sin conflictos. La gestión de la memoria implica varias tareas, una de ellas es llevar un registro de qué zonas están libres (es decir, no están siendo utilizadas por ningún proceso), y qué zonas están ocupadas por qué procesos. Otra tarea importante surge en sistemas en los que no todos los procesos, o no todo el código y datos de un proceso, se ubican en la memoria principal. En estos sistemas, a menudo se debe pasar parte, o la totalidad del código y datos de un proceso, de memoria a disco, o viceversa; siendo el sistema operativo responsable de esta tarea. De esta forma se libera al usuario de realizar estas transferencias de información, de las cuales no es consciente.
Otros dos temas importantes en la gestión de la memoria son el de la carga de los programas de disco a memoria y el de la protección. Desde el momento en que varios procesos deben compartir la memoria del ordenador surge el problema de la protección. En general, se pretende que un proceso no pueda modificar las direcciones de memoria en las que no reside. Esto es así ya que en las direcciones de memoria donde no está ubicado el proceso pueden residir otros procesos, o código o estructuras de datos del S.O. Si un proceso puede modificar indiscriminadamente la memoria, podría, por ejemplo, cambiar el valor de una dirección de memoria donde residiera una variable de otro proceso, con la consecuente ejecución incorrecta del proceso propietario de la variable. Algunos sistemas ni siquiera permiten que un proceso pueda leer las direcciones de memoria en las que no reside, con esto se consigue privacidad sobre el código y datos de los procesos. Conforme avance este tema y el siguiente se profundizará en todos estos aspectos.
Existen varias formas de gestionar la memoria. Por lo común, la forma de gestión dependerá de la máquina virtual que se quiera proporcionar y delhardware subyacente. Con independencia de la forma de gestión es necesario decidir qué estrategias se deben utilizar para obtener un rendimiento óptimo. Las estrategias de administración de la memoria determinan el comportamiento de una organización de memoria determinada cuando se siguen diferentes políticas: ¿ Cuándo se coge un nuevo programa para colocarlo en la memoria ? ¿ Se coge el programa cuando el sistema lo necesita, o se intenta anticiparse a las peticiones del sistema ? ¿ En qué lugar de la memoria principal se coloca el siguiente programa por ejecutar ? ¿ Se colocan los programas lo más cerca posible unos de otros en los espacios disponibles de la memoria principal para reducir al mínimo el desperdicio de espacio, o se colocan lo más rápido posible para reducir el tiempo empleado en tomar la decisión ?
Los sistemas actuales son en su mayor parte sistemas con almacenamiento virtual, muchas de la formas de gestión estudiadas en este tema tienen principalmente valor histórico, pero sientan las bases de los sistemas actuales.
Jerarquía de la memoria
Los programas y datos necesitan estar en la memoria principal para ser ejecutados, o para poder ser referenciados. Los programas o datos que no se necesitan de inmediato pueden guardarse en la memoria secundaria hasta que se necesiten, y en ese momento se transfieren a la memoria principal para ser ejecutados o referenciados. Los soportes de memoria secundaria, como cintas o discos, son en general menos caros que la memoria principal, y su capacidad es mucho mayor. Normalmente, es mucho más rápido el acceso a la memoria principal que a la secundaria.
En los sistemas con varios niveles de memoria hay muchas transferencias constantes de programas y datos entre los distintos niveles. Estas transferencias consumen recursos del sistema, como tiempo de la CPU, que de otro modo podrían utilizarse provechosamente.
En los años sesenta se hizo evidente que la jerarquía de la memoria podía extenderse un nivel más, con una clara mejora del rendimiento. Este nivel adicional, la memoria caché, es una memoria de alta velocidad, mucho más rápida que la memoria principal. La memoria caché es extremadamente cara, si se compara con la principal, por lo que sólo se utilizan memorias caché relativamente pequeñas. La figura 6.1 muestra la relación que existe entre la memoria caché, la principal y la secundaria.
La memoria caché introduce un nivel adicional de transferencia de información en el sistema. Los programas en memoria principal se pasan a la memoria caché antes de ejecutarse. En la memoria caché se pueden ejecutar mucho más rápido que en la principal. La esperanza de los diseñadores es que el trabajo extra requerido por la transferencia de programas sea mucho menor que el incremento del rendimiento obtenido por la ejecución más rápida en la caché.
11.2 Gestión de la memoria en los sistemas monoprogramados
En los sistemas de monoprogramación sólo existe un proceso de usuario, que disfruta de todos los recursos del ordenador. Esto va a simplificar notablemente la gestión de la memoria, ya que ésta sólo debe ser compartida por los programas del sistema operativo, y por el único proceso de usuario existente. Esto se muestra en la figura 6.2. Dependiendo de detalles de diseño, el sistema operativo ocupará la parte baja de la memoria RAM, como se muestra en la figura 6.2 (a); o la parte alta de la memoria ROM, como se muestra en la figura 6.2 (b). El PC de IBM ubica parte del sistema operativo en RAM, y los gestores de dispositivos en ROM; a esta última parte se le llama BIOS (Basic Input/Output System, sistema básico de entrada/salida), esto último se ilustra en la figura 6.2 (c).
Si el usuario conoce la ubicación en la memoria del sistema operativo, entonces puede escribir programas en términos de direcciones absolutas de memoria. Una dirección absoluta de memoria es una dirección física (es decir, real) de la memoria. En contraposición se tienen las direcciones relativas. Un programa está escrito en término de direcciones relativas cuando se escribe suponiendo que empieza a cargarse en la dirección cero de la memoria. Por lo general, los usuarios escriben programas en lenguajes de alto nivel, por lo que son los traductores los encargados de generar las direcciones que ocupan las variables, procedimientos, etc, en la memoria. Los compiladores no generan direcciones absolutas de memoria, pues no saben dónde se almacenarán los procesos.
Por lo común, los sistemas operativos monousuario de monoprogramación (muy comunes en las microcomputadoras) no tienen protección de la memoria. Por lo tanto, el único proceso de usuario que existe en la memoria, puede modificar posiciones de memoria pertenecientes al sistema operativo, esto provocaría errores al ejecutarse la zona modificada. La protección se puede realizar mediante un registro de límite integrado en la CPU. Si se tiene un esquema como el de la figura 6.2 (b) el registro de límite contendrá la dirección de inicio de carga del S.O. El hardware, en tiempo de ejecución, verifica que las direcciones generadas por el proceso de usuario no son superiores al valor del registro de límite. En caso de ser superior, el proceso de usuario intenta acceder al S.O., esto provoca una interrupción hardware que gestiona el S.O., normalmente eliminando al proceso.
11.3 Gestión de la memoria en los sistemas multiprogramados
En un sistema de multiprogramación la memoria debe ser compartida por varios procesos de cara a obtener una mayor utilización de los recursos del ordenador. Esto provoca que la gestión de la memoria se complique sustancialmente. En primer lugar, hay que llevar un recuento de las zonas de memoria ocupadas por los procesos. Así, cuando un nuevo proceso entre en la memoria se le asignará una zona que estaba libre. Otro problema a resolver viene dado por el hecho de que en el momento de escribir un programa no se sabe en qué zona de memoria se ubicará, siendo posible que durante la vida de un proceso éste cambie varias veces de emplazamiento. Habrá que tener en cuenta, también, la protección de las zonas de memoria ocupadas por los procesos, máxime en sistemas multiusuario donde los procesos pueden pertenecer a distintos usuarios.
En lo que resta de este tema, y en el tema siguiente, se estudiarán varias formas de gestión de la memoria utilizadas en sistemas de multiprogramación.
11.4 Asignación de memoria contigua
En un esquema de asignación de memoria contigua un proceso se ubica en su totalidad en posiciones consecutivas de memoria. Un ejemplo de este tipo de asignación es el utilizado en los sistemas de monoprogramación vistos previamente. En este apartados se estudian dos métodos de asignación contigua empleados históricamente en sistemas multiprogramados.
11.4.1 Particiones estáticas
Esta forma de gestión consiste en dividir la memoria en varias zonas, pudiendo ser cada zona de un tamaño diferente. Esto se ilustra en la figura 6.3. El tamaño de las zonas podrá ser modificado eventualmente por algún usuario responsable de la administración del ordenador.
Los trabajos se traducían mediante compiladores y ensambladores absolutos, para ejecutarse en una partición específica. Una vez introducido un proceso en una partición, permanece en ella hasta su finalización. Si un trabajo se iniciaba, y la partición para la que estaba compilado estaba ocupada, tenía que esperar, aunque estuvieran libres otras particiones. Esto provoca una pérdida de eficiencia.
De cara a mejorar el rendimiento es preciso que un proceso se pueda cargar en cualquier partición. Para ello, los programas se escriben en términos de direcciones relativas a la dirección de comienzo de carga cero. Sin embargo, los programas no se cargan a partir de la dirección cero, esta circunstancia se debe resolver mediante la reasignación o reubicación, ¿cómo se realiza ésta ?. Una posible implantación viene proporcionada por el hardware. Existe un registro, denominado registro base, en el que el sistema operativo, dentro de la operación de cambio de proceso, escribe la dirección de memoria a partir de la cual se almacenó el proceso. Esta dirección coincidirá con la de comienzo de la partición en que reside, y forma parte de su descriptor(PCB). Cuando la CPU genera una dirección de memoria, ésta es transformada por el hardware antes de ser introducida en el bus del sistema. La transformación consiste en sumarle a la dirección el registro base.
Para clarificar esto, supóngase que la instrucción que actualmente ejecuta la CPU guarda el contenido del acumulador en la dirección relativa 100 de la memoria. Esta dirección, 100, (que podría, por ejemplo, guardar el contenido de una variable de otro proceso) es relativa a una dirección 0 de comienzo del programa. Si el programa se ha cargado en la posición 10000 de la memoria, el registro base contendrá el valor 10000. Cuando la CPU ejecuta la instrucción, genera la dirección 100 de memoria (la cual físicamente pertenece a otro proceso). Sin embargo, el hardware suma 10000 a este valor, introduciéndose 10100 en el bus del sistema, dirección que realmente ocupa la variable. Observe que con este esquema, si se quiere reubicar el proceso a otro lugar de la memoria, sólo hay que desplazarlo de lugar, y modificar el registro base con la nueva dirección de comienzo de carga.
Una solución software al problema de la reasignación consiste en modificar las instrucciones cuando el programa se carga en la memoria. Para que esto ocurra es preciso que el enlazador (el programa que a partir de los ficheros objeto genera un único objeto) incluya en el programa binario una lista que indique qué partes del programa son direcciones a reasignar, y cuáles no (constantes, códigos de operadores u otros elementos que no deban ser reasignados). Con esta solución, cada reubicación en la memoria implica una reasignación de las direcciones de memoria del programa.
Protección
Si se tiene el esquema hardware del registro base, para lograr la protección de las zonas de memoria basta con añadir un nuevo registro, denominadoregistro límite. Este registro guarda la última dirección de la partición, y forma también parte del PCB del proceso. El hardware, después de sumar el registro base a la dirección relativa, comprueba que la dirección obtenida no supere el valor del registro límite. Si se supera el valor, se está intentando acceder a una zona que no corresponde al proceso; en esta situación, el hardware genera una interrupción. El sistema operativo sirve a la interrupción, lo normal es que mande una señal al proceso por violación de memoria. Si el proceso no tiene definido atrapar esa señal, lo cual es lo más probable, se eliminará al proceso.
Cuando un proceso quiera ejecutar código del sistema operativo, por ejemplo, para realizar una E/S, no tiene acceso directo a las rutinas que tiene el sistema operativo en memoria para implementar dicha función, sino que debe realizar una llamada al sistema para no violar la protección. Este esquema es necesario, pues los programas de usuario tienen que avisar al sistema operativo de que le solicitan servicios (al hacer una llamada al sistema), el sistema operativo atenderá las peticiones si son correctas, o si pueden ser factibles en dicho momento (por ejemplo, no se asignará una impresora que está siendo utilizada por otro proceso). Los procesos de usuario no pueden llamar directamente al sistema operativo gracias a la protección de memoria.
Una última observación, al margen de la protección: cuando un proceso se introduce en una partición, lo más probable es que su tamaño no sea el mismo (es decir, sea algo menor) que el de la partición. Esto origina un problema de desperdicio de memoria conocido como fragmentación interna.
11.4.2 Particiones dinámicas
En este método se va asignando la memoria dinámicamente a los procesos, conforme se introducen en la memoria. A cada proceso se le asigna exactamente la memoria que necesita.
En la figura 6.4 se ilustra cómo evoluciona la ocupación de la memoria en un sistema de este tipo. Al principio sólo se encuentra el proceso A en la memoria. Después, se insertan los procesos B y C . En la figura 6.4-d A concluye. Luego, D entra y B sale. Por último E entra.
Con este método de gestión de la memoria se evita el problema de la fragmentación interna. Sin embargo, aparece el problema de la fragmentación externa entre particiones, el cual se aprecia en la figura 6.4-f. El problema consiste en que se creen huecos libres demasiado pequeños como para que quepan procesos, aunque la unión de todos esos huecos produciría un hueco considerable, lo que acarrea el desperdicio de la memoria. Una posible solución es la compactación de la memoria, que consiste en desplazar todos los procesos hacia la parte inferior de la memoria mientras sea posible. Como la compactación lleva mucho tiempo, a veces no se realiza, o se hace por la noche, en horas de poco uso del ordenador. Hay que tener en cuenta que el sistema debe detener todas sus actividades mientras realiza la compactación. Ello puede ocasionar tiempos de respuesta irregulares para usuarios interactivos, y podría ser devastador en un sistema de tiempo real. Además, con una combinación normal de trabajos que cambia rápidamente, es necesario compactar a menudo. En este caso, los recursos del sistema que se consumen quizá no justifiquen las ventajas de la compactación.
El esquema de los registro base y límite sigue siendo válido para la reasignación y la protección. Otro tema a tener en cuenta es la cantidad de memoria por asignar a un proceso recién creado. Si los procesos se crean con un tamaño fijo invariante, la asignación es muy sencilla, se asigna exactamente lo que se necesite.
Si, por el contrario, los segmentos de datos de los procesos pueden crecer, como es el caso de la asignación dinámica de memoria a partir de una pila, que ocurre en muchos lenguajes de programación, aparece un problema cuando un proceso intenta crecer. Si hay un hueco adyacente al proceso, éste puede ser asignado, y el proceso podrá crecer hacia el hueco. Sin embargo, si el proceso es adyacente a otro proceso, el proceso de crecimiento deberá ser desplazado a un hueco de la memoria lo suficientemente grande; o bien, habrá que eliminarlo.
Si es de esperar que la mayoría de los procesos crezcan conforme se ejecuten, sería una buena idea asignar un poco de memoria adicional siempre que un proceso pase a la memoria, con el fin de reducir el gasto excesivo asociado con el traslado de procesos que ya no caben en su memoria asignada. En la figura 5-a vemos una configuración de la memoria en la que se asignó a dos procesos el espacio adicional para el crecimiento.
Si los procesos pueden tener dos segmentos de crecimiento, como por ejemplo, el segmento de datos, que se utiliza como una pila, y el stack, se sugiere un método alternativo, el de la figura 5-b. En esta figura se puede ver que cada proceso tiene un stack de crecimiento hacia abajo, en la parte superior de la memoria asignada a él; además, tiene un segmento de datos justo encima del programa, el cual crece hacia arriba. La memoria entre ellos se puede utilizar para cualquiera de los segmentos. Si el espacio se agota, puede ocurrir que el proceso sea desplazado a un hueco con el espacio suficiente; o bien, ser aniquilado.
Registro de la ocupación de la memoria
En el sistema de particiones estáticas es sencillo llevar el registro de la ocupación de la memoria, basta con guardar sobre cada partición si está libre, u ocupada por qué proceso, así como sus direcciones de comienzo y fin de partición. Por contra, con las particiones dinámicas, el número de éstas varía con el tiempo, así como su tamaño. Una forma posible de registrar la ocupación de la memoria es utilizar una lista enlazada de los segmentos de la memoria asignados o libres. La memoria de la figura 6.6-a se presenta en la figura 6-c como una lista enlazada de segmentos. Cada entrada de la lista especifica un hueco (H) o un proceso (P), la dirección donde comienza, su longitud, y un puntero a la siguiente entrada.
En este ejemplo, la lista de segmentos está ordenada por direcciones. Este orden tiene la ventaja de que al terminar un proceso la actualización de la lista es directa. Un proceso que termina, tiene dos vecinos (a menos que se encuentre en la parte superior o inferior de la memoria). Estos pueden ser procesos o huecos, lo que produce las cuatro combinaciones de la figura 6.7. En la figura 6.7-a, la actualización de la lista requiere el reemplazo de una P por una H. En la figura 6.6 (b) y (c), dos entradas se funden en una, y la lista se acorta en una entrada. En la figura 6.6-d tres entradas se fusionan en una. Puesto que en el descriptor del proceso que termina se guardará un puntero a la entrada de la lista enlazada que ocupa dicho proceso, sería conveniente que la lista fuera doblemente enlazada. Esta estructura facilita la búsqueda de la entrada anterior y, por tanto, la verificación de si es posible una fusión.
Figura 6.6. (a) Una parte de la memoria, con cinco procesos y 3 huecos. La marca muestra las unidades de asignación de la memoria. Las regiones sombreadas ( 0 en el mapa de bits) están libres. (b) El mapa de bits correspondiente. (c) La misma información como lista enlazada.
11.4.3 Estrategias de colocación
Cuando en un sistema de particiones dinámicas se debe asignar memoria principal para un nuevo proceso, y los procesos y huecos se mantienen en una lista ordenada por direcciones, se pueden utilizar diversos algoritmos para la elección del hueco de memoria donde ubicar al proceso. Supongamos que se conoce la cantidad de memoria por asignar.
El algoritmo más simple es el primero en ajustarse (first fit). Se revisa la lista de huecos hasta encontrar un espacio lo suficientemente grande. El espacio se divide entonces en dos partes, una para el proceso, y otra para la memoria no utilizada, excepto en el caso poco probable de un ajuste perfecto. Este algoritmo es rápido, ya que busca lo menos posible.
Otro algoritmo es el mejor en ajustarse (best fit), el cual busca en toda la lista, y elige el mínimo hueco suficientemente grande como para ubicar al proceso. Este algoritmo intenta que los huecos que se creen en la memoria sean lo más pequeños posible.
Como ejemplo de los algoritmos, retomemos la figura 6.6. Si se necesita un bloque de tamaño 2, el primero en ajustarse asignará el espacio en 5, mientras que el mejor en ajustarse asignará el espacio en 18.
Realizando simulaciones se ha demostrado que el algoritmo del mejor ajuste desperdicia más la memoria, pues al crear huecos demasiado pequeños, éstos no pueden ser utilizados por procesos. Un algoritmo que enfrenta el problema de la manera contraria es el del peor ajuste (worst fit). En este algoritmo se elige el hueco más grande disponible. De esta forma aumenta la probabilidad de que el nuevo hueco creado sea lo suficientemente grande como para albergar un proceso.
11.4.4 Intercambio (swapping)
En un sistema con particiones estáticas el número de procesos con posibilidades de estar en estado listo viene determinado por el número de particiones, y en uno de particiones dinámicas por el tamaño de la memoria principal y el tamaño de los procesos, ya que en ambos métodos un proceso permanece en una partición hasta que finaliza. Supongamos un sistema en que dicho número es cinco, es muy probable que en un momento dado los cinco procesos que ocupan las particiones estén bloqueados (por ejemplo, porque esperan la finalización de una operación de E/S). Mientras los cinco procesos permanezcan bloqueados se desperdicia la CPU. Para remediar este inconveniente muchos sistemas operativos optaron por permitir ejecutar concurrentemente más procesos de los que pueden entrar físicamente en la memoria principal del ordenador. Para ello se utiliza la memoria secundaria (generalmente los discos) que, aunque más lenta, tiene mayor capacidad de almacenamiento que la principal. La solución consiste en tener en disco una copia de la parte de la memoria que ocupa todo proceso. En el disco se encuentran todos los procesos, en la memoria sólo unos cuantos. Para que un proceso se pueda ejecutar debe residir en memoria principal.
La razón por la que se aumenta el número de procesos con posibilidades de tener instrucciones en memoria principal es porque cuanto mayor sea este número, es menos probable que se dé la circunstancia de que todos estén bloqueados y, por lo tanto, es menor la posibilidad de que la CPU permanezca inactiva.
Algunos sistemas UNIX utilizaban el intercambio en un sistema de particiones dinámicas. El movimiento de procesos entre la memoria principal y el disco lo realizaba el planificador de nivel medio, conocido como el intercambiador (swapper a medio plazo). El intercambio de la memoria principal al disco (swapping out) se iniciaba cuando el S.O. precisa memoria libre y estaba toda ocupa debido a alguno de los siguientes eventos:
Una llamada al sistema fork que necesitaba memoria para un proceso hijo.
Una llamada al sistema brk de solicitud de memoria dinámica en un proceso que no tiene suficiente memoria libre como para aceptar la petición.
Una pila que se agranda, y ocupa un espacio mayor al asignado.
Además, cuando había que recuperar un proceso presente en el disco (swapping in) desde hace mucho tiempo con frecuencia se necesitaba sacar a otro proceso de memoria a disco para disponer de espacio para el primero.
El intercambiador elegía una víctima al examinar los procesos bloqueados en espera de algo (por ejemplo, una entrada del terminal). Es mejor sacar a un proceso bloqueado (pasará a estado suspendido_bloqueado) que sacar a uno listo. Si existían varios procesos bloqueados ubicados en la memoria principal se elegía a uno cuya combinación de prioridad y tiempo de residencia en memoria principal fuera más desfavorable. Así, un buen candidato era un proceso que hubiera consumido mucho tiempo de CPU recientemente, al igual que uno que hubiera permanecido en la memoria durante mucho tiempo, aun cuando durante este tiempo hubiera realizado E/S. Si no se dispone de procesos bloqueados, entonces se elegía a un proceso listo en base a los mismos criterios.
Cada pocos segundos el intercambiador examinaba la lista de procesos intercambiados para ver si alguno estaba listo para su ejecución. En caso de que existiera alguno, se seleccionaba a aquel que hubiese permanecido en el disco durante mucho tiempo. A continuación el intercambiador verificaba si el intercambio sería fácil o difícil. Un intercambio fácil era aquel en el que existiera la suficiente memoria libre, de forma que no había necesidad de sacar a un proceso para hacer espacio para el nuevo. Un intercambio difícil precisaba la eliminación de uno o más procesos. La implantación de un intercambio fácil se llevaba a cabo al traer el proceso a la memoria. Un intercambio difícil se implantaba liberando primero la memoria suficiente sacando a disco a uno o más procesos, y después, cargando en la memoria el proceso deseado.
Este algoritmo se repetía hasta que se cumpliera alguna de estas condiciones: (1) ningún proceso en el disco está suspendido_listo; o (2) la memoria está tan ocupada por procesos recién traídos que no hay espacio para más. Para evitar un trasiego excesivo entre memoria y disco que pudiera afectar al rendimiento no se intercambiaba hacia el disco a un proceso hasta que hubiera permanecido en la memoria durante 2 segundos.
El espacio libre en la memoria principal y en el dispositivo de intercambio se registraba mediante una lista enlazada de huecos. Si se necesitaba espacio en alguno de los dos, el algoritmo del primero en ajustarse leía la lista adecuada de huecos, y devolvía el primer hueco que encontrara y que fuese lo bastante grande, a la vez que eliminaba este espacio de la lista de huecos.
11.5 Asignación de memoria no contigua.
Hasta ahora se han estudiado esquemas de administración de la memoria en los que los procesos se almacenan en posiciones contiguas (consecutivas) de memoria. Sin embargo, un proceso puede dividirse en bloques, y estos bloques pueden situarse en posiciones no contiguas de memoria principal. Es más, no es preciso que se encuentren en la memoria todos los bloques de un proceso para que se pueda ejecutar, basta con que se encuentren los bloques que contienen código o datos actualmente referenciados, el resto puede permanecer en memoria secundaria.
La memoria virtual
La clave del concepto de memoria virtual es la disociación de las direcciones a las que hace referencia un proceso en ejecución de las direcciones disponibles en la memoria principal.
Las direcciones a las que hace referencia un proceso en ejecución, en este esquema, se llaman direcciones virtuales. El intervalo de direcciones virtuales a las que puede hacer referencia un proceso en ejecución se llama espacio de direcciones virtuales, V, del proceso. El intervalo de direcciones reales de la memoria principal de un ordenador concreto se llama espacio de direcciones reales, R. El número de direcciones de V se denota |V|, y el número de direcciones de R, |R|. En los sistemas de almacenamiento virtual ya implantados lo normal es que |V| >> |R|, aunque se han construido sistemas en los que |V| < |R|.
La memoria virtual es una técnica de gestión de la memoria que posibilita que el espacio de direcciones virtuales sea mayor al espacio de direcciones reales. En otras palabras, se permite hacer programas de tamaño mayor al de la memoria principal. Para lograr esto, el sistema operativo se encarga de mantener en la memoria principal solamente aquellas partes del espacio de direcciones del proceso que actualmente están siendo referenciadas, el resto permanece en disco.
La memoria virtual se basa en el hecho de que muchos programas presentan un comportamiento conocido como operación en contexto, según el cual, en cualquier intervalo pequeño de tiempo un programa tiende a operar dentro de un módulo lógico en particular, sacando sus instrucciones de una sóla rutina y sus datos de una sóla zona de datos. De esta forma, las referencias de memoria de los programas tienden a agruparse en pequeñas zonas del espacio de direcciones. La localidad de estas referencias viene reforzada por la frecuente existencia de bucles: cuanto más pequeño sea el bucle, menor será la dispersión de las referencias. La observación de este comportamiento conduce al postulado (Denning, 1970) del llamado principio de localidad: "Las referencias de un programa tienden a agruparse en pequeñas zonas del espacio de direcciones. Estas zonas, además, tienden a cambiar sólo de forma intermitente".
La validez del principio de localidad varía de programa en programa: será, por ejemplo, más válido en programas que lleven a cabo accesos secuenciales a vectores que en programas que accedan a estructuras complejas de datos.
La memoria virtual se compagina con la multiprogramación. Al no tener que almacenar los procesos enteros en la memoria, pueden entrar más en la memoria principal, con lo que es más probable que siempre exista un proceso en estado listo. Por otro lado, cuando un proceso espera a que se cargue en la memoria principal parte de su código o datos, se inicia una E/S con el disco. Mientras dura dicha E/S la CPU puede ejecutar otro proceso.
Aunque los procesos sólo hacen referencia a direcciones virtuales, deben ejecutarse en la memoria real. Por lo tanto, durante la ejecución de un proceso es preciso establecer la correspondencia entre las direcciones virtuales y las reales. Como se verá más adelante esta correspondencia debe realizarse de una manera rápida, pues si no, se ralentizaría demasiado el tiempo de ejecución de los procesos.
Se han desarrollado varios métodos para asociar las direcciones virtuales con las reales. Los mecanismos de traducción dinámica de direccionesconvierten la direcciones virtuales en direcciones reales en tiempo de ejecución. Todos estos sistemas tienen la propiedad de que las direcciones contiguas en el espacio de direcciones virtuales de un proceso no son necesariamente contiguas en la memoria principal. Esto se conoce comocontigüidad artificial (fig. 6.8). Debe quedar claro que toda esta correspondencia es transparente al programador, que escribe sus programas en términos de direcciones consecutivas de memoria virtual.
11.5.1 Esquema general de traducción
Los mecanismos de traducción dinámica de direcciones deben mantener mapas de correspondencia de traducción de direcciones que indiquen qué localidades de la memoria virtual están en memoria principal en un momento dado y dónde se encuentran.
Existen dudas en cuanto a si los bloques en que se dividen los procesos deben ser del mismo tamaño o de tamaños diferentes. Cuando los bloques son del mismo tamaño, se llaman páginas, y la organización de la memoria virtual correspondiente se conoce como paginación. Cuando los bloques pueden tener tamaños diferentes se llaman segmentos, y la organización de la memoria virtual correspondiente se llama segmentación. Algunos sistemas combinan ambas técnicas, con segmentos, que son entidades de tamaño variable, compuestas de páginas de tamaño fijo ( Segmentación paginada ).
Las direcciones en un sistema de correspondencia son bidimensionales. Para referirse a un elemento en particular, el programa especifica el bloque en el que se encuentra el elemento, y su desplazamiento a partir del inicio del bloque. Una dirección virtual, v, se denota por un par ordenado (b,d), donde bes el número de bloque en el que se encuentra el elemento al que se hace referencia, y d es el desplazamiento a partir del inicio del bloque.
La traducción de una dirección virtual v = (b,d) a una dirección real, r, se ejecuta de la siguiente forma (fig. 9). Cada proceso tiene su propia tabla de correspondencia de bloques, mantenida por el sistema operativo dentro de la memoria principal. Un registro especial dentro de la CPU, denominadoregistro de origen de la tabla de correspondencia de bloques, se carga con la dirección real, a, de la tabla de correspondencia de bloques del proceso durante el cambio de proceso. La tabla contiene una entrada por cada bloque del proceso, y las entradas siguen un orden secuencial para el bloque 0, el bloque 1, etcétera. Ahora se suma el número de bloque, b, a la dirección base, a, de la tabla de bloques, para formar la dirección real de la entrada del bloque b en la tabla de correspondencia de bloques. Esta entrada contiene la dirección real, b', de inicio del bloque b. El desplazamiento, d, se suma a la dirección de inicio del bloque, b', para formar la dirección real
deseada, r = b' + d.
Todas las técnicas de correspondencia de bloques empleadas en los sistemas de segmentación, paginación, y paginación y segmentación combinada son similares a la correspondencia mostrada en la figura 6.9.
Es importante señalar que la traducción de una dirección virtual a real la realiza una unidad hardware, que transforma todas las direcciones generadas por la CPU antes de que pasen al bus del sistema. Es esencial que esta transformación la realice el hardware, y no el sistema operativo, pues muchas instrucciones máquina incluyen referencias a memoria, y la correspondencia debe realizarse rápidamente, para no ralentizar en exceso el tiempo de ejecución de los procesos. Por ejemplo, las dos sumas indicadas en la figura 6.9 deben ser más rápidas que las sumas convencionales del lenguaje máquina.
Aunque el hardware consulta las tablas de correspondencia de bloques para la transformación de direcciones, es el sistema operativo el encargado de rellenar y gestionar dichas tablas. Un proceso no tiene por qué tener todos sus bloques en memoria principal, recuérdese que el espacio de direcciones virtuales puede ser muy superior al espacio de direcciones reales, esto hace que a veces un proceso referencie a una dirección de un bloque que no se encuentra en la memoria principal. Para detectar esto, las tablas de correspondencias tienen un "bit de presencia" por entrada (cada entrada representa un bloque), que indica si el bloque se encuentra presente en la memoria principal o no. El hardware de traducción debe verificar este bit en cada referencia a memoria.
Si el bloque no está en memoria principal, el hardware produce una interrupción. Esta interrupción provoca que el control pase al software (sistema operativo), para que éste inicie la transferencia del bloque que falta desde la memoria secundaria a la memoria principal, y actualice de acuerdo con ello la tabla de correspondencias. El proceso en ejecución se hará no listo hasta que se haya completado esta transferencia. La posición de los bloques en la memoria secundaria puede guardarse en la misma tabla de correspondencias.
11.5.2 Paginación
El concepto de almacenamiento a un sólo nivel, en el que la memoria secundaria aparece como una extensión de la memoria principal, se introdujo por primera vez en el ordenador Atlas de la Universidad de Manchester alrededor de 1960, y desde entonces ha ejercido una profunda influencia en el diseño de los ordenadores.
El almacenamiento a un sólo nivel puede llevarse a cabo mediante una técnica llamada paginación, según la cual el espacio de direcciones virtuales se divide en páginas del mismo tamaño (en el Atlas eran de 512 palabras). La memoria principal se divide también en marcos o páginas físicas del mismo tamaño. Estos marcos son compartidos entre los distintos procesos que haya en el sistema, de forma que en cualquier momento un proceso dado tendrá unas cuantas páginas residentes en la memoria principal (sus páginas activas) y el resto en la memoria secundaria (sus páginas inactivas). El mecanismo de paginación cumple dos funciones:
Llevar a cabo la transformación de una dirección virtual a física, o sea, la determinación de la página a la que corresponde una determinada dirección de un programa, así como del marco, si lo hay, que ocupa esta página;
Transferir, cuando haga falta, páginas de la memoria secundaria a la memoria principal, y de la memoria principal a la memoria secundaria cuando ya no sean necesarias.
La primera función se aborda a continuación, y se deja para el siguiente tema la segunda función.
Con el fin de determinar la página a la que hace referencia un programa, los bits de mayor peso de la dirección se interpretan como el número de página, y los bits de menor peso como el número de palabra dentro de esta página. De ahí que si el tamaño de página es 2n, los n bits finales de la dirección representarán el número de palabra y los bits restantes del principio el número de página. El número total de bits en la dirección es suficiente para direccionar la totalidad de la memoria virtual. Así, por ejemplo, en el Atlas las direcciones de programa tenían 20 bits de longitud, proporcionando una memoria virtual de 220 palabras; el tamaño de la página era de 512 palabras (29), y de ahí que los 9 bits inferiores representasen el número de palabra y los 11 superiores representasen el número de la página. El número total de páginas en la memoria virtual era por tanto de 211 (en contraposición a las 32 páginas físicas de que disponía la memoria principal).
Es de destacar el hecho de que la división de la dirección en número de palabra y número de página, es tarea del hardware, y es transparente al programador: por lo que a Jl concierne está programando en un espacio secuencial de direcciones muy grande.
La transformación de número de página y de palabra en la dirección física de memoria se realiza a través de una tabla de páginas, cuyo p-ésimo elemento contiene la posición p' del marco que contiene a la página p (la posibilidad de que la p-ésima página no se encuentre en la memoria principal se abordará dentro de un momento). El número de palabra, w, se suma a p' para obtener la dirección buscada (ver la figura 10).
La transformación de direcciones consiste, pues, en:
f(a) = f(p, w) = p' + w
donde la dirección de programa, a, el número de página, p, y el número de palabra, w, están relacionados con el tamaño de página Z a través de:
p = parte entera de (a/Z)
w = resto de (a/Z)
Así pues, cada vez que la CPU genere una dirección de memoria ésta es transformada por una unidad hardware, de forma que en el bus del sistema se introduce la dirección física correspondiente. Es importante observar que la paginación es en sí misma una forma de reubicación dinámica. Cada dirección lógica es transformada en alguna dirección física por el hardware de paginación. Observe también que si el tamaño de página (como es lo usual) es una potencia de dos, el hardware no precisa realizar ninguna división, simplemente sabe que los últimos n bits, si el tamaño de página es de 2n, representan el desplazamiento, y los primeros bits la página.
Cada proceso debe tener su propia tabla de páginas, y su dirección de comienzo en la memoria principal forma parte de la porción del PCB utilizada para realizar un cambio de proceso.
Como el número de marcos (cantidad de memoria real) asignados a un proceso será normalmente menor que el número de páginas que éste utiliza, es muy posible que una dirección del programa haga referencia a una página que no se encuentre en aquel momento en la memoria principal. En este caso el elemento correspondiente de la tabla de páginas estará vacío, provocando el hardware una interrupción de "fallo de página" si se intenta acceder a ella. Esta interrupción provoca que el control pase al software (al sistema operativo), para que éste inicie la transferencia de la página que falta desde la memoria secundaria a la memoria principal, y actualice de acuerdo con ello la tabla de páginas. El proceso en ejecución se hará no listo hasta que se haya completado esta transferencia. La posición de las páginas en la memoria secundaria puede guardarse en una tabla separada o en la misma tabla de páginas. En este último caso, es necesario un "bit de presencia" en cada elemento de la tabla de páginas, para indicar si la página se encuentra presente o no en la memoria principal, y si el campo de direcciones debe interpretarse como una dirección de marco, o bien como una dirección de la memoria secundaria.
Si no existe ningún marco vacío en el momento en que ocurre un fallo de página, hay que guardar en la memoria secundaria alguna otra página con el fin de hacer sitio a la nueva. La elección de la página que habrá que sacar es el resultado de un algoritmo de reemplazo de página, del cual veremos varios ejemplos en el tema siguiente. Por el momento, vamos a destacar tan sólo el hecho de que la información que necesita el algoritmo de cambio de página, puede estar contenida en algunos bits adicionales que se añaden a cada elemento de la tabla de páginas.
Quizás habría que aclarar, que toda la operación de transformaciones de direcciones la lleva a cabo el hardware, excepto en el caso en que haya que traer una página de la memoria secundaria. En este caso, la aplicación del algoritmo de cambio de página, así como la actualización de la tabla de páginas, las lleva a cabo el software.
La anterior discusión proporciona una visión general de cómo funciona la paginación. En la práctica hay que hacer una serie de modificaciones para llegar a una implementación viable. Una de ellas es que la transformación de dirección virtual a física debe ser rápida.
11.5.2.1 Memoria asociativa
En el sistema que hemos descrito el tiempo necesario para cada referencia a memoria queda doblado, debido a la necesidad de acceder primero a la tabla de páginas. Una forma de evitarlo podría ser la de tener guardada la tabla de páginas en un conjunto de registros rápidos en lugar de sobre la memoria ordinaria. Sin embargo, el tamaño de la tabla de páginas es proporcional al tamaño del espacio de direcciones virtuales; de ahí que el número de registros necesarios sea demasiado grande para que esta alternativa resulte económicamente viable. La solución al problema consiste en adoptar una técnica diferente para acceder a las páginas activas. Esta técnica representa el tener que incorporar a la máquina una memoria asociativa, que consistirá en un pequeño conjunto de registros de dirección de página (PARs, del inglés page address registers), cada uno de los cuales contiene el número de página de una página activa. Los PARs presentan la propiedad de poderse buscar en ellos de forma simultánea el número de página asociado a una dirección de programa en particular.
Por ejemplo, en la figura 6.11, la dirección de programa 3243 se divide en el número de página 3 y el número de palabra 243 (vamos a suponer, por comodidad, que el tamaño de la página sea 1000). El número de página se compara entonces de forma simultánea con el contenido de todos los PARs, y se encuentra que coincide con el valor del PAR 5. Ello indica que la página 3 ocupa en la actualidad la página física número 5, de forma que la dirección buscada será la 5243.
El empleo de un almacenamiento de tipo asociativo reduce el tiempo empleado en la transformación de direcciones en un orden de magnitud con respecto al caso en el que se guardaba la tabla de páginas sobre memoria principal.
Con el fin de que se pueda hacer referencia a todas las páginas activas a través de un PAR, hay que disponer de tantos como marcos haya en la memoria. Ello es posible en sistemas con una memoria principal reducida (como por ejemplo, el Atlas), pero en sistemas mayores no es viable, desde el punto de vista económico, disponer de todos los PARs necesarios para ello (aunque es de esperar que estos argumentos de tipo económico cambien a medida que se desarrolla la tecnología). Se puede llegar a una solución de compromiso, guardando para cada proceso una tabla de páginas completa en la memoria, y utilizando una pequeña memoria asociativa para referenciar unas pocas páginas asociadas a los procesos activos más recientes. En este caso, el marco al que hará referencia cada PAR, no vendrá implícito por la situación de éste, sino que deberá incluirse como un campo adicional en el mismo PAR. El hardware de direccionamiento de la memoria lleva a cabo, entonces, la operación de transformación de direcciones que se muestra en la figura 6.12. Como antes, sólo se requiere la intervención del software en el caso de que haya que sustituir una página.
Un problema que no ilustra la figura 6.11 es el de distinguir en la memoria asociativa las páginas asociadas al proceso en ejecución de las páginas correspondientes a otros procesos. Una solución consistiría en ampliar los PARs para incluir la identificación de los procesos, junto con el número de la página. Cada dirección que se presente a la memoria asociativa deberá incluir, según esto, el identificador del proceso junto con los bits de la página.
Evidentemente, es de desear que la memoria asociativa contenga los números de las páginas a las que haya mayores posibilidades de acceder. Lamentablemente, no existe ningún algoritmo general que nos asegure que así suceda (véase el siguiente tema). En la práctica se cargan cíclicamente en la memoria asociativa las direcciones de las páginas a las que se ha hecho referencia con más frecuencia recientemente. Este algoritmo, más bien primitivo, es, de hecho, bastante eficaz.
El porcentaje de veces que se encuentra un número de página entre los registros asociativos está relacionado claramente con el número de registros asociativos. Con 8 o 16 registros asociativos, puede obtenerse un porcentaje del 80 al 90%. Un porcentaje del 80% significa que el 80% de las veces encontramos el número de página deseado entre los registros asociativos. Si explorar los registros asociativos lleva 50 nanosegundos, y 750 nanosegundos acceder a memoria, entonces un acceso a memoria "mapeada" lleva 800 nanosegundos cuando el número de página se encuentra en los registros asociativos. Si no conseguimos encontrar el número de página (50 ns), entonces tenemos que acceder a la memoria en primer lugar para buscar el número de marco en la tabla de páginas (750 ns) y entonces acceder a la palabra deseada en memoria (750 ns), dando en total 1550 nanosegundos. Para encontrar el tiempo efectivo de acceso a memoria, tenemos que ponderar cada caso con su probabilidad:
t. efectivo de acceso a memoria = 0,80 x 800 + 0,20 x 1550 = 950 ns
En este ejemplo, sufrimos un 26,6% de retardo en el tiempo de acceso a memoria (de 750 a 950 nanosegundos).
11.5.2.2 Páginas compartidas
Otra ventaja de la paginación es la posibilidad de compartir programas de uso corriente. Esto es particularmente importante en un entorno de tiempo compartido. Consideremos un sistema que soporta 40 usuarios, cada uno de los cuales ejecuta un editor de textos. Si el editor de textos consta de 30K de código y 5K de espacio para datos, necesitaríamos 1400K para permitir a los 40 usuarios. No obstante, si el programa es reentrante, podría compartirse como se muestra en la figura 6.13. Aquí vemos un editor de tres páginas que es compartido por tres procesos. Cada proceso tiene su propia página de datos
El código reentrante (también llamado código puro) es un código no automodificable. Si el código es reentrante, entonces nunca cambia durante la ejecución. Así, dos o más procesos pueden ejecutar el mismo código al mismo tiempo. Cada proceso, para su ejecución, tiene su PCB y su memoria para mantener los datos. Por supuesto, los datos de todos esos procesos diferentes varían para cada uno de ellos.
Tan sólo hace falta mantener una copia del editor en la memoria física. Cada tabla de páginas de usuario-proceso hace referencia a la misma copia física del editor, pero las páginas de datos lo hacen a marcos diferentes. Así, para permitir 40 usuarios, precisamos solamente una copia del editor, 30K, más 40 copias del espacio de 5K por usuario. El espacio total requerido es ahora de 230K, en lugar de 1400K, un ahorro significativo.
También pueden compartirse otros programas muy utilizados: compiladores, ensambladores, sistemas de bases de datos, etc. Para que sea compartible, el código tiene que ser reentrante (no automodificable). Este término significa que nunca debería darse una tentativa de almacenar algo en el código, que es de sólo búsqueda o sólo lectura. Obviamente, es crucial que las páginas compartidas sean inamovibles. Si un usuario cambiara una posición, cambiaría para todos los usuarios. La naturaleza de sólo lectura del código compartido no debería dejarse a merced de la corrección del código. El sistema operativo debe reforzar esa propiedad.
11.5.2.3 Protección
La protección de la memoria en un entorno paginado se consigue por medio de unos bits de protección asociados a cada página. Normalmente estos bits se mantienen en la tabla de páginas. Un bit puede definir que una página sea de lectura/escritura o de sólo lectura. Cada referencia a memoria pasa a través de la tabla de páginas para encontrar el número de marco correcto. Al tiempo que se calcula la dirección física, pueden verificarse los bits de protección para asegurar que no se escribe sobre una página de sólo lectura. Una tentativa de escribir sobre una página de sólo lectura ocasiona una excepción hardware al sistema operativo (por violación de acceso a una zona de la memoria principal).
Esta concepción de la protección puede ser extendida fácilmente para obtener una protección más detallada. Podemos disponer de hardware que ofrezca protección de sólo lectura, lectura-escritura o sólo ejecución. O bien, por medio de bits de protección independientes para cada tipo de acceso, puede permitirse cualquier combinación de estos accesos, al tiempo que las tentativas ilegales generan una excepción al sistema operativo.
11.5.2.4 Dos visiones de la memoria
Un aspecto muy importante de la paginación es la clara separación entre la visión de la memoria que tiene el usuario y la memoria física real. El programa de usuario cree que la memoria es un espacio contiguo, conteniendo solamente ese único programa. En realidad, el programa de usuario está disperso por la memoria física, que también contiene otros programas. La diferencia que existe entre la visión que el usuario tiene de la memoria y la memoria física real se salva por medio del hardware de traducción de direcciones o de transformación (mapping). El hardware de transformación traduce las direcciones lógicas en direcciones físicas. Esta operación permanece oculta al usuario, y la controla el sistema operativo.
Un resultado de la distinción entre direcciones físicas y lógicas es que de hecho pueden no ser iguales. Por ejemplo, en el XDS-940, una dirección lógica es de 14 bits y una dirección física es de 16 bits. Un número de página de 3 bits se usa como índice en la tabla de páginas para seleccionar un número de marco de 5 bits. Así, puede haber hasta 4 veces más memoria física que la que un usuario puede direccionar.
Esta técnica fue adoptada en particular por los fabricantes de miniordenadores. Muchos miniordenadores fueron diseñados en los años 60, cuando la memoria era cara y los programas tenían que ser pequeños. De esta manera las direcciones estaban limitadas a 15 o 16 bits. Con la disponibilidad de la memoria de semiconductores, más barata, se hizo factible aumentar la memoria física de estos miniordenadores. Pero incrementar el tamaño de la dirección para obtener direcciones de 17 o 18 bits, precisas para la memoria física aumentada, significaba, o bien rediseñar el conjunto de instrucciones, o bien extender el tamaño de palabra para acomodar los bits extra. Cualquier solución implicaría un cambio importante, invalidando todos los programas y documentación existentes. La solución que adoptaron la mayoría de los fabricantes fue el mapping de memoria. Las direcciones lógicas (15 o 16 bits), se transforman en direcciones físicas (17 o 18 bits). Multiprogramando el sistema, puede utilizarse toda la memoria. Sin embargo, los usuarios individuales no pueden emplear más memoria que antes, puesto que el espacio para la dirección lógica no ha sido incrementado. No obstante, hay que tener claro que en los sistemas actuales el rango de direcciones virtuales suele ser muy superior al rango de direcciones reales.
El sistema operativo controla esta transformación, y puede activarla para el usuario y desactivarla para el sistema operativo. Puesto que el sistema operativo gestiona memoria física, tiene que estar al tanto de la memoria física: qué marcos están asignados, qué marcos están disponibles, cuántos marcos hay en total, etc. Esta información se mantiene generalmente en una estructura denominada tabla de marcos. La tabla de marcos tiene una entrada para cada marco, que indica si está libre o asignado y, si está asignado, a qué página de qué proceso.
Además, el sistema operativo tiene que conocer qué procesos de usuario operan en el espacio de usuario, y tiene que transformar todas las direcciones lógicas para generar direcciones físicas. Si un usuario realiza una llamada al sistema (para realizar E/S) y da una dirección como parámetro (por ejemplo, un buffer), esa dirección tiene que ser traducida para generar la dirección física correcta. El sistema operativo puede utilizar la dirección de la tabla de páginas del proceso (que se guarda en su descriptor o PCB) para traducir las direcciones lógicas en físicas siempre que tenga que realizar por él mismo la operación.
11.5.3 Segmentación
Un aspecto importante de la gestión de la memoria que la paginación convierte en inevitable es la separación de la visión que el usuario tiene de la memoria y la memoria física real. La visión del usuario no coincide con la memoria física real. La visión del usuario se transforma en la memoria física. La traducción de direcciones permite esta diferencia entre la memoria lógica y la física.
11.5.3.1 Visión del usuario de la memoria
¿Cuál es la visión de la memoria que tiene el usuario ? Concibe el usuario la memoria como una tabla lineal de palabras, algunas de las cuales contienen instrucciones mientras que otras contienen datos, o bien se prefiere alguna otra visión de la memoria ? Hay un acuerdo general en que el usuario o programador de un sistema no piensa en la memoria como una tabla lineal de palabras. Más bien prefieren concebirla como una colección de segmentos de longitud variable, no necesariamente ordenados (fig. 6.14).
Consideremos cómo ve usted un programa cuando lo está escribiendo. Piensa en él como un programa principal, con un conjunto de subrutinas, procedimientos, funciones o módulos. También puede haber diversas estructuras de datos: tablas, matrices, pilas, variables, etc. Cada uno de estos módulos o elementos de datos se referencian por un nombre. Usted habla de la "tabla de símbolos", A "la función Sqrt", "el programa principal", sin tener en cuenta qué direcciones de memoria ocupan estos elementos. Usted no se preocupa de si la tabla de símbolos se almacena antes o después de la función Sqrt. Cada uno de estos elementos es de longitud variable; la longitud está definida intrínsecamente por el propósito del segmento en el programa. Los elementos dentro de un segmento están identificados por su desplazamiento desde el principio del segmento: la primera instrucción del programa, la decimoséptima entrada de la tabla de símbolos la quinta función Sqrt, etc.
La segmentación es un esquema de administración de la memoria que soporta la visión que el usuario tiene de la misma. Un espacio de direcciones lógicas es una colección de segmentos. Cada segmento tiene un nombre y una longitud. Las direcciones especifican tanto el nombre del segmento como el desplazamiento dentro del segmento. Por lo tanto, el usuario especifica cada dirección mediante dos cantidades: un nombre de segmento y un desplazamiento. (Compárese este esquema con la paginación, donde el usuario especificaba solamente una única dirección, que el hardware particionaba en número de página y desplazamiento, siendo todo ello invisible al programador).
Por simplicidad de implementación, los segmentos están numerados y se referencian por un número de segmento en lugar de por un nombre. Normalmente el programa de usuario se ensambla (o compila), y el ensamblador (o el compilador) construye automáticamente segmentos que reflejan el programa de entrada. Un compilador de Pascal podría crear segmentos separados para (1) las variables globales, (2) la pila de llamada de procedimientos, para almacenar parámetros y devolver direcciones, (3) el código de cada procedimiento o función, y (4) las variables locales de cada procedimiento y función. El cargador tomaría todos esos segmentos y les asignaría números de segmento.
11.5.3.2 Hardware
Aunque el usuario ahora puede referenciar los objetos del programa por medio de una dirección de dos dimensiones, la memoria física real es todavía, por supuesto, una secuencia unidimensional de palabras. La transformación se efectúa por medio de una tabla de segmentos.
El empleo de una tabla de segmentos se muestra en la figura 6.15. Una dirección lógica consta de dos partes: un número de segmento s y un desplazamiento dentro de ese segmento, d. El número de segmento se utiliza como un índice en la tabla de segmentos. Cada entrada de la tabla de segmentos tiene una base de segmento y un límite. El desplazamiento d de la dirección lógica tiene que estar comprendido entre 0 y el límite de segmento. En caso contrario se produce una excepción al sistema operativo (tentativa de direccionamiento lógico más allá del fin de segmento). Si este desplazamiento es legal, se añade a la base para producir la dirección de la tabla deseada en la memoria física. La tabla de segmentos es así esencialmente una matriz de pares registros base/límite.
11.5.3.3 Implementación de tablas de segmentos
Al igual que la tabla de páginas, la tabla de segmentos puede situarse bien en registros rápidos o bien en memoria. Una tabla de segmentos mantenida en registros puede ser referenciada muy rápidamente: la adición a la base y la comparación con el límite pueden realizarse simultáneamente para ahorrar tiempo. El PDP-11/45 utiliza este método; tiene 8 registros de segmento. Una dirección de 16 bits se forma a partir de un número de segmento de 3 bits y de un desplazamiento de 13 bits. Esta disposición permite hasta 8 segmentos; cada segmento puede ser de hasta 8 K-bytes. Cada entrada en la tabla de segmentos tiene una dirección base, una longitud y un conjunto de bits de control de acceso que especifican acceso denegado, acceso de sólo lectura, o acceso de lectura/escritura al segmento.
El Burroughs B5500 permitía 32 segmentos de hasta 1024 palabras cada uno. Estas especificaciones definían un número de segmento de 5 bits y un desplazamiento de 10 bits. Sin embargo, la experiencia con este sistema mostró que los segmentos eran pocos y que el límite del tamaño del segmento era demasiado pequeño (las tablas mayores de 1K tenían que fragmentarse entre varios segmentos). Por ello, el GE 645 utilizado por Multics permite hasta 256 K-segmentos de hasta 64 K-palabras.
Con tantos segmentos no es factible mantener la tabla de segmentos en registros, de modo que tiene que mantenerse en memoria. Un registro de base de tabla de segmentos (STBR) apunta a la tabla de segmentos. Puesto que el número de segmentos utilizado por un programa puede variar ampliamente, también se utiliza un registro de longitud de tabla de segmentos (STLR). En el caso de una dirección lógica (s, d) verificamos primero que el número de segmento s es legal (s < STLR), Entonces, añadimos el número de segmento al STBR resultando la dirección en memoria de la entrada de la tabla de segmentos (STBR + s). Esta entrada se lee en la memoria y actuamos igual que antes: se verifica el desplazamiento frente a la longitud de segmento, y se calcula la dirección física de la palabra deseada como la suma de la base del segmento y el desplazamiento.
Igual que con la paginación, esta transformación requiere dos referencias a memoria por dirección lógica, el ordenador disminuirá su velocidad en un factor de 2, a menos que se haga algo para evitarlo. La solución normal consiste en utilizar un conjunto de registros asociativos para mantener las entradas utilizadas más recientemente en la tabla de segmentos. Un conjunto de registros asociativos relativamente pequeño (8 \ 16) puede reducir generalmente el retardo a los accesos a memoria hasta no más allá de un 10% o 15% más lentos que los accesos a memoria "mapeada".
11.5.3.4 Compartición y protección
Una ventaja importante de la segmentación es la asociación de la protección con los segmentos. Puesto que los segmentos representan una porción del programa definida semánticamente, es probable que todas las entradas en el segmento se utilicen de la misma manera. De ahí que tengamos algunos segmentos que son instrucciones, mientras que otros son datos. En una arquitectura moderna las instrucciones son no automodificables, de modo que los segmentos de instrucciones pueden definirse como de sólo lectura o sólo ejecución. El hardware verificará los bits de protección asociados a cada entrada en la tabla de segmentos para impedir accesos ilegales a memoria, tales como tentativas de escribir en un segmento de sólo lectura o de utilizar un segmento de sólo ejecución como datos. Situando una tabla en un segmento propio, el hardware verificará automáticamente que toda indexación en la tabla es legal, y no sobrepasa los límites de la misma. Así, muchos errores frecuentes en programas serán detectados por hardware antes de que puedan ocasionar un daño serio.
Otra ventaja de la segmentación está relacionada con la compartición de código y datos. Los segmentos se comparten cuando las entradas en las tablas de segmentos de dos procesos diferentes apuntan a las mismas posiciones físicas.
La compartición se produce a nivel de segmento. Por lo tanto, cualquier información puede compartirse definiéndole un segmento. Pueden compartirse varios segmentos, de modo que es posible compartir un programa compuesto de más de un segmento.
Por ejemplo, consideremos el uso de un editor de textos en un sistema de tiempo compartido. Un editor completo podría resultar bastante largo, y formado por muchos segmentos. Estos segmentos pueden compartirse entre todos los usuarios, limitando la memoria física necesaria para soportar las tareas de edición. En lugar de necesitar n copias del editor, precisamos solamente una. Aún necesitamos segmentos únicos e independientes para almacenar las variables locales de cada usuario. Estos segmentos, por supuesto, no deben ser compartidos.
También es posible compartir solo partes de programas. Por ejemplo, subrutinas de uso frecuente pueden compartirse entre muchos usuarios definiéndolas como segmentos de sólo lectura compartibles. Por ejemplo, dos programas Fortran pueden utilizar la misma subrutina Sqrt, pero sólo será precisa una copia física de la rutina Sqrt.
Aunque esta compartición parece ser bastante sencilla, tiene algunas sutilezas. Típicamente, los segmentos de código tienen referencias a sí mismos. Por ejemplo, un salto condicional tiene normalmente una dirección de transferencia. La dirección de transferencia es un nombre de segmento y un desplazamiento. El número de segmento de la dirección de transferencia será el del segmento de código. Si tratamos de compartir este segmento, todos los procesos que lo compartan tienen que definir el segmento de código compartido con el mismo número de segmento.
Por ejemplo, si queremos compartir la rutina Sqrt y un proceso quiere definirla como segmento 4 y otro lo hace como segmento 17, ¿cómo podría la subrutina Sqrt referenciarse a sí misma? Puesto que solamente hay una copia física de Sqrt, tiene que referenciarse a sí misma de la misma manera para ambos usuarios: tiene que tener un número de segmento único. A medida que crece el número de usuarios que comparten el segmento, también crece la dificultad de encontrar un número de segmento aceptable.
Los segmentos de datos de sólo lectura (sin punteros) pueden compartirse aún usando números de segmento diferentes; lo mismo puede hacerse con segmentos de código que no se referencian directamente a sí mismos, sino sólo indirectamente. Por ejemplo, la bifurcación condicional que especifica la dirección de desplazamiento a partir del valor actual del contador de programa o respecto a un registro que contiene el número de segmento actual, permite que el código no tenga que realizar una referencia al número de segmento actual.
El ordenador GE 645 utilizado con Multics tenía 4 registros que contenían los números de segmento del segmento actual, del segmento de pila, del segmento de enlace y de un segmento de datos. Los programas pocas veces hacen referencia directamente a un número de segmento, sino siempre indirectamente a través de estos cuatro registros de segmento. Esto permite que el código pueda compartirse libremente.
11.5.3.5 Fragmentación
El sistema operativo tiene que encontrar y asignar memoria para todos los segmentos de un programa de usuario. Esta situación es similar a la paginación, excepto en el hecho de que los segmentos son de longitud variable; las páginas son todas del mismo tamaño. Por tanto, como en el caso de las particiones dinámicas, la asignación de memoria es un problema de asignación dinámica de almacenamiento, resuelto probablemente mediante un algoritmo del mejor o primer ajuste.
La segmentación puede ocasionar entonces fragmentación externa, cuando todos los bloques libres de memoria son demasiado pequeños para acomodar a un segmento. En este caso, el proceso puede simplemente verse obligado a esperar hasta que haya disponible más memoria (o al menos huecos más grandes), o puede utilizarse la compactación para crear huecos mayores. Puesto que la segmentación es por naturaleza un algoritmo de reubicación dinámica, podemos compactar la memoria siempre que queramos.
¿ En qué medida es mala la fragmentación externa en un esquema de segmentación ? La respuesta a estas preguntas depende principalmente deltamaño medio de segmento. En un extremo, se podría definir cada proceso como un segmento; este esquema es el de las particiones dinámicas. En el otro extremo, cada palabra podría situarse en su propio segmento y reubicarse por separado. Esta disposición elimina la fragmentación externa. Si el tamaño medio de segmento es pequeño, la fragmentación externa también será pequeña. (Por analogía, consideremos la colocación de las maletas en el maletero de un coche; parece que nunca encajan bien. Sin embargo, si se abren las maletas y se colocan en el maletero los objetos sueltos, todo encaja). Puesto que los segmentos individuales son más pequeños que el proceso en conjunto, es más probable que encajen en los bloques de memoria disponibles.
11.5.4 Segmentación paginada
Tanto la paginación como la segmentación tienen sus ventajas y desventajas. También es posible combinar estos dos esquemas para mejorar ambos. Veamos como ejemplo el esquema del ordenador GE 645 con el sistema operativo Multics. Las direcciones lógicas estaban formadas a partir de un número de segmento de 18 bits y un desplazamiento de 16 bits. Aunque este esquema crea un espacio de direcciones correspondiente a una dirección de 34 bits, la tabla de segmentos tiene un tamaño tolerable, puesto que el número variable de segmentos conduce naturalmente al uso de un Registro de Longitud de Tabla de Segmentos. Necesitamos tan solo el mismo número de entradas en la tabla de segmentos que segmentos; no tenemos por qué tener entradas vacías en la tabla de segmentos.
No obstante, con segmentos de 64 K-palabras, el tamaño medio de segmento podría resultar bastante grande y la fragmentación externa constituir un problema. Incluso si la fragmentación externa no es significativa, el tiempo de búsqueda para asignar un segmento, utilizando un primer o mejor ajuste, podría ser grande. De esta manera se podría desperdiciar memoria a causa de la fragmentación externa o bien desperdiciar tiempo debido a la búsqueda larga, o bien ambas cosas.
La solución adoptada fue paginar los segmentos. La paginación elimina la fragmentación interna y convierte en trivial el problema de la asignación: cualquier marco vacío puede utilizarse para una página. Obsérvese que la diferencia entre esta solución y la segmentación pura es que la entrada en la tabla de segmentos no contiene la dirección de la base del segmento, sino la dirección de la base de una tabla de páginas para ese segmento. El desplazamiento del segmento se fragmenta entonces en un número de página de 6 bits y un desplazamiento de página de 10 bits. El número de página indexa en la tabla de páginas para dar el número de marco. Finalmente, el número de marco se combina con el desplazamiento de página para formar la dirección física.
Fig.: Acceso a un sistema de memoria Segmentado Paginado.
Ahora debemos tener una tabla de páginas independiente para cada segmento. No obstante, puesto que cada segmento tiene una longitud limitada por su entrada en la tabla de segmentos, la tabla de páginas no tiene por qué tener su tamaño máximo. Sólo precisa tantas entradas como se necesiten realmente. Además, generalmente la última página de cada segmento no estará totalmente llena. De este modo tendremos, por término medio, media página de fragmentación interna por segmento. Consecuentemente, aunque hemos eliminado la fragmentación externa, hemos introducido fragmentación interna e incrementado la sobrecarga de espacio de la tabla.
A decir verdad, incluso la visión de paginación segmentada de Multics que acabamos de presentar es simplista. Puesto que el número de segmento es una cantidad de 18 bits, podríamos tener 262144 segmentos, con lo que precisaríamos una tabla de segmentos muy larga. Para simplificar este problema, Multics pagina la tabla de segmentos. De esta manera, en general, una dirección en Multics utiliza un número de segmento para definir un índice de página en una tabla de páginas para la tabla de segmentos. A partir de esta entrada, localiza la parte de la tabla de segmentos que tiene la entrada para ese segmento. La entrada en la tabla de segmentos apunta a una tabla de páginas para ese segmento, que especifica el marco que contiene la palabra deseada.
Leer Mas......
PROFESOR:LIC. ULISES BARRADAS.
ALUMNOS:TAYDE A. JIMÉNEZ VELÁZQUEZ, MARIO SILVA RODRIGUREZ.
FECHA DE ENTREGA:22 DE MAYO DEL 2010.
VIDEOS RELACIONADOS
descarga archivo en word
UNIDAD 1 “INTRODUCCION A LOS SISTEMAS OPERATIVOS”
1.0 CONCEPTO DE SISTEMA OPERATIVO……………………………………..5
1.1 sistema operativo ……………………………………………….…………………..5
1.1.1 llamadas al sistema……………………………………………….........................5
1.1.2 intérprete de comandos…………………………………………...........................5
1.1.3 núcleo (o kernel)………………………………………………….........................5
1.1.4 programas del sistema…………………………………………….........................5
1.2 programas de aplicación………………………………………….………………..5
1.3 resumen ( sistema operativo) ………………………………………………………6
2.0 TIPOS DE SISTEMAS OPERATIVOS……………………………………….....6
3.0 ESTRUCTURA BASICA DE UN SISTEMA OPERATIVO…………………...6
3.1 cargador………………………………………………………………………..……6
3.1.1 cargador para el sistema operativo………………………………………….……6
3.1.2 cargador incluido en el sistema operativo………………………………….…….6
3.2 supervisor (ejecutivo o monitor)……………………………………………….…..7
3.3 lenguaje de comunicación……………………………………………………….…7
3.4 utileria de sistema……………………………………………………………….….7
4.0 FUNCIONES BASICAS DE UN SISTEMA OPERATIVO…………………....7
4.1 programas de control……………………………………………………………....7
4.1.1 administracion de trabajos…………………………………………………….….7
4.1.2 administracion de recursos…………………………………………………….…7
4.1.3 control de operaciones de entrada y salida…………………………………….…7
4.1.4 administracion de la memoria……………………………………………………7
4.1.5 recuperacion de errores…………………………………………………………..7
4.1.6 programas de proceso…………………………………………………………….8
4.1.6.1 utilerias del sistema…………………………………………………………...8
4.1.6.2 utilerias para archivos………………………………………………………...8
4.1.6.3 utilerias independientes……………………………………………………....8
4.2 TIPOS DE SISTEMA OPERATIVO……………………………………………..8
5.0 ESTRUCTURAS DE SISTEMAS OPERATIVOS ……………………..……8
5.1 la estructura del sistema operativo dos ……………………………………..…8
5.3 estructura del sistema operativo os/2…………………………………………..….9
5.4 estructura del sistema operativo novell – netware………………………………..10
5.5 estructura del sistema operativo windows 95…………………………………….10
5.6 estructura del sistema operativo windows nt…………………………………..…10
6.0 HISTORIA DE LOS SISTEMAS OPERATIVOS …………………….…….11
6.1 historia del sistema operativo ms-dos …………………………………………….11
6.2 historia del sistema operativo unix ……………………………………………….12
6.3 historia del sistema operativo netware de novell………………………………….14
7.0 HARDWARE, SOFTWARE Y FIRMWARE………………………………..14
7.1 hardware………………………………………………………………………….14
7.1.1 placa base o placa madre……………………………………………………….14
7.1.2 grupos de hardware…………………………………………………………….14
7.1.3 dispositivos de entrada………………………………………………………....15
7.1.4 chipset (circuito integrado auxiliar)……………………………………………15
7.1.5 unidad central de procesamiento (cpu)………………………………………....15
7.1.6 unidad de control………………………………………..……………………..15
7.1.7 unidad aritmético-lógica………………………………………….……………15
7.1.8 unidad de almacenamiento…………………………………………………….15
7.1.9 memoria principal o primaria (ram – rom)……………………………………16
7.1.10 memoria secundaria (disco duro, disco flexibles, etc.)………………………16
7.1.11 dispositivos de salida…………………………………………………………16
7.2 software……………………………………………………………………….…16
7.2.2 sistema operativo………………………………………………………………17
7.2.3 controladores de dispositivos……………………………………………….…17
7.2.4 programas utilitarios……………………………………………………..…….17
7.2.5 software de aplicación…………………………………………..…………….17
7.2.6 software de programación…………………………………………..…………17
7.3 firmware………………………………………………………………………….18
UNIDAD 2 “ADMINISTRACION DE PROCESOS”
8.0 DEFINICIÓN Y CONTROL DE PROCESOS………………………………19
8.1 ¿ qué es un proceso ?............................................................................................19
8.2 estados de un proceso y transiciones de estado de los procesos …………..….19
8.3 descripción de un proceso ……………………………………………………….21
8.4 el bloque de control de proceso……………………………………………..….21
8.5 control de un proceso …………………………………………………..………24
8.5.1 modos de ejecución………………………………………………………...…24
8.5.2 cambio de proceso……………………………………………………………25
8.5.3 cambio de contexto………………………………………………………..….26
9.0 COMUNICACIÓN Y SINCRONIZACIÓN DE PROCESOS
9.1 comunicación y sincronización de procesos ……………………….……………28
9.1.1 cooperación entre procesos………………………………………………..…..28
9.1.2 competencia entre los procesos…………………………….…………………..29
9.1.3 requisitos para la exclusión mutua……………………………..………………30
9.2 utilizando memoria compartida……………………………………….…………30
9.2.1 soluciones software al problema de la exclusión mutua…………………….…31
9.2.2 soluciones hardware a la exclusión mutua ……………………..……………..40
9.3 sin utilizar memoria compartida. mensajes………………………………………41
9.4 problemas clásicos de comunicación entre procesos……………………….……45
9.4.1 el problema de la cena de los filósofos………………………….…………….45
9.4.2 el problema de los lectores y los escritores……………………………………48
9.5 un ejemplo de aplicación cliente-servidor…………………………………..….50
10.0 INTERBLOQUEOS…………………………………………………..……..57
10.4.1 Desentenderse. El Algoritmo de la Avestruz ……………..…………62
10.4.2 Prevención de Interbloqueos………………………..………………..63
10.4.3 Evitación de Interbloqueos ………………….……………………….66
10.4.4 Detección y Recuperación de Interbloqueos……………………..….71
10.4 Estrategias para Resolver Interbloqueos……………………………….74
10.5 Interbloqueos: Sistemas Actuales/Sistemas Futuros……………….…..75
UNIDAD 3
11.0 “ADMISTRACIÓN DE LA MEMORIA”
11.1 La organización y gestión de la memoria. Conceptos generales……….77
11.2 Gestión de la memoria en los sistemas monoprogramados………..…..79
11.3 Gestión de la memoria en los sistemas multiprogramados…………….80
11.4 Asignación de memoria contigua………………………………………81
11.4.1 Particiones estáticas………………………………………………….81
11.4.2 Particiones dinámicas…………………………………………………83
11.4.3 Estrategias de colocación……………….…………..………….……..86
11.4.4 Intercambio (swapping)…………………………..…………………..87
11.5 Asignación de memoria no contigua………………………….………..89
11.5.1 Esquema general de traducción ………………………….…………..91
11.5.2 Paginación ……………………………………………………....……94
11.5.2.1 Memoria asociativa…………………………………….…………..97
11.5.2.2 Páginas compartidas………………………………………………..100
11.5.2.3 Protección………………………………………………….………102
11.5.2.4 Dos visiones de la memoria……………………………….………102
11.5.3 Segmentación …………………………………………..……………103
11.5.3.1 Visión del usuario de la memoria………………………………….104
11.5.3.2 Hardware…………………………………………………………..105
11.5.3.3 Implementación de tablas de segmentos……………………………106
11.5.3.4 Compartición y protección……………………………….…………107
11.5.3.5 Fragmentación…………………………………………….………..109
11.5.4 Segmentación paginada………………………………………………110
UNIDAD 1
“INTRODUCCION A LOS SISTEMAS OPERATIVOS”
1.0 CONCEPTO DE SISTEMA OPERATIVO
Conjunto de programas que se integran con el hardware para facilitar al usuario, el aprovechamiento de los recursos disponibles. Algunos de sus objetivos principales son:
Provee de un ambiente conveniente de trabajo.
Hace uso eficiente del Hardware.
Provee de una adecuada distribución de los recursos.
Para un Sistema Operativo real deberá satisfacer las siguientes funciones:
Gobierna el Sistema.
Asigna los recursos.
Administra y controlar la ejecución de los programas.
Un sistema de computo en muchos casos cuenta con demasiados recursos para ser utilizados por un solo usuario, es en estos casos cuando se puede dar servicio a varios procesos.
1.1 Sistema Operativo
1.1.1 Llamadas al Sistema
El Sistema Operativo en conjunto con el Hardware aparecen al usuario como un solo dispositivo con un conjunto de instrucciones más flexibles y variadas a las que se conoce como Llamadas al Sistema (System Callings).
1.1.2 Intérprete de Comandos
También conocido por su nombre en inglés, Shell, es un programa que interpreta las órdenes del usuario y las convierte en Llamadas al Sistema.
1.1.3 Núcleo (o Kernel)
Es la parte del Sistema Operativo que se encarga de sincronizar la activación de los procesos y definir prioridades.
1.1.4 Programas del Sistema
Son programas de servicio que debe ser solicitados explícitamente por los usuarios. Como ejemplos de estos tenemos:
Compiladores
Son programas que traducen Programas Fuente en programas Objeto.
Ensambladores
Traducen programas escritos con mnemónicos a lenguaje de máquina.
Editores
Son programas que permiten escribir textos y guardarlos en memoria secundaria.
Utilerías de Archivos
Programas para dar mantenimiento a los archivos.
Bibliotecas
Programas que contienen rutinas para realizar funciones frecuentemente requeridas. Estas funciones pueden ser ligadas a los programas escritos por el usuario.
1.2 Programas de Aplicación
Programas externos al sistema, utilizados para realizar tareas específicas como simulación, creación y edición de gráficas e imágenes, etc..
1.3 Resumen ( Sistema Operativo)
Es el programa o programas que tienen todas las computadoras modernas, el usuario de un equipo de computo no tiene que preocuparse de como funciona, por ejemplo, una unidad lectora de disco, sólo necesita pedirle al sistema operativo que lo lea o escriba en el disco mediante un comando. El más comúnmente usado es el MS-DOS.
Conjunto de programas que sirven como interfaz entre el usuario (Sirve como agente de intercambio de información entre la computadora y el usuario.) y la computadora, además de que administran los recursos de la misma (Entendiéndose como recursos: Memoria, Disco Duro, Procesador, Monitor, Etc.).
2.0 TIPOS DE SISTEMAS OPERATIVOS
Existen dos tipos generales de sistemas operativos: Los basados en caracteres y los de interfaz gráfica (ambientes amigables). El sistema basado en caracteres es ejemplificado perfectamente con el sistema operativo utilizado por las computadoras IBM y compatibles. El MS-DOS está listo para recibir un comando desplegando el tipo de indicador (A> o C>) en la pantalla; en donde el usuario escribe carácter por carácter el comando que se desea ejecutar.
Ante las justificadas quejas de los usuarios por la falta de programas amigables, los desarrolladores de software respondieron añadiendo menús y mensajes en pantalla. Los menús mejoran en mucho la cordialidad de los programas, reduciendo el número de comandos que se necesitan conocer.
La Macintosh logró crear la primera interfaz gráfica, posteriormente Microsoft introdujo la interfaz gráfica Windows para las computadoras IBM y compatibles.
Cada programa en Windows tiene reservada un área de la pantalla conocida con el nombre de ventana.
Un sistema operativo que se opera mediante el uso de imágenes y símbolos en vez de palabras se denomina interfaz gráfica para el usuario, o GUI (Graphic User Interface).
3.0 ESTRUCTURA BASICA DE UN SISTEMA OPERATIVO
3.1 CARGADOR
Cualquier programa que requiere ser ejecutado en la computadora, deberá ser transferido desde su lugar de residencia a la memoria principal.
3.1.1 CARGADOR PARA EL SISTEMA OPERATIVO
Este programa se encarga de transferir desde algún medio de almacenamiento externo (disco, cinta o tambor) a la memoria principal, los programas del sistema operativo que tienen como finalidad establecer el ambiente de trabajo del equipo de cómputo. Existe un programa especial almacenado en memoria ROM que se encarga de accesar a este programa cargador. Cuando el sistema operativo esta cargado en memoria toma el control absoluto de las operaciones del sistema.
3.1.2 CARGADOR INCLUIDO EN EL SISTEMA OPERATIVO
Su función es cargar a memoria todos los archivos necesarios para la ejecución de un proceso.
3.2 SUPERVISOR (EJECUTIVO O MONITOR)
Es el administrador del sistema que controla todo el proceso de la información por medio de un gran número de rutinas que entran en acción cuando son requeridos. Funge como enlace entre los programas del usuario y todas las rutinas que controlan los recursos requeridos por el programa para posteriormente continuar con su ejecución.
El supervisor también realiza otras funciones como son:
- Administra la memoria.
- Administración de las rutinas que controlan el funcionamiento de los recursos de la computadora.
- Manejo de Archivos
- Administración y control de la ejecución de los programas.
3.3 LENGUAJE DE COMUNICACION
Es el medio a través del cual el usuario interactúa directamente con el sistema operativo y esta formado por comandos que son introducidos a través de algún dispositivo. Generalmente un comando consta de dos partes, la primera formada por una palabra que identifica el comando y la acción a realizar y la segunda parte por un conjunto de valores o parámetros que permiten seleccionar diversas operaciones de entre los que dispone el comando.
3.4 UTILERIA DE SISTEMA
Son programas o rutinas del sistema operativo que realizan diversas funciones de uso común o aplicación frecuente como son: clasificar, copiar e imprimir información.
4.0 FUNCIONES BASICAS DE UN SISTEMA OPERATIVO
4.1 PROGRAMAS DE CONTROL
4.1.1 ADMINISTRACION DE TRABAJOS
Cuando existen varios programas en espera de ser procesados, el sistema operativo debe decidir el orden de procesamiento de ellos, así como asignar los recursos necesarios para su proceso.
4.1.2 ADMINISTRACION DE RECURSOS
Mediante está función el sistema operativo esta en capacidad de distribuir en forma adecuada y en el momento oportuno los diferentes recursos (memoria, dispositivos, etc.,...) entre los diversos programas que se encuentran en proceso, para esto, lleva un registro que le permite conocer que recursos están disponibles y cuales están siendo utilizados, por cuanto tiempo y por quien, etc.
4.1.3 CONTROL DE OPERACIONES DE ENTRADA Y SALIDA
Mediante esta actividad el sistema operativo decide que proceso hará uso del recurso, durante cuánto tiempo y en que momento.
4.1.4 ADMINISTRACION DE LA MEMORIA
Supervisa que áreas de memoria están en uso y cual están libre, determina cuanta memoria asignará a un proceso y en que momento, además libera la memoria cuando ya no es requerida para el proceso.
4.1.5 RECUPERACION DE ERRORES
El sistema operativo contiene rutinas que intentan evitar perder el control de una tarea cuando se suscitan errores en la trasferencia de información hacia y desde los dispositivos de entrada / salida.
4.1.6 PROGRAMAS DE PROCESO
El sistema operativo contiene programas de servicios que sirven de apoyo al procesamiento de los trabajos, se conocen también como utilerías y se pueden clasificar en tres tipos:
4.1.6.1 UTILERIAS DEL SISTEMA
Se ejecutan bajo el control del sistema operativo y se utilizan para preparar algunos recursos usados por el sistema. Son de uso interno.
4.1.6.2 UTILERIAS PARA ARCHIVOS
Manejan información de los archivos tales como imprimir, clasificar, copiar, etc.
4.1.6.3 UTILERIAS INDEPENDIENTES
Realizar funciones que se relacionan con la iniciación de dispositivos de Entrada/Salida, carga del sistema operativo, etc.
4.2 TIPOS DE SISTEMA OPERATIVO
El sistema operativo como controlador y supervisor de todas las actividades que realiza la computadora tiene características que le permiten soportar técnicas avanzadas de procesamiento de datos como:
- La utilización de Lenguaje de Alto Nivel.
- Tiempo Compartido.
- Multiprogramación.
- Memoria Virtual.
5.0 ESTRUCTURAS DE SISTEMAS OPERATIVOS
5.1 La estructura del sistema operativo DOS
Es representada en la siguiente figura:
Como puede verse en primer término, rodeando al hardware se encuentra una parte del software denominada BIOS residente en memoria de sólo lectura ROM, cuyas misiones son las siguientes:
Realizar un test de todo el equipo en cada proceso de arranque donde se examinan todos los elementos conectados y en qué estado se encuentran.
Hacer de interfaz entre el software de los niveles superiores y el hardware a través de una serie de rutinas, cada una de ellas con una misión específica.
El siguiente nivel corresponde al núcleo del sistema operativo, que permanece constantemente en la memoria desde que se enciende en el equipo. Esta compuesto por el programa intérprete de comandos (COMMAND.COM) que lleva consigo la carga de una serie de comandos residentes permanentes en memoria y dos archivos de los denominados ocultos, pues no aparecen en el directorio del disco que los contienen pero que se encuentran presentes. Estos archivos tienen rutinas que permiten ampliar y actualizar (evolución de las versiones DOS) las rutinas de la ROM-BIOS.
5.2 ESTRUCTURA DEL SISTEMA OPERATIVO UNIX
El sistema operativo UNIX es un sistema de tiempo compartido y, por tanto multiusuario, en el que existe portabilidad para la implantación en distintas computadoras.
Esta formado por una serie de elementos que pueden representarse en esta fo rma de capas concentricas donde, en primer lugar, alrededor del hardware de la máquina se encuentran el núcleo (kernel), que interactuán directamente con el hardware, aislando a este de los usuarios, además de adaptar el resto del sistema operativo a la máquina debido a la portabilidad que existe en el mismo.
En una segunda capa se encuentran los comandos, que no son otra cosa que el interface entre los programas de aplicación y el núcleo del sistema operativo. La última de las capas contiene los programas de aplicación.
5.3 ESTRUCTURA DEL SISTEMA OPERATIVO OS/2
El sistema operativo OS/2 al trabajar en modo real para la ejecución del programa DOS ya existentes, deja libertad al proceso para acceder a la memoria, utilizar dispositivos, entre otros.
El modo protegido para los programas de OS/2 en el que varios de ellos pueden estar coexistiendo en la memoria y compartiendo recursos del sistema, tiene una estructura a través de la cual el propio sistema ejerce el control de los procesos.
Para que exista compatibilidad con el software DOS, el sistema OS/2 posee dos modos de ejecución de sus programas:
Proceso en modo real. En el una computadora puede acceder al hardware directamente, realizar operaciones de entrada/salida de bajo nivel y controlar todos los recursos de la computadora, no existiendo interferencias entre un programa y otro, es decir se ejecuta un solo programa.
Proceso en modo protegido. Es el modo que permite la ejecución de programas en multiprogramación o multitarea.
El sistema operativo OS/2 precisa una configuración mínima del hardware para su funcionamiento. Las nuevas incorporaciones del OS/2 frente al DOS se encuentran en aspectos relacionados con:
Multiprogramación o Multitarea.
Gestión de memoria virtual.
Utilización de dispositivos virtuales.
Comunicación entre procesos concurrentes.
Interconexión en redes.
Gráficos avanzados.
Interfaz potente con el usuario.
5.4 ESTRUCTURA DEL SISTEMA OPERATIVO NOVELL - NETWARE
Novell netware, es una red Novell. Una red de área local que es controlada por alguno de los sistemas operativos Netware de Novell.
Netware, es una familia de sistemas operativos de redes Novell. Que se ejecuta desde una PC 286, 386,486; soporta a los sistemas operativos DOS, OS/2, estaciones de trabajo y una variedad de métodos de accesos de red de área local. Netware de Novell es uno de los programas de control de redes más usado.
5.5 ESTRUCTURA DEL SISTEMA OPERATIVO WINDOWS 95
Windows 95, es un sistema operativo de desarrollo abierto y gráfico, este sistema operativo se clasifica como multiusuario y multitarea, ya que permite la ejecución de procesos en forma simultánea, es decir realiza las operaciones en forma paralela. Este sistema operativo nos brinda el servicio de acceso a la información que requiere el usuario para compartir archivos desde distintas estaciones de trabajo, además de un ambiente de desarrollo Cliente-Servidor. que permite el acceso a Internet, al correo electrónico, entre otros.
El sistema operativo Windows 95 es una aplicación de 32 bits, que maneja simultáneamente aplicaciones de 16 a 32 bits.
5.6 ESTRUCTURA DEL SISTEMA OPERATIVO WINDOWS NT
La aparición de sistemas operativos de 32 bits es ya el presente. Windows NT ofrece, además, un sistema integrado de red que lo distinguirá de sus competidores y puede gestión del sistema.
El núcleo de Windows NT está enfocado para dar todo el soporte necesario y hacerlo con unos niveles de seguridad, desconocidos hasta el presente nivel de computadores personales.
Windows NT proporciona un sistema avanzado en el que se ha pretendido integrar funcionalidades tales como capacidad de conexión Peer-to-Peer, nivel de seguridad C2 o un amplio espectro de compatibilidades con redes existentes (a nivel de protocolos y adaptadores).
6.0 HISTORIA DE LOS SISTEMAS OPERATIVOS
6.1 HISTORIA DEL SISTEMA OPERATIVO MS-DOS
Con la aparición de la computadora personal de IBM en 1981, se desarrollo el sistema operativo (DOS), siendo sus creadores las empresas Microsoft Corporation e IBM. En aquel año se utilizaban dos versiones similares, una de cada empresa denominadas MS-DOS 1.0 Y PC-DOS 1.0, que permitían a los usarios del PC (computadora personal) una serie de órdenes básicas para su funcionamiento. La característica principal de estas primeras versiones era la utilización de un subsistema de archivos que ha permitido compatibilizar éstos en las sucesivas versiones así como en otros sistemas operativos como el OS/2. Otra característica de esta primera versión era la utilización de disquetes de 5.25 pulgadas de una sola cara con una capacidad de 160K.
En el año 1982, la empresa mejoró el sistema operativo permitiendo el uso de los disquetes de doble cara con una capacidad de 360K. Esta visión fue la del MS-DOS 1.25.
En 1983, las empresas Microsoft e IBM mejoran notablemente el sistema operativo dotándole de una buena gestión de archivos (aparición de subdirectorios, etc.), ampliando el conjunto de órdenes y mejorando algunos de las existentes. Las versiones surgidas en aquel año fueron 2.0, 2.01, 2.10, 2.11 y 2.25.
En el año 1984 y con la aparición del modelo PC-AT, se desarrollaron dos nuevas versiones. La DOS 3.0, que incorpora la utilización de discos de 5.25 pulgadas de alta densidad (1.4 Mbytes) y discos fijos también de gran capacidad y la versión DOS 3.1, que permite la conexión de computadoras personales bajo DOS en redes de área local y su utilización como servidores en entornos multiusuarios.
La versión DOS 3.2, aparecida en 1986, además de la mejora en cuanto a órdenes, introdujo la posibilidad de utilización de disquetes de 3.5 pulgadas tanto en baja (720K) como de alta densidad (1.2 Mbytes).
En 1987, con la aparición de otras arquitecturas de computadoras personales (80286, 80386, etc.) compatibles con las anteriores pero con importantes mejoras tecnológicas, se comercializo la versión DOS 3.3, capaz de ser implantado en la nueva serie de computadores personales PS/2 de IBM.
En 1988, aparece la versión DOS 4.X, de características superiores a las anteriores.
En 1989, se tienen versiones DOS 5.X . Actualmente se encuentran ya en el mercado la versión 6.X.
6.2 HISTORIA DEL SISTEMA OPERATIVO UNIX
1965: Las empresas Bell Telephone Laboratories y General Electric Company intervienen enm el proyecto MAC para desarrollar un nuevo sistema operativo denominado MULTICS, cuyo objetivo fue el ofrecer un sistema multiusuario de gran potencia de proceso, gran capacidad de almacenamienmto y con grandes facilidades para compartir datos entre procesos.
1969: Vistos los resultados poco satisfactorios del MULTICS, la Bell Telephone Laboratories se retira del proyecto y desarrolla un sistema de tiempo compartido con paginación por demanda para uso interno de la empresa sobre la computadora PDP-7 de Digital, siendo los artífices del mismo un equipo encabezado por Ken Thompson y Denis Ritchie. Este sistema operativo constituyó la primera versión de UNIX, que solo permitía la explotación en monoprogramación.
1971: El resultado del sistema anterior tuvo tanto éxito que la compañía puso a disposición de Thompson y Ritchie una computadora más potente, que fue la PDP-11 de Digital. En ella Thompson desarrollo el lenguaje de programación B inspirandose en el BCPL y en el FORTRAN, y a continuación Ritchie creo el lenguaje C, con el que consiguió la generación de código de máquina, descripción de tipo de datos y de estructuras.
1973: Se reescribe en C la versión de UNIX desarrollada en ensamblador y que prácticamente es la que ha mantenido hasta hoy. Aparece una versión de UNIX conocida por Programmer's Workbench (PWB).
1974: Se introduce el sistema operativo UNIX en las Universidades norteamericanas con fines educativos.
1977: Se construye la primera versión comercial del UNIX, conocida como versión 6, implantándose por primera vez en una computadora distinta de la PDP, que fue la INTERDATA 8/32.
1979: aparece la versión 7 de UNIX para PDP y una versión para la computadora VAX de digital (32 bits) conocida como 32V.
1981: Nace la primera versión de UNIX para computadoras personales con el nombre de XENIX.
1982: Para la distribución externa los laboratorios Bell desarrollan el UNIX System III, que no es más que el original con algunas pequeñas variantes. Por otra parte la Universidad de Berkeley desarrolla una variante del UNIX 32V para computadoras VAX con mejoras en cuanto a comandos y gestión de la memoria virtual paginada, denominada 4.1 BSD.
1983: La empresa AT&T anuncia una nueva versión denominada UNIX System V, que es el sistema actual y que presenta importantes mejoras de rendimiento, comunicaciones, etc.
1984: La Universidad de Brekeley presenta la versión 4.2 BSD para computadoras VAX, que también se aplica en estaciones de trabajo SUN 2/3 de SUN MICROSYSTEMS.
En la actualidad se utilizan fundamentalmente dos versiones del sistema operativo:
UNIX System V.
SCO UNIX System V.
UNIX
El Sistema Operativo Unix fue diseñado originalmente a finales de los años sesenta y principios de los años setenta por AT&T.
Su sencillez y elegancia llamaron la atención de investigadores de las universidades y la industria. UNIX ha alcanzado una posición de extraordinaria importancia, siendo el único sistema operativo que las compañías parecen dispuestas a aceptar como estándar preferido de sistema operativo. UNIX es el único sistema operativo que se ha instalado en todo tipo de computadores, desde los micro hasta los supercomputadores, y es el único sistema operativo que implanta casi todos los fabricantes importantes de computadores.
La estandarización de UNIX se ha convertido en un tema cada vez mas debatido. Parece poco probable que en el futuro surja una norma UNIX única. AT&T continua promoviendo su UNIX System, muy utilizado en la industria. Las universidades siguen prefiriendo el UNIX de Berkeley. La comunidad UNIX ha cooperado en el desarrollo de una especificación estandarizado del sistema denominado POSIX que es un subconjunto de los principales sistemas UNIX. La fundación de sistemas de Software se constituyo para producir una versión de UNIX basada en gran medida en la AIX de IBM, sistema parecido a UNIX.
Pasará muchos años antes de que aparezca un solo UNIX estandarizado, si es que se consigue alguna vez.. Tal vez no exista un diseño de sistemas opertivos capaz de satisfacer las diversas necesidades de la comunidad informática mundial.
6.4 HISTORIA DEL SISTEMA OPERATIVO NETWARE DE NOVELL
ELS Netware (Entry Level System- sistema de nivel de entrada). Fue el primer sistema de igual a igual (peer to peer) de Novell que soporta hasta ocho estaciones de trabajo y ha sido reemplazado por Netware Lite.
Netware 2.x ( el primer Netware 286 avanzado) se ejecuta en un servidor de archivos y soporta hasta 100 usuarios. Es el único programa de control en el servidor. Netware 3.x (el primer Netware 386) se ejecuta en servidores 386 y superiores y se aprovecha de 32 bits. Las versiones 3.x están disponibles de 10 a 4.000 nodos.
Netware 4.0, previsto para 1993, es de compatibilidad descendente con Netware 2.x y 3.x e incluye el servidor de nombrado NDS (Netware Directory Service - servicio de directorios Netware) que proporciona compatibilidad X.500.
SFT Netware (System Fault Tolerant-tolerante a fallos del sistema). Proporciona recuperación automática de un mal funcionamiento de la red.
Netware para VMS proporciona conectividad Netware a redes VAX, portable Netware facilita código fuente Netware para conversión a otras plataformas.
Netware Lite se ha diseñado para redes pequeñas de PC de igual a igual con migración ascendente a sistemas más grandes de Novell. El conjunto de arranque conecta dos PC.
El sistema Operativo de Red Netware 4.1, es la culminación de 12 de años de mejoramiento continuo de los standares en la industria de sistema operativos de red. El servidor Windows NT ha sido desarrollado como muchos otros: un sistema desktop o de escritorio, un servidor de aplicaciones. El servidor de Netware aventaja al de Windows NT, en 5 áreas específicas.
Netware 4.1 ofrece un servicio de directorio Netware NDS, diseñado para proporcionar un entorno administrativo centralizado, seguro y escaleable para la distribución global de la red.
7.0 HARDWARE, SOFTWARE Y FIRMWARE
7.1 Hardware
Los componentes y dispositivos del Hardware se dividen en Hardware Básico yHardware Complementario
El Hardware Básico: son las piezas fundamentales e imprescindibles para que la computadora funcione como son: Placa base, monitor, teclado y ratón.
El Hardware Complementario: son todos aquellos dispositivos adicionales no esenciales como pueden ser: impresora, escáner, cámara de vídeo digital, webcam, etc.
7.1.1 Placa Base o Placa Madre
Los componentes Hardware más importantes de la computadora y esenciales para su funcionamiento se encuentran en la Placa Base (también conocida como Placa Madre), que es una placa de circuito impreso que aloja a la Unidad Central de Procesamiento (CPU) o microprocesador, Chipset (circuito integrado auxiliar), Memoria RAM, BIOS o Flash-ROM, etc., además de comunicarlos entre sí.
7.1.2 Grupos de Hardware
Según sus funciones, los componentes y dispositivos del hardware se dividen en varios grupos y en el siguiente orden:
Dispositivos de Entrada
Chipset (Circuito Integrado Auxiliar)
Unidad Central de Procesamiento (CPU)
Unidad de Control
Unidad Aritmético-Lógica
Unidad de Almacenamiento
Memoria Principal o Primaria (RAM – ROM)
Memoria Secundaria o Auxiliar (Disco Duro, Flexible, etc.)
Dispositivos de Salida
7.1.3 Dispositivos de Entrada
Los Dispositivos de Entrada son aquellos a través de los cuales se envían datos externos a la unidad central de procesamiento, como el teclado, ratón, escáner, o micrófono, entre otros.
7.1.4 Chipset (Circuito Integrado Auxiliar)
El Chipset o Circuito Integrado Auxiliar es la médula espinal de la computadora, integrado en la placa base, hace posible que esta funcione como eje del sistema permitiendo el tráfico de información entre el microprocesador (CPU) y el resto de componentes de la placa base, interconectándolos a través de diversos buses que son: el Northbridge (Puente Norte) y el Southbridge (Puente Sur).
El Northbridge o Puente Norte es un circuito integrado que hace de puente de enlace entre el microprocesador y la memoria además de las tarjetas gráficas o de vídeo AGP o PCI-Express, así como las comunicaciones con el Puente Sur.
El Southbridge o Puente Sur (también conocido como Concentrador de Controladores de Entrada/Salida), es un circuito integrado que coordina dentro de la placa base los dispositivos de entrada y salida además de algunas otras funcionalidades de baja velocidad. El Puente Sur se comunica con la CPU a través delPuente Norte.
7.1.5 Unidad Central de Procesamiento (CPU)
La CPU (Central Processing Unit o Unidad Central de Procesamiento) puede estar compuesta por uno o varios microprocesadores de circuitos integrados que se encargan de interpretar y ejecutar instrucciones, y de administrar, coordinar y procesar datos, es en definitiva el cerebro del sistema de la computadora. además, la velocidad de la computadora depende de la velocidad de la CPU o microprocesador que se mide en Mhz (unidad de medida de la velocidad de procesamiento). Se divide en varios registros:
7.1.6 Unidad de Control
La Unidad de Control es la encargada de controlar que las instrucciones se ejecuten, buscándolas en la memoria principal, decodificándolas (interpretándolas) y que después serán ejecutadas en la unidad de proceso.
7.1.7 Unidad Aritmético-Lógica
La Unidad Aritmético-Lógica es la unidad de proceso donde se lleva a cabo la ejecución de las instrucciones con operaciones aritméticas y lógicas.
7.1.8 Unidad de Almacenamiento
La Unidad de Almacenamiento o Memoria guarda todos los datos que son procesados en la computadora y se divide en Memoria Principal y Memoria Secundaria o Auxiliar.
7.1.9 Memoria Principal o Primaria (RAM – ROM)
En la Memoria Principal o Primaria de la computadora se encuentran las memoriasRAM, ROM y CACHÉ.
La Memoria RAM (Random Access Memory o Memoria de Acceso Aleatorio) es un circuito integrado o chip que almacena los programas, datos y resultados ejecutados por la computadora y de forma temporal, pues su contenido se pierde cuando esta se apaga. Se llama de acceso aleatorio - o de acceso directo - porque se puede acceder a cualquier posición de memoria sin necesidad de seguir un orden. LaMemoria RAM puede ser leída y escrita por lo que su contenido puede ser modificado.
La Memoria ROM (Read Only Memory o Memoria de sólo lectura) viene grabada en chips con una serie de programas por el fabricante de hardware y es sólo de lectura, por lo que no puede ser modificada - al menos no muy rápida o fácilmente - y tampoco se altera por cortes de corriente. En esta memoria se almacenan los valores correspondientes a las rutinas de arranque o inicio del sistema y a su configuración.
La Memoria Caché o RAM Caché es una memoria auxiliar de alta velocidad, que no es más que una copia de acceso rápido de la memoria principal almacenada en los módulos de RAM.
7.1.10 Memoria Secundaria (Disco Duro, Disco Flexibles, etc.)
La Memoria Secundaria (también llamada Periférico de Almacenamiento) está compuesta por todos aquellos dispositivos capaces de almacenar datos en dispositivos que pueden ser internos como el disco duro, o extraíble como los discos flexibles (disquetes), CDs, DVDs, etc.
7.1.11 Dispositivos de Salida
Los Dispositivos de Salida son aquellos que reciben los datos procesados por la computadora y permiten exteriorizarlos a través de periféricos como el monitor, impresora, escáner, plotter, altavoces,etc.
Dispositivos de Entrada/Salida (Periféricos mixtos): Hay dispositivos que son tanto de entrada como de salida como los mencionados periféricos de almacenamiento, CDs, DVDs, así como módems, faxes, USBs, o tarjetas de red.
7.2 Software
El Software es el soporte lógico e inmaterial que permite que la computadora pueda desempeñar tareas inteligentes, dirigiendo a los componentes físicos o hardware con instrucciones y datos a través de diferentes tipos de programas.
El Software son los programas de aplicación y los sistemas operativos, que según las funciones que realizan pueden ser clasificados en:
Software de Sistema
Software de Aplicación
Software de Programación
7.2.1 Software de Sistema
Se llama Software de Sistema o Software de Base al conjunto de programas que sirven para interactuar con el sistema, confiriendo control sobre el hardware, además de dar soporte a otros programas.
El Software de Sistema se divide en:
Sistema Operativo
Controladores de Dispositivos
Programas Utilitarios
7.2.2 Sistema operativo
El Sistema Operativo es un conjunto de programas que administran los recursos de la computadora y controlan su funcionamiento.
Un Sistema Operativo realiza cinco funciones básicas: Suministro de Interfaz al Usuario, Administración de Recursos, Administración de Archivos, Administración de Tareas y Servicio de Soporte.
Suministro de interfaz al usuario: Permite al usuario comunicarse con la computadora por medio de interfaces que se basan en comandos, interfaces que utilizan menús, e interfaces gráficas de usuario.
Administración de recursos: Administran los recursos del hardware como la CPU, memoria, dispositivos de almacenamiento secundario y periféricos de entrada y de salida.
Administración de archivos: Controla la creación, borrado, copiado y acceso de archivos de datos y de programas.
Administración de tareas: Administra la información sobre los programas y procesos que se están ejecutando en la computadora. Puede cambiar la prioridad entre procesos, concluirlos y comprobar el uso de estos en la CPU, así como terminar programas.
Servicio de soporte: Los Servicios de Soporte de cada sistema operativo dependen de las implementaciones añadidas a este, y pueden consistir en inclusión de utilidades nuevas, actualización de versiones, mejoras de seguridad, controladores de nuevos periféricos, o corrección de errores de software.
7.2.3 Controladores de Dispositivos
Los Controladores de Dispositivos son programas que permiten a otros programa de mayor nivel como un sistema operativo interactuar con un dispositivo de hardware.
7.2.4 Programas Utilitarios
Los Programas Utilitarios realizan diversas funciones para resolver problemas específicos, además de realizar tareas en general y de mantenimiento. Algunos se incluyen en el sistema operativo.
7.2.5 Software de Aplicación
El Software de Aplicación son los programas diseñados para o por los usuarios para facilitar la realización de tareas específicas en la computadora, como pueden ser las aplicaciones ofimáticas (procesador de texto, hoja de cálculo, programa de presentación, sistema de gestión de base de datos...), u otros tipos de software especializados como software médico, software educativo, editores de música, programas de contabilidad, etc.
7.2.6 Software de Programación
El Software de Programación es el conjunto de herramientas que permiten al desarrollador informático escribir programas usando diferentes alternativas y lenguajes de programación.
Este tipo de software incluye principalmente compiladores, intérpretes, ensambladores, enlazadores, depuradores, editores de texto y un entorno de desarrollo integrado que contiene las herramientas anteriores, y normalmente cuenta una avanzada interfaz gráfica de usuario (GUI).
7.3 FIRMWARE.
Es un programa almacenado en un chip de memoria flash de un dispositivo de hardware cuya función es asegurar su correcto funcionamiento. Firmware o Programación en Firme, es un bloque de instrucciones de programa para propósitos específicos, grabado en una memoria tipo ROM, que establece la lógica de más bajo nivel que controla los circuitos electrónicos de un dispositivo de cualquier tipo. Al estar integrado en la electrónica del dispositivo es en parte hardware, pero también es software, ya que proporciona lógica y se dispone en algún tipo de lenguaje de programación. Funcionalmente, el firmware es el intermediario (interfaz) entre las órdenes externas que recibe el dispositivo y su electrónica, ya que es el encargado de controlar a ésta última para ejecutar correctamente dichas órdenes externas.
Encontramos Firmware en memorias ROM de los sistemas de diversos dispositivos
UNIDAD 2 “ADMINISTRACION DE PROCESOS”
8.0 DEFINICIÓN Y CONTROL DE PROCESOS
Los sistemas operativos multiprogramados necesitan del concepto de proceso. El sistema operativo debe entremezclar la ejecución de un número de procesos para maximizar la utilización de los recursos del ordenador. Al mismo tiempo, los sistemas de tiempo compartido deben proporcionar un tiempo de respuesta razonable. El sistema operativo debe asignar recursos a los procesos de acuerdo a una política específica (ciertas funciones o aplicaciones son de mayor prioridad), mientras impide los interbloqueos. Por último, el sistema operativo debe ofrecer un soporte para llevar a cabo la comunicación entre procesos.
El concepto de proceso es clave en los sistemas operativos modernos. La gestión del procesador mediante multiprogramación, revolucionó la concepción de los sistemas operativos, e introdujo el término proceso como elemento necesario para realizar dicha gestión. Por lo demás, este tema trata sobre la definición de proceso, el estudio de sus propiedades, y la gestión que realiza el sistema operativo para crear la abstracción de proceso, aunque esto último se completará en el tema de planificación. Por último, descubriremos que el concepto de proceso encierra, en realidad, dos características potencialmente independientes: por un lado, es una unidad a la que se le asigna y posee recursos y, por otro, es una unidad planificable. Basándonos en esta distinción emprenderemos el estudio de los threads (hebra o hilo), o también llamados procesos ligeros.
8.1 ¿ Qué es un proceso ?
Hasta ahora hemos utilizado siempre el término programa. A partir de ahora distinguiremos entre programa y proceso. Un programa es una secuencia de instrucciones escrita en un lenguaje dado. Un proceso es una instancia de ejecución de un programa, caracterizado por su contador de programa, su palabra de estado, sus registros del procesador, su segmento de texto, pila y datos, etc. Un programa es un concepto estático, mientras que un proceso es un concepto dinámico. Es posible que un programa sea ejecutado por varios usuarios en un sistema multiusuario, por cada una de estas ejecuciones existirá un proceso, con su contador de programa, registros, etc. El sistema operativo necesita el concepto de proceso para poder gestionar el procesador mediante la técnica de multiprogramación o de tiempo compartido, de hecho, el proceso es la unidad planificable, o de asignación de la CPU.
8.2 Estados de un proceso y Transiciones de estado de los procesos
Durante su vida, un proceso puede pasar por una serie de estados discretos, algunos de ellos son:
En ejecución: El proceso ocupa la CPU actualmente, es decir, se está ejecutando.
Listo o preparado: El proceso dispone de todos los recursos para su ejecución, sólo le falta la CPU.
Bloqueado: Al proceso le falta algún recurso para poder seguir ejecutándose, además de la CPU. Por recurso se pueden entender un dispositivo, un dato, etc. El proceso necesita que ocurra algún evento que le permita poder proseguir su ejecución.
Hay otros estados de los procesos, pero en la presente exposición se tratarán estos tres. Por sencillez, se considera un sistema con una sola CPU, aunque no es difícil la extensión a múltiples procesadores. Solamente puede haber un proceso en ejecución a la vez, pero pueden existir varios listos y varios pueden estar bloqueados. Así pues, se forman una lista de procesos listos y otra de procesos bloqueados. La lista de procesos listos se ordena por prioridad, de manera que el siguiente proceso que reciba la CPU será el primero de la lista. La lista de procesos bloqueados normalmente no está ordenada; los procesos no se desbloquean (es decir, no pasan a ser procesos listos) en orden de prioridad, sino que lo hacen en el orden de ocurrencia de los eventos que están esperando. Como se verá más adelante, hay situaciones en las cuales varios procesos pueden bloquearse esperando la ocurrencia del mismo evento; en tales casos es común asignar prioridades a los procesos que esperan.
Transiciones de estado de los procesos
A continuación se dan ejemplos de eventos que pueden provocar transiciones de estado en un proceso en este modelo de tres estados (ver figura 2.1). La mayoría de estos eventos se discutirán con profundidad a lo largo del curso:
De ejecución á Bloqueado: al iniciar una operación de E/S, al realizar una operación WAIT sobre un semáforo a cero (en el tema de procesos concurrentes se estudiarán los semáforos).
De ejecución á Listo: por ejemplo, en un sistema de tiempo compartido, cuando el proceso que ocupa la CPU lleva demasiado tiempo ejecutándose continuamente (agota su cuanto) el sistema operativo decide que otro proceso ocupe la CPU, pasando el proceso que ocupaba la CPU a estado listo.
De Listo á en ejecución: cuando lo requiere el planificador de la CPU (veremos el planificador de la CPU en el tema de planificación de procesos).
De Bloqueado á Listo: se dispone del recurso por el que se había bloqueado el proceso. Por ejemplo, termina la operación de E/S, o se produce una operación SIGNAL sobre el semáforo en que se bloqueó el proceso, no habiendo otros procesos bloqueados en el semáforo.
Obsérvese que de las cuatro transiciones de estado posibles, la única iniciada por el proceso de usuario es el bloqueo, las otras tres son iniciadas por entidades externas al proceso.
Figura 2.1 Transiciones de estado de los procesos.
Interpretación de la figura. Como podemos observar en esta figura tenemos una serie de transiciones posibles entre estados de proceso, representados a partir mediante una gama de colores. Estos colores hay que interpretarlos de forma que, el color del borde de los estados representa a dichos estados, los colores dentro de los circulos nos dicen las posibles alternativas de acceso hacia otro estado, y los colores de las flechas nos representan hacia que estado nos dirigimos si seguimos la misma.
8.3 Descripción de un proceso
De algún modo, debemos hacer una pregunta fundamental: ¿cuál es la manifestación física de un proceso? Como mínimo debe incluir un programa o conjunto de programas que sean ejecutados. Asociados a estos programas hay un conjunto de ubicaciones de datos para las variables locales y globales, y las constantes definidas. Así pues, un proceso constará, al menos, de la memoria suficiente para albergar los programas y los datos del proceso. Además, en la ejecución de un programa entra en juego normalmente una pila, que se utiliza para llevar la cuenta de las llamadas aprocedimientos y de los parámetros que se pasan entre los procedimientos. Por último, asociado a cada proceso hay una serie de atributos que utiliza el sistema operativo para el control del proceso. Estos atributos se recogen en una estructura de datos que se conoce como bloque de control de proceso (Process Control Block, PCB) o descriptor de proceso. A esta colección de programa, datos, pila y atributos se le llama imagen oentorno del proceso.
8.4 El bloque de control de proceso
El bloque de control de proceso es la estructura de datos central y más importante de un sistema operativo. Cada bloque de control de proceso contiene toda la información de un proceso que necesita un sistema operativo para su control. Estos bloques son leídos y/o modificados por casi todos los módulos de un sistema operativo, incluyendo aquellos que tienen que ver con la planificación, la asignación de recursos, el tratamiento deinterrupciones y el análisis y supervisión del rendimiento. Puede decirse que el conjunto de los bloques de control de procesos definen el estado del sistema operativo. El conjunto de todos los PCB’s se guarda en una estructura del sistema operativo llamada tabla de procesos, la cual se puede implementar como un vector o un lista enlazada. La tabla de procesos reside en memoria principal, debido a su alta frecuencia de consulta.
En un sistema de multiprogramación, se requiere una gran cantidad de información de cada proceso para su administración. Sistemas distintos organizarán esta información de modo diferente. En general, se puede agrupar la información de los PCB’s en tres categorías:
Identificación del proceso.
Información del estado del procesador.
Información de control del proceso.
Con respecto a la identificación del proceso, en casi todos los sistemas operativos se le asigna a cada proceso un identificador numérico único (ID). Este identificador nos servirá para localizarlo dentro de la tabla de procesos. Cuando se permite que los procesos creen otros procesos, se utilizan identificadores para señalar al padre y a los descendientes de cada proceso. Además de estos, un proceso también puede tener asignado un identificador de usuario que indica a quién pertenece el proceso (UID).
El siguiente conjunto de información es la información de estado del procesador. Básicamente, está formada por el contenido de los registros del procesador. Por supuesto, mientras el proceso está ejecutándose, la información está en los registros. Cuando se interrumpe el proceso, toda la información de los registros debe salvarse de forma que pueda restaurarse cuando el proceso reanude su ejecución. La naturaleza y número de registros involucrados depende del diseño del procesador. Normalmente, en el conjunto de registros se incluyen los registros visibles para el usuario, los registros de control y de estado (contador de programa y palabra de estado) y los punteros a pila.
A la tercera categoría general de información del bloque de control de proceso se le podría llamar información de control del proceso. Esta es la información adicional necesaria para que el sistema operativo controle y coordine los diferentes procesos activos. Como, por ejemplo, información de planificación y estado (estado del proceso, su prioridad, información de planificación, suceso), apuntadores(punteros) a estructuras de datos (los procesos que esperan en un semáforo), punteros a zonas de memoria del proceso, recursos controlados por el proceso (ficheros abiertos), etc.
Así pues, el PCB es la entidad que define un proceso en el sistema operativo. Dado que los PCB necesitan ser manejados con eficiencia por el sistema operativo, muchos ordenadores tienen un registro hardware que siempre apunta hacia el PCB del proceso que se está ejecutando. A menudo existen instrucciones hardware que cargan en el PCB información sobre su entorno, y la recuperan con rapidez.
Operaciones con procesos
Los sistemas que administran procesos deben ser capaces de realizar ciertas operaciones sobre y con los procesos. Tales operaciones incluyen:
crear y destruir un proceso
suspender y reanudar un proceso
cambiar la prioridad de un proceso
bloquear y "desbloquear" un proceso
planificar un proceso (asignarle la CPU)
permitir que un proceso se comunique con otro (a esto se denomina comunicación entre procesos, y se estudiará en el tema deprocesos concurrentes).
Crear un proceso implica muchas operaciones, tales como:
buscarle un identificador
insertarlo en la tabla de procesos
determinar la prioridad inicial del proceso
crear el PCB
asignar los recursos iniciales al proceso
Un proceso puede crear un nuevo proceso. Si lo hace, el proceso creador se denomina proceso padre, y el proceso creado, proceso hijo. Sólo se necesita un padre para crear un hijo. Tal creación origina una estructura jerárquica de procesos, en la cual cada hijo tiene sólo un padre, pero un padre puede tener muchos hijos. En el sistema operativo UNIX la llamada al sistema ‘fork’ crea un proceso hijo.
Destruir un proceso implica eliminarlo del sistema. Se le borra de las tablas o listas del sistema, sus recursos se devuelven al sistema y su PCB se borra (es decir, el espacio de memoria ocupado por su PCB se devuelve al espacio de memoria disponible). La destrucción de un proceso es más difícil cuando éste ha creado otros procesos. En algunos sistemas un proceso hijo se destruye automáticamente cuando su padre es destruido; en otros sistemas, los procesos creados son independientes de su padre y la destrucción de este último no tiene efecto sobre sus hijos.
Un proceso suspendido o bloqueado no puede proseguir sino hasta que lo reanuda otro proceso. La suspensión es una operación importante, y ha sido puesta en práctica de diferentes formas en diversos sistemas. La suspensión dura por lo normal sólo periodos breves. Muchas veces, el sistema efectúa las suspensiones para eliminar temporalmente ciertos procesos, y así reducir la carga del sistema durante una situación de carga máxima. Cuando hay suspensiones largas se debe liberar los recursos del proceso. La decisión de liberar o no los recursos depende mucho de la naturaleza de cada recurso. La memoria principal debe ser liberada de inmediato cuando se suspenda un proceso; una unidad de cinta puede ser retenida brevemente por un proceso suspendido, pero debe ser liberada si el proceso se suspende por un periodo largo o indefinido. Reanudar (o activar) un proceso implica reiniciarlo a partir del punto en el que se suspendió.
Cambiar la prioridad de un proceso normalmente no implica más que modificar el valor de la prioridad en el PCB.
Suspensión y reanudación
Algunas líneas más arriba se presentaron los conceptos de suspensión y reanudación de un proceso. Estas operaciones son importantes por diversas razones.
Si un sistema está funcionando mal, y es probable que falle, se puede suspender los procesos activos para reanudarlos cuando se haya corregido el problema.
Un usuario que desconfíe de los resultados parciales de un proceso puede suspenderlo (en lugar de abortarlo) hasta que verifique si el proceso funciona correctamente o no.
Algunos procesos se pueden suspender como respuesta a las fluctuaciones (bajas y altas) a corto plazo de la carga del sistema, y reanudarse cuando las cargas vuelvan a niveles normales.
Interpretación de la figura. Como podemos observar en esta figura tenemos una serie de transiciones posibles entre estados de proceso, representados mediante una gama de colores. Estos colores hay que interpretarlos de forma que, el color del borde de los estados representa a dichos estados, los colores dentro de los circulos nos dicen las posibles alternativas de acceso hacia otro estado, y los colores de las flechas nos representan hacia que estado nos dirigimos si seguimos la misma.
Figura 3.1. Transiciones de estado de los procesos.
La figura 3.1 muestra el diagrama de transiciones de estado de los procesos, modificado para incluir las operaciones de suspensión y reanudación. Se han añadido dos estados nuevos, denominados suspendido_listo y suspendido_bloqueado; no hay necesidad de un estado suspendido_en_ejecución. El rango de procesos en el azul mantiene los estados activos, y debajo tenemos los estados suspendidos.
Una suspensión puede ser iniciada por el propio proceso o por otro. En un sistema con un sólo procesador, el proceso en ejecución puede suspenderse a sí mismo; ningún otro proceso podría estar en ejecución al mismo tiempo para realizar la suspensión (aunque otro proceso sí podría solicitar la suspensión cuando se ejecute). En un sistema de múltiples procesadores, un proceso en ejecución puede suspender a otro que se esté ejecutando en ese mismo momento en un procesador diferente.
Solamente otro proceso puede suspender un proceso listo. Un proceso puede hacer que otro proceso que se encuentre en el estado suspendido_listo pase al estado listo. Un proceso puede suspender a otro proceso que esté bloqueado, y hacerlo pasar de suspendido_bloqueado a bloqueado. Se podría alegar que en lugar de suspender un proceso bloqueado, sería mejor esperar hasta que ocurriera el evento que esperaba; entonces el proceso podría suspenderse y pasarse al estado suspendido_listo. Por desgracia, puede ser que nunca ocurra el evento o que se postergue indefinidamente. Así pues, el diseñador debe decidir si realiza la suspensión del proceso bloqueado o establece un mecanismo mediante el cual se realice la suspensión desde el estado listo cuando ocurra la finalización de la operación. Como la suspensión es, por lo normal, una actividad de alta prioridad, se debe realizar de inmediato. Cuando ocurre finalmente el evento, el proceso suspendido_bloqueado pasa a suspendido_listo.
En el tema de planificación y de gestión de memoria se analiza la forma en que el sistema operativo utiliza las operaciones de suspensión y reanudación para equilibrar la carga del sistema.
8.5 control de un proceso
8.5.1 Modos de Ejecución
Antes de continuar la discusión sobre la forma en que el sistema operativo gestiona los procesos, hace falta distinguir entre el modo de ejecución del procesador que normalmente se asocia con el sistema operativo y el modo que normalmente se asocia con los programas de usuario. Ciertasinstrucciones máquina pueden ejecutarse sólo en modo privilegiado. Entre éstas están la lectura o modificación de registros de control (como lapalabra de estado), instrucciones primitivas de E/S e instrucciones relativas a la gestión de memoria. Y solamente se puede acceder a ciertas zonas de memoria en el modo privilegiado. El modo de menor privilegio se conoce como modo usuario, y el de mayor privilegio como modo de sistema, supervisor o núcleo.
La razón por la que se usan dos modos debe quedar clara. Es necesario proteger al sistema operativo y a las estructuras de datos importantes, tales como los bloques de control de procesos, de las inferencias de los programas de usuario. En el modo núcleo o privilegiado, el software tiene control completo del procesador y de todas las instrucciones, registros y memoria.
Surgen dos preguntas: ¿cómo conoce el procesador en qué modo va a ejecutar?, ¿cómo se cambia de modo? Para la primera pregunta, hay un bit en la PSW( palabra de estado ), que indica el modo de ejecución. El bit se cambia como respuesta a ciertos sucesos tales como una llamada al sistema y, así, se cambia de modo.
8.5.2 Cambio de Proceso
A primera vista, la función de cambio de proceso parece sencilla. En cierto momento, un proceso que se está ejecutando se interrumpe, el sistema operativo pone a otro proceso en el estado de ejecución y pasa el control a dicho proceso. Sin embargo, surgen diversas cuestiones de diseño. En primer lugar, ¿qué sucesos provocan un cambio de proceso? Otra cuestión es que se debe hacer una distinción entre cambio de contexto y cambio de proceso. Por último, ¿qué debe hacer el sistema operativo con las diferentes estructuras de datos bajo su control para llevar a cabo un cambio de proceso?
¿Qué eventos provocan el cambio de proceso?
Un cambio de proceso puede suceder en cualquier instante en el que el sistema operativo gana el control de la CPU.
En primer lugar, se van a tener en cuenta las interrupciones del sistema. Se pueden distinguir dos clases de interrupciones del sistema. La primera es originada por algún tipo de suceso que es externo e independiente del proceso que se está ejecutando, como la culminación de una E/S. La segunda tiene que ver con una condición de error o excepción generada dentro del proceso que se está ejecutando, como un intento ilegal de acceso a un fichero, una división entre cero, una instrucción máquina con código de operación no contemplado. En una interrupción ordinaria, el control se transfiere primero al gestor de interrupciones, quien lleva a cabo algunas tareas básicas y, después, se salta a la rutina del sistema operativo que se ocupa del tipo de interrupción que se ha producido. Algunos ejemplos de estas interrupciones son:
Interrupción de reloj: Un reloj es un dispositivo que genera interrupciones periódicamente. Ante una interrupción de este tipo, un sistema operativo de tiempo compartido, entre otras cosas, determina si el proceso en ejecución ha alcanzado el máximo tiempo de ejecución que se le concedió. Si es así, el proceso pasará a estado listo, y se asignará la CPU a otro proceso.
Interrupción de E/S: El sistema operativo determina exactamente qué acción de E/S ha ocurrido. Si se trata de un evento o suceso por el que esperaban uno o más procesos, entonces el sistema operativo traslada todos los procesos bloqueados en dicho evento al estado listo, y determina (dependiendo de la política de planificación, que se verá en el próximo tema) si reanuda la ejecución del proceso interrumpido o pasa a otro de mayor prioridad.
Falta de memoria: Un proceso hace una referencia a una dirección que no se encuentra en memoria y que debe traerse de memoria secundaria (esta posibilidad se estudiará en el módulo de gestión de la memoria). Después de hacer la solicitud de E/S para traer esa o esas direcciones de memoria, el sistema operativo lleva a cabo un cambio de contexto (próximo apartado) para reanudar la ejecución de otro proceso; el proceso que cometió la falta de memoria se pasa al estado bloqueado. Después de que las direcciones aludidas se carguen en memoria, dicho proceso se pondrá en estado listo.
En una interrupción del segundo tipo, el sistema operativo determina si el error es fatal. Si lo es, el proceso que se estaba ejecutando es eliminado, y se produce un cambio de proceso. Si no es fatal, la acción del sistema operativo dependerá de la naturaleza del error y del diseño del sistema operativo. Se puede hacer un cambio de proceso o, simplemente, reanudar el mismo proceso que se estaba ejecutando.
Finalmente, el sistema operativo puede activarse mediante una llamada al sistema desde el programa que se está ejecutando. Por ejemplo, está ejecutándose un proceso de usuario y se llega a una instrucción que solicita una operación de E/S, tal como abrir un fichero. Esta llamada provoca la transferencia a una rutina que forma parte del código del sistema operativo. Por lo general (aunque no siempre) el uso de una llamada al sistema hace que el proceso de usuario pase al estado bloqueado.
8.5.3 Cambio de Contexto
Si existe una interrupción pendiente es necesario:
Salvar el contexto (PC, registros del procesador, información de la pila) del programa en ejecución.
Poner en el PC la dirección del programa de tratamiento de la interrupción, que suele constar de unas pocas tareas básicas.
Una pregunta que puede plantearse es: ¿qué es lo que constituye el contexto que se debe salvar? La respuesta es que se debe incluir información que pueda ser necesaria para reanudar el programa interrumpido. Así pues, debe guardarse la parte del bloque de control del proceso denominada información de estado del procesador. Esto incluye al contador de programa, otros registros del procesador y la información de la pila.
¿Se tiene que hacer algo más? Ello dependerá de lo que ocurra a continuación. La rutina de tratamiento de la interrupción es normalmente un programa corto que lleva a cabo unas pocas tareas básicas relacionadas con una interrupción. Por ejemplo, se marca el indicador que señala la presencia de una interrupción, puede enviar un acuse de recibo a la entidad que produjo la interrupción (como un módulo de E/S) y puede hacer algunas tareas básicas relacionadas con los efectos del suceso que causó la interrupción. Por ejemplo, si la interrupción está relacionada con un suceso de E/S, el gestor de interrupciones comprobará condiciones de error. Si se ha producido un error, la rutina de tratamiento puede enviar una señal al proceso que solicitó originalmente la operación de E/S.
¿Hay que hacer algo más? Pues depende de si la interrupción va a venir seguida de un cambio de proceso o no. La ocurrencia de una interrupción no siemprecausa el cambio de proceso. Es posible que después de que el gestor de interrupciones se haya ejecutado, el proceso que estaba ejecutándose reanude su ejecución. En tal caso, tan sólo hay que guardar la información de estado del procesador y restaurarla para que pueda reanudarse correctamente el proceso interrumpido (estas funciones son realizadas en hardware).
Por tanto, el cambio de contexto es un concepto distinto al cambio de un proceso. Puede ocurrir un cambio de contexto sin cambiar el estado del proceso que está actualmente en estado de ejecución. En tal caso, salvar el contexto y restaurarlo posteriormente involucra un pequeño coste extra. Sin embargo, si el proceso que estaba ejecutándose tiene que pasar a otro estado (listo o bloqueado), el sistema operativo tiene que llevar a cabo cambios substanciales en su entorno( contexto ). Los pasos involucrados en un cambio completo de proceso son los siguientes:
1.Salvar el contexto del procesador, incluyendo el contador de programa y otros registros.
2.Actualizar el PCB que estaba en estado de ejecución. Esto implica cambiar el estado del proceso a alguno de los otros estados (listo, bloqueado, suspendido_listo). También se tienen que actualizar otros campos, como uno en el que se guarde la razón por la que se abandona el estado de ejecución y otros con información de contabilidad.
3.Mover el PCB a la cola apropiada (listos, bloqueados por el suceso i, suspendido_listo).
4.Seleccionar otro proceso para ejecución (como veremos en el tema de Planificación de Procesos).
5.Actualizar el PCB seleccionado. Cambiar, por ejemplo, su estado a ‘en ejecución’.
6.Actualizar las estructuras de datos de gestión de la memoria. Esto puede hacer falta dependiendo de cómo se gestione la traducción de direcciones (lo dejaremos para los temas sobre memoria).Restaurar el contexto del procesador a aquél que existía en el momento en el que el proceso seleccionado dejó por última vez el estado de en ejecución, cargando los valores previos del contador de programa y de otros registros.
Así pues, el cambio de proceso, que implica un cambio de contexto, requiere un esfuerzo considerablemente superior al de un cambio de contexto.
8.6 Procesos y Threads
El concepto de proceso es más complejo y sutil que el presentado hasta ahora. Engloba dos conceptos separados y potencialmente independientes: uno relativo a la propiedad de recursos y otro que hace referencia a la ejecución.
Unidad que posee recursos: A un proceso se le asigna un espacio de memoria y, de tanto en tanto, se le puede asignar otros recursos como dispositivos de E/S o ficheros.
Unidad a la que se le asigna el procesador: Un proceso es un flujo de ejecución (una traza) a través de uno o más programas. Esta ejecución se entremezcla con la de otros procesos. De tal forma, que un proceso tiene un estado (en ejecución, listo, etc) y una prioridad de expedición u origen. La unidad planificada y expedida por el sistema operativo es el proceso.
En la mayoría de los sistemas operativos, estas dos características son, de hecho, la esencia de un proceso. Sin embargo, son independientes, y pueden ser tratadas como tales por el sistema operativo. Esta distinción ha conducido en los sistemas operativos actuales a desarrollar la construcción conocida como thread, cuyas traducciones más frecuentes son hilo, hebra y proceso ligero. Si se tiene esta división de características, la unidad de asignación de la CPU se conoce como hilo, mientras que a la unidad que posee recursos se le llama proceso.
Dentro de un proceso puede haber uno o más hilos de control cada uno con:
Un estado de ejecución (en ejecución, listo, bloqueado).
Un contexto de procesador, que se salva cuando no esté ejecutándose.
Una pila de ejecución.
Algún almacenamiento estático para variables locales.
Acceso a la memoria y a los recursos de ese trabajo que comparte con los otros hilos.
Los beneficios clave de los hilos se derivan de las implicaciones del rendimiento: se tarda menos tiempo en crear un nuevo hilo de un proceso que ya existe, en terminarlo, y en hacer un cambio de contexto entre hilos de un mismo proceso. Al someter a un mismo proceso a varios flujos de ejecución se mantiene una única copia en memoria del código, y no varias.
Un ejemplo de aplicación que podría hacer uso de los hilos es un servidor de ficheros de una red de área local. Cada vez que llega una solicitud de una operación sobre un fichero, se puede generar un nuevo hilo para su gestión. El servidor gestiona multitud de solicitudes, por tanto, se pueden crear y destruir muchos hilos en poco tiempo para dar servicio a estas
9.1 Comunicación y Sincronización de Procesos
Puede verse la concurrencia de procesos como la ejecución simultánea de varios procesos. Si tenemos un multiprocesador o un sistema distribuido(tema 1) la concurrencia parece clara, en un momento dado cada procesador ejecuta un proceso. Se puede ampliar el concepto de concurrencia si entendemos por procesado concurrente (o procesado paralelo) la circunstancia en la que de tomar una instantánea del sistema en conjunto, varios procesos se vean en un estado intermedio entre su estado inicial y final. Esta última definición incluye los sistemas multiprogramadosde un único procesador que estudiamos en los temas anteriores.
Los distintos procesos dentro de un ordenador no actúan de forma aislada. Por un lado, algunos procesos cooperan para lograr un objetivo común. Por otro lado, los procesos compiten por el uso de unos recursos limitados, como el procesador, la memoria o los ficheros. Estas dos actividades de cooperación y competición llevan asociada la necesidad de algún tipo de comunicación entre los procesos. Parte de este tema lo dedicaremos a estudiar mecanismos de comunicación entre los procesos.
Para aclarar un poco todo esto, supongamos que en un entorno UNIX se ejecuta la orden
cat tema1 tema2 tema3 | wc -l
Esta orden va a provocar que el intérprete de órdenes cree dos procesos concurrentes, el primero ejecutará el programa cat, que concatenará el contenido de los ficheros de texto tema1, tema2 y tema3. El segundo ejecutará el programa wc, que contará el número de líneas de la salida producida por cat. Estos dos procesos cooperan, y será preciso algún tipo de sincronización entre ellos, concretamente hasta que cat no produzca alguna salida wc debería bloquearse.
9.1.1 Cooperación entre Procesos
La velocidad de un proceso con respecto a otro es impredecible ya que depende de la frecuencia de la interrupción asociada a cada uno de ellos y cuán a menudo y de por cuánto tiempo tiene asignado cada proceso un procesador. Diremos, pues, que un proceso se ejecuta asíncronamente con respecto a otro, es decir, sus ejecuciones son independientes. Sin embargo, hay ciertos instantes en lo que los procesos deben sincronizar sus actividades. Son estos puntos a partir de los cuales un proceso no puede progresar hasta que otro haya completado algún tipo de actividad.
Los procesos también necesitan comunicarse entre sí. Por ejemplo, para leer de un fichero, los procesos de usuario deben decir al proceso que gestiona los ficheros lo que desean. Este, a su vez, debe pedirle al proceso de disco que lea los bloques necesarios. Cuando el shell conecta dos procesos con un tubo, los datos de salida del primer proceso se transfieren al segundo. Se necesita que los procesos se comuniquen entre sí, con un mecanismo bien estructurado y no por medio de interrupciones.
9.1.2 Competencia entre los procesos
Los recursos de un sistema pueden clasificarse como compartibles, lo que significa que pueden ser utilizados por varios procesos de forma concurrente, o no compartibles, lo que equivale a que su uso se restrinja a un sólo proceso a la vez. El hecho de que un recurso no sea compartible deriva de una de las dos razones siguientes:
La naturaleza física del recurso hace que sea imposible compartirlo. Un ejemplo lo constituye una impresora, si una impresora fuera utilizada por varios procesos simultáneamente sus salidas se entremezclarían en el papel.
El recurso es tal que si es usado por varios procesos de forma concurrente la acción de uno de ellos puede interferir con la de otro. Un ejemplo común lo constituye un fichero que contiene unos datos accesibles desde más de un proceso, y modificables al menos por uno de ellos. Por ejemplo, supongamos un fichero que contiene registros con la siguiente información sobre una cuenta bancaria:
CLAVE SALDO
Supongamos también dos procesos que se ejecutan concurrentemente y que actualizan una misma cuenta, el proceso P1 añade al saldo el valor de la nómina y el proceso P2 descuenta del saldo una factura domiciliada. El código de los procesos es el siguiente:
El resultado final de la ejecución de los dos procesos debería actualizar el saldo añadiéndole la nómina, y descontándole la factura. Sin embargo, la secuencia de ejecución en el procesador de las instrucciones a1b1b2b3a2a3, que puede darse debido a un cambio de proceso, hace que no se descuente la factura.
Dentro de la categoría de recursos no compartibles se incluirán la mayoría de los periféricos (los discos no), los ficheros de escritura y las zonas de memoria sujetas a modificación. Los recursos compartibles incluirán la CPU (en los temas previos vimos cómo compartir la CPU entre los procesos introduciendo el concepto de PCB), los ficheros de lectura, y las zonas de memoria que contengan rutinas puras o bien datos que no están sujetos a modificación.
9.1.3 Requisitos para la Exclusión Mutua
Los recursos no compartibles, ya sean periféricos, ficheros, o datos en memoria, pueden protegerse del acceso simultáneo por parte de varios procesos evitando que éstos ejecuten de forma concurrente sus fragmentos de código a través de los cuales llevan a cabo este acceso. Estos trozos de código reciben el nombre de secciones o regiones críticas, pudiéndose asimilar el concepto de exclusión mutua en el uso de estos recursos a la idea de exclusión mutua en la ejecución de las secciones críticas. Así, por ejemplo, puede implementarse la exclusión mutua de varios procesos en el acceso a una tabla de datos mediante el recurso de que todas las rutinas que lean o actualicen la tabla se escriban como secciones críticas, de forma que sólo pueda ejecutarse una de ellas a la vez. En el ejemplo previo de la cuenta bancaria los fragmentos de códigoa1a2a3 y b1b2b3 constituyen dos secciones críticas mutuamente excluyentes, esto significa que una vez que se ha comenzado la ejecución de una sección crítica, no se puede entrar en otra sección crítica mutuamente excluyente.
Idear soluciones que garanticen la exclusión mutua es uno de los problemas fundamentales de la programación concurrente. Muchas son las alternativas y tipos de mecanismos que se pueden adoptar. A lo largo de este tema veremos diferentes soluciones software y alguna hardware ; unas serán sencillas y otras complejas, algunas requieren la cooperación voluntaria de los procesos y otras que exigen un estricto ajuste a rígidos protocolos. La selección de las operaciones primitivas adecuadas para garantizar la exclusión mutua de las secciones críticas es una decisión primordial en el diseño de un sistema operativo. Al menos, una solución apropiada debería cumplir las cuatro condiciones siguientes:
1. Que no haya en ningún momento dos procesos dentro de sus respectivas secciones críticas.
2. Que no hagan suposiciones a priori sobre las velocidades relativas de los procesos o el número de procesadores disponibles.
3. Que ningún proceso que esté fuera de su sección crítica pueda bloquear a otros.
4. Que ningún proceso tenga que esperar un intervalo de tiempo arbitrariamente grande para entrar en su sección crítica.
9.2 Utilizando Memoria Compartida
A partir de aquí, iremos haciendo un estudio progresivo sobre las posibles soluciones de todo tipo que intentarán resolver la exclusión mutua y el sincronismo entre procesos. Muchas de estas soluciones fracasarán en su intento. Otras lo lograrán, pero mostrarán ciertas deficiencias que nos llevarán a pensar en nuevas primitivas de concurrencia.
Nuestro viaje comenzará con las soluciones que utilizan memoria compartida. Dentro de este grupo, distinguiremos entre mecanismos software y hardware que emplean espera ocupada, y los que usan espera bloqueada (semáforos y monitores).
9.2.1 Soluciones Software al Problema de la Exclusión Mutua
En esta sección se van a estudiar varios métodos que intentan resolver el problema de la ejecución en exclusión mutua de las secciones críticas de los procesos. En primer lugar, introduciremos algunos métodos que no producen una solución aceptable, sin embargo, nos ayudarán a comprender mejor el problema.
Desactivación de las interrupciones
La solución más sencilla es que cada proceso prohiba todas las interrupciones justo antes de entrar en su región crítica y las permita de nuevo justo antes de salir. Esto funciona correctamente, pues el código del sistema operativo sólo se activa como consecuencia de la ocurrencia de interrupciones. Si el sistema operativo no puede ejecutarse mientras se ejecuta la sección crítica, es obvio que no podrá realizar un cambio de proceso en la CPU, por lo tanto, la sección crítica se ejecutará en exclusión con todo proceso.
Pero con las interrupciones prohibidas no se servirá ni la interrupción de reloj ni ninguna otra. Dado que la asignación del procesador a los diferentes procesos sólo cambia como consecuencia de una interrupción, sea de reloj o de cualquier otra clase, el prohibir interrupciones hace que no pueda conmutarse el procesador a otro proceso.
Esta solución es poco atrayente porque le da a los procesos de usuario la capacidad de prohibir las interrupciones. Si no las vuelve a habilitar, sería el fin del sistema. Además, si el computador tuviera dos o más procesadores, la desactivación de las interrupciones sólo afectaría al procesador que ejecutó la instrucción. El resto de los procesadores continuarían normalmente y podrían acceder a la memoria compartida sin mayor problema.
Sin embargo, a veces es conveniente que el propio sistema operativo prohiba las interrupciones mientras está actualizando sus variables o listas. La prohibición de interrupciones es un mecanismo adecuado para garantizar la exclusión mutua dentro del núcleo, pero poco recomendable para procesos de usuario.
Variable de cerradura
Analicemos una solución mediante software. Consiste en tener una variable de cerradura compartida por los procesos. Antes de que un proceso entre en su sección crítica comprueba el valor de la cerradura. Si ésta vale 0, el proceso cambia el valor a 1 y entra en la sección crítica. Si ésta ya vale 1, el proceso espera hasta que la variable valga 0. Por lo tanto, un 0 indica que ningún proceso se encuentra en una sección crítica y un 1 indica que algún proceso está en una sección crítica. A continuación se presenta el fragmento del código (en lenguaje C) de un proceso que quiere entrar en una sección crítica. A las instrucciones, relativas a proporcionar la exclusión mutua, que se ejecutan antes de entrar en la sección crítica, se les llama protocolo de entrada; a las que se ejecutan después de ejecutar el código de la sección crítica se les llama protocolo de salida. En este caso el protocolo de entrada lo constituyen la conjunción de las instrucciones while y ‘cerrado = 1'. El protocolo de salida lo conforma la instrucción ‘cerrado = 0'.
Esta solución no funciona. Suponga que un proceso lee la cerradura y comprueba que tiene un valor 0. Antes de que pueda ponerla a 1 se planifica otro proceso. Éste comprueba el valor de cerrado, al ser 0 entra en su sección crítica. Si antes de que este proceso termine la sección crítica se vuelve a planificar al primer proceso no se habrá logrado la exclusión mutua. El problema proviene de que el protocolo de entrada es una sección crítica más, pues se dedica a modificar una variable compartida (la variable cerrado). Obsérvese que si el protocolo de entrada se pudiera ejecutar sin cambios de proceso la solución sería efectiva.
Algunos intentos para especificar el código de las primitivas de exclusión mutua
Acabamos de ver cómo el uso de una variable de cerradura fracasa en su intento. Analicemos otras posibles soluciones software. Necesitamos unas primitivas de exclusión mutua que protejan el acceso a las secciones críticas. Utilizaremos el siguiente esquema general (figura 4.2) : tendremos una pareja de construcciones entrar_exclusión_mutua y salir_exclusión_mutua que encapsulan el código de cada proceso que tiene acceso a la variable compartida. La construcción parbegin/parend hace que proceso_uno y proceso_dos operen como procesos concurrentes. Cada uno de estos procesos se encuentra dentro de un ciclo infinito, entrando una y otra vez en sus secciones críticas.
Fig 4.2. Esquema general del uso de primitivas de exclusión mutua.
Primera tentativa
La variable compartida número_proceso, con un valor inicial 1, mantiene un registro del turno para entrar en la sección crítica. El Proceso_uno ejecuta el ciclo while do. Como en un principio número_proceso vale 1, proceso_uno entra en la sección crítica. Proceso_dos encuentra que número_proceso equivale a 1 y se mantiene dentro de su ciclo while do. Cada vez que el proceso_dos obtiene el procesador, se limita a repetir el ciclo en espera de que número_proceso valga 2, de manera que proceso_dos no entra en su sección crítica y la exclusión mutua está garantizada. El procesador está en uso mientras proceso_dos no hace nada (excepto verificar el valor de número_proceso), esto se conoce como espera ocupada o activa. La espera activa se considera una técnica aceptable cuando las esperas anticipadas son cortas; de lo contrario, la espera activa puede resultar costosa.
La exclusión mutua está garantizada, pero a un precio alto. Los procesos deben entrar y salir de su sección crítica de manera estrictamente alterna. Si un proceso es más corto que otro, la velocidad de uno de ellos condicionará al otro. Si uno de los procesos termina, el otro no podrá continuar. Esta primera solución utiliza una variable global, y ella ocasiona el problema de la sincronización con alternancia estricta.
Fig 4.3 Primera versión de las primitivas de exclusión mutua.
Segunda Tentativa
Por ello, en la segunda versión se usan dos variables: p1dentro, que es cierta si el proceso uno está en su sección crítica y, p2dentro, que también será cierta si el proceso dos está en su sección crítica.
P1 y P2 son concurrentes e intentarán entrar simultáneamente en su sección crítica. No está garantizada la exclusión mutua. El problema se debe a que, entre el momento en que un proceso determina que puede seguir y el momento en que se asigna cierto a su bandera ( variable centinela), hay tiempo suficiente para que el otro verifique su bandera y entre en su sección crítica.
Por tanto, en el momento en que realiza su verificación deberá estar seguro de que el otro proceso no podrá pasar su verificación.
Fig 4.4. Segunda versión de las primitivas de exclusión mutua.
Tercera Tentativa
Ahora cambiamos la bandera antes de realizar la verificación, indicando su deseo de ejecutar la sección crítica. Se puede producir un bloqueo mutuo, los dos procesos entrarán en un ciclo infinito. Esto se debe a que cada uno de los procesos se puede bloquear en su verificación.
Fig 4.5. Tercera versión de las primitivas de exclusión mutua.
Cuarta Tentativa
En la anterior versión quedábamos atrapados en la verificación, por tanto, ahora intentaremos escapar de ella. Una manera de hacerlo es retardando la verificación, para comprobar si el otro también desea entrar. La exclusión mutua está garantizada y no ocurre bloqueo mutuo, pero puede ocurrir un aplazamiento indefinido. Un aplazamiento indefinido o inanición es una situación en la que se posterga indefinidamente el progreso en la ejecución de uno o más procesos. Veamos cómo puede suceder: puesto que no podemos hacer suposiciones sobre sus velocidades podría suceder que se ejecutasen en tándem, esto es, uno ejecuta una instrucción y el otro, a continuación, la correspondiente. Luego, cada proceso puede asignar el valor cierto a su bandera, realizar la verificación, entrar en el cuerpo del 'ciclo while', asignar el valor falso a su bandera, asignar el valor cierto a su bandera y después repetir la secuencia comenzando con la verificación (esto no se puede consentir para ciertas aplicaciones que deben ejecutar en un tiempo concreto como el software de control de vuelo, un marcapasos o un sistema de control de tráfico aéreo...).
Fig 4.6. Cuarta versión de las primitivas de exclusión mutua.
Algoritmo de Dekker
Gestiona elegantemente la exclusión mutua. Utiliza, además de las banderas de intención de entrar, una variable turno (proceso_favorecido) que resuelve en caso de conflicto. Da la posibilidad de que el otro proceso entre en su sección crítica una segunda vez si lo hace antes que el proceso que acaba de dejar el bucle de espera, asigne el valor cierto a su intención de entrar. Pero cuando de nuevo tiene el procesador, realiza la asignación y es su turno, así que se ejecuta. En consecuencia, no produce aplazamiento indefinido (figura 4.7).
Fig 4.7. Algoritmo de Dekker
Algoritmo de Peterson
Simplifica el algoritmo de Dekker. El protocolo de entrada es más elegante con las mismas garantías de exclusión mutua, imposibilidad de bloqueo mutuo y de aplazamiento indefinido.
Fig 4.8 Algoritmo de Peterson
9.2.2 Soluciones hardware a la exclusión mutua
Se estudia ahora una solución que requiere apoyo del hardware. Muchos ordenadores, en particular aquellos diseñados teniendo en mente varios procesadores, tienen una instrucción TEST AND SET LOCK (TSL). Esta instrucción máquina provoca la lectura del contenido de una palabra de la memoria en un registro, y el almacenamiento de un valor distinto de cero en dicha palabra de memoria. Al ser una instrucción máquina, las operaciones de lectura y escritura de la palabra tienen la garantía de ser indivisibles (atómicas). Además, ninguno de los demás procesadores puede tener acceso a la palabra hasta terminar la instrucción. El procesador que ejecuta la instrucción TSL cierra el bus de la memoria para prohibir a los demás el acceso a la memoria hasta el término de la instrucción.
A continuación se muestra una solución al problema de la exclusión mutua que se basa en la instrucción TSL. La solución viene expresada en un lenguaje ensamblador ficticio (pero típico). Existen dos subrutinas que los procesos llamarán como protocolos de entrada y salida:
La variable cerrado es una variable compartida que se utiliza para coordinar el acceso a las secciones críticas. Cuando vale 0 se permite el acceso y cuando vale 1 no. Cuando un proceso quiera entrar a una sección crítica llamará a la subrutina entrar_sección. Esta subrutina estará ejecutando un ciclo hasta que cerrado valga 0. Obsérvese que esta solución funciona, mientras que la solución de la variable cerradura no funcionaba. La clave está en que la instrucción TSL realiza atómicamente el comprobar que cerrado vale 0 y el asignarle el valor 1.
Fig 5.8. Instrucción TSL
9.3 Sin Utilizar Memoria Compartida. Mensajes
Los monitores y los semáforos se diseñaron para resolver problemas de sincronización en un sistema mono o multiprocesador, es decir, un sistema con una o varias CPU's que tienen acceso a una memoria compartida. La comunicación se logra compartiendo una zona de memoria donde los procesos guardan información, los semáforos y monitores se utilizan para sincronizar el acceso a dicha zona. Si pasamos a un sistema distribuido, con varias CPU's, cada una con su memoria privada, unidas mediante una red, estos mecanismos de comunicación entre procesos ya no se pueden aplicar. Además, estos dos mecanismos sirven para la sincronización, pero no para el intercambio de información entre procesos. En el siguiente apartado veremos un mecanismo que solventa ambos problemas.
Transferencia de mensajes
Este mecanismo de comunicación entre procesos se basa en dos primitivas: send y receive, las cuales, al igual que los semáforos, y a diferencia de los monitores, son servicios (llamadas al sistema) proporcionados por el sistema operativo. Los lenguajes de programación tendrán rutinas de biblioteca para invocar tales servicios desde un programa. Dichas rutinas de biblioteca tendrán un formato parecido al siguiente:
send(mensaje, destino) ,y
receive(mensaje, origen)
La primera función envía un mensaje a un destino dado, y la segunda recibe un mensaje desde cierto origen (o desde cualquier origen, si al receptor no le importa el origen).
Los sistemas operativos suelen implementar dos tipos de comunicación basadas en transferencia de mensajes: la directa y la indirecta. El comportamiento de los procesos en cuanto a la sincronización es distinto en los dos tipos de comunicación. A continuación se exponen ambos.
Transferencia de mensajes con designación directa
En este sistema, tanto el proceso emisor como el proceso receptor deben especificar explícitamente el proceso destino y origen respectivamente. Las funciones tendrá un formato similar al siguiente:
send(mensaje, identificador proceso destino)
receive(mensaje, identificador proceso origen)
En cuanto a la sincronización, viene determinada por la ausencia de un lugar donde almacenar el mensaje. Si se ejecuta send antes de receive en el proceso destino, el proceso emisor se bloquea hasta la ejecución de receive, momento en el cual el mensaje se puede copiar de manera directa desde el emisor al receptor sin almacenamiento intermedio. Análogamente, si se ejecuta primero receive, el receptor se bloquea hasta que se ejecute una operación send en el proceso emisor. Este modo de sincronización se conoce como cita (rendezvous).
Transferencia de mensajes con designación indirecta
En este sistema, los mensajes se envían o reciben de unos objetos proporcionados por el sistema operativo denominados buzones. Un buzón es un lugar donde almacenar un número determinado de mensajes, la cantidad de mensajes que alberga el buzón se especifica al crearlo. Al utilizar buzones, los parámetros de dirección en las llamadas send y receive son buzones, y no procesos:
send(mensaje, buzón)
receive(mensaje, buzón)
El sistema operativo debe proporcionar servicios para la creación y destrucción de buzones, así como para la especificación de los usuarios y/o procesos que pueden utilizar un buzón.
En cuanto a la sincronización, un proceso que haga una operación send sobre un buzón, sólo se bloquea si dicho buzón está lleno. Un proceso que realice una operación receive sobre un buzón, sólo se bloquea si el buzón está vacío, es decir, no contiene mensajes.
Los sistemas de transferencia de mensajes con designación directa son más fáciles de implementar. Sin embargo, son menos flexibles, puesto que el emisor y el receptor deben estar ejecutándose simultáneamente. Si se utilizan buzones, el emisor puede almacenar sus mensajes en un buzón, pudiendo el receptor recuperarlos posteriormente.
Ejemplos de utilización de transferencia de mensajes
En este apartado vamos a ver cómo resolver los problemas de la exclusión mutua y de los productores y consumidores utilizando transferencia de mensajes con designación indirecta. En el apartado de Comunicación y Sincronización se emplea la designación directa para crear una aplicación cliente-servidor.
Exclusión mutua
Se necesita un proceso de inicialización, en el que se crea el buzón exmut con un tamaño de un mensaje, y tamaño de mensaje de un byte. A continuación se llena el buzón (el contenido del mensaje, el carácter '*', no es relevante). Para realizar la exclusión mutua en la sección crítica del proceso Pi se tiene en cuenta que la operación receive es indivisible, y representa un bloqueo potencial si el buzón está vacío. Obsérvese que la solución es análoga a la realizada mediante semáforos. En aquella se definía un semáforo de valor incial 1, representando este valor la ausencia de procesos dentro de una sección crítica. El cero representaba el que un proceso estaba en una sección crítica. En esta solución, se define un buzón de tamaño 1, la existencia de un mensaje en ese buzón significa la no existencia de procesos en una sección crítica. La ausencia de mensajes en el buzón implica que un proceso está en una sección crítica.
Productores y consumidores
Para la solución se crean dos buzones de tamaño N (longitud del buffer). El tamaño de un mensaje es sizeof(int), sizeof es una macro de C que sirve para calcular el número de bytes que ocupa el tipo de dato que representa su único parámetro (en este caso un entero). En el buzón esp habrá tantos mensajes (de valor insustancial 0) como espacios haya en el buzón ele. La información almacenada en el buzón ele sí es importante, son los elementos producidos por los productores.
Llamadas a procedimientos remotos
La noción de llamadas a procedimientos remotos (remote procedure calls, RPC) se introdujo con el objeto de ofrecer un mecanismo estructurado de alto nivel para realizar la comunicación entre procesos en sistemas distribuidos. Con una llamada a un procedimiento remoto, un proceso de un sistema puede llamar a un procedimiento de un proceso de otro sistema. El proceso que llama se bloquea esperando el retorno desde el procedimiento llamado en el sistema remoto y después continúa su ejecución desde el punto que sigue a la llamada.
El procedimiento llamado y el que llama residen en máquinas distintas, con espacios de direcciones distintos, no existe la noción de variables globales compartidas, como en los procedimientos normales dentro de un proceso. Las RPC transfieren la información a través de parámetros de la llamada. Una RPC se puede realizar con los mecanismo del tipo enviar/recibir.
send(proceso_remoto,parámetros_entrada);
receive(proceso_remoto, parámetros_salida);
Una llamada a procedimiento remoto debería ser igual a una llamada a un procedimiento local, desde el punto de vista del usuario. Una llamada por valor es más fácil enviando copias de los datos mediante mensajes. Las llamadas por referencia son más difíciles, porque una RPC cruza a otro espacio de direcciones. Los formatos internos de los datos pueden cambiar en una red de máquinas heterogéneas; requieren conversiones complejas y un considerable trabajo adicional. Deben tenerse en cuenta la posibilidad de transmisiones defectuosas y la pérdida de mensajes en la red.
9.4 Problemas Clásicos de Comunicación entre Procesos
9.4.1 El problema de la cena de los filósofos
En 1965 Dijkstra planteó y resolvió un problema de sincronización llamado el problema de la cena de los filósofos, que se puede enunciar como sigue. Cinco filósofos se sientan a la mesa, cada uno con un plato de espaghetti. El espaghetti es tan escurridizo que un filósofo necesita dos tenedores para comerlo. Entre cada dos platos hay un tenedor. En la figura 4.15 se muestra la mesa.
Fig 4.15. Los filósofos se disponen a comer
La vida de un filósofo consta de periodos alternos de comer y pensar. Cuando un filósofo tiene hambre, intenta obtener un tenedor para su mano derecha, y otro para su mano izquierda, cogiendo uno a la vez y en cualquier orden. Si logra obtener los dos tenedores, come un rato y después deja los tenedores y continúa pensando. La pregunta clave es: ¿ puede el lector escribir un programa para cada filósofo que permita comer equitativamente a los filósofos y no se interbloquee ?
Figura 4.16. Una no-solución al problema de la cena de los filósofos
La figura 4.16 muestra una solución obvia. El procedimiento coger_tenedor espera hasta que el tenedor especificado esté disponible y lo coge. Por desgracia la solución obvia es incorrecta. Supongamos que los cinco filósofos cogen sus tenedores izquierdos de forma simultánea. Ninguno podría coger su tenedor derecho, lo que produciría un interbloqueo.
Se podría modificar el programa de forma que después de coger el tenedor izquierdo, el programa verificara si el tenedor derecho está disponible. Si no lo está, el filósofo deja el izquierdo, espera cierto tiempo y vuelve a repetir el proceso. Esta propuesta también falla, aunque por razones distintas. Con un poco de mala suerte todos los filósofos podrían empezar el algoritmo de forma simultánea, por lo que cogerían sus tenedores izquierdos, verían que los derechos no están disponibles, esperarían, volverían a coger sus tenedores izquierdos simultáneamente, etc. eternamente. Esto implica un aplazamiento indefinido.
Figura 4.17. Una solución al problema de la cena de los filósofos
El lector podría pensar: "si los filósofos esperaran un tiempo arbitrario, en vez del mismo tiempo, después de que no pudieran coger el tenedor derecho, la probabilidad de que todo quedara bloqueado, incluso una hora, sería muy pequeña". Esta observación es correcta, pero en ciertas aplicaciones se desea una solución que funcione siempre, y no que pueda funcionar bien con gran probabilidad. (Piense en el control de seguridad de una planta nuclear).
Una mejora a la figura 4.16, que no tiene interbloqueos ni aplazamiento indefinido, es la protección de los cinco enunciados siguientes a la llamada al procedimiento pensar mediante un semáforo binario exmut. Antes de empezar a coger los tenedores, un filósofo haría un wait sobre exmut. Desde el punto de vista teórico esta solución es adecuada. Desde el punto de vista práctico presenta un error de eficiencia: en todo instante existirá a lo sumo un filósofo comiendo. Si se dispone de cinco tenedores, se debería permitir que dos filósofos comieran al mismo tiempo.
La solución que aparece en la figura 4.17 es correcta, y permite el máximo paralelismo para un número arbitrario de filósofos. Utiliza un vector,estado, para llevar un registro de la actividad de un filósofo: si está comiento, pensando o hambriento (estado que indica que quiere coger los tenedores). Un filósofo puede comer únicamente si los vecinos no están comiendo. Los vecinos del i-ésimo filósofo se definen en las macros IZQ yDER. En otras palabras, si i= 2, entonces IZQ = 1, y DER = 3.
El programa utiliza un vector de semáforos, uno por filósofo, de forma que los filósofos hambrientos puedan bloquearse si los tenedores necesarios están ocupados. Observe que cada proceso ejecuta el procedimiento filósofo como programa principal, pero los demás procedimientos,coger_tenedores, dejar_tenedores y prueba, son procedimientos ordinarios y no procesos separados.
9.4.2 El problema de los lectores y los escritores
El problema de la cena de los filósofos es útil para modelar procesos que compiten por el acceso exclusivo a un número limitado de recursos, como una unidad de cinta u otro dispositivo de E/S. Otro problema famoso es el de los lectores y escritores (Courtois et al., 1971), que modela el acceso a una base de datos. Supóngase una base de datos, con muchos procesos que compiten por leer y escribir en ella. Se puede permitir que varios procesos lean de la base de datos al mismo tiempo, pero si uno de los procesos está escribiendo (es decir, modificando) la base de datos, ninguno de los demás debería tener acceso a ésta, ni siquiera los lectores. La pregunta es ¿ cómo programaría los lectores y escritores ? La solución se muestra en la figura 4.18.
En esta solución, el primer lector que obtiene el acceso a la base de datos realiza un wait sobre el semáforo bd. Los lectores siguientes sólo incrementan un contador, nl. Al salir los lectores, éstos decrementan el contador, y el último en salir realiza un signal sobre el semáforo, lo que permite entrar a un escritor bloqueado, si existe.
Una hipótesis implícita en esta solución es que los lectores tienen prioridad sobre los escritores. Si surge un escritor mientras varios lectores se encuentran en la base de datos el escritor debe esperar. Pero si aparecen nuevos lectores, y queda al menos un lector accediendo a la base de datos, el escritor deberá esperar hasta que no haya más lectores interesados en la base de datos.
Figura 4.18. Una solución al problema de los lectores y escritores
9.5 Un ejemplo de aplicación cliente-servidor
En este apéndice vamos a ver cómo se pueden utilizar las primitivas de mensajes con designación directa proporcionadas por el sistema operativo para crear un servidor de ficheros, y un cliente que solicita sus servicios para copiar un fichero. Previamente se muestra cómo se puede realizar un programa que copie un fichero en un sistema en el que las operaciones con ficheros las proporciona el sistema operativo, y no un proceso de usuario como será el servidor de ficheros.
Comencemos estudiando cómo realizar un programa sencillo en C para MS DOS que copia un fichero fuente a un fichero destino. El listado del programa es el siguiente:
El programa tiene una funcionalidad mínima y un informe de los errores raquítico. El programa copyfile se puede llamar, por ejemplo, mediante la línea de órdenes:
para copiar el fichero abc a xyz. Si xyz ya existe, se escribe sobre él. En caso contrario, se crea. El programa debe invocarse con dos argumentos, dados por dos nombres válidos de ficheros.
Los enunciados #include hacen que un gran número de definiciones y prototipos de funciones se incluyan en el programa. La línea siguiente es un prototipo de función para main, necesario para ANSI C.
El enunciado #define es una definición de macro para la cadena BUF_SIZE, el cual se expande en el número 4096. El programa leerá y escribirá en bloques de 4096 bytes.
El programa principal se llama main y tiene dos argumentos, argc y argv. Estos son proporcionados por el sistema operativo cuando se llama al programa. El primer argumento indica el número de palabras presentes en la línea de órdenes, que debe ser tres. El segundo es un vector de punterosa los argumentos. En este ejemplo de llamada los elementos de este vector contienen punteros a los valores siguientes:
argv[0] = "copyfile"
argv[1] = "abc"
argv[2] = "xyz"
Mediante esta vía el programa tiene acceso a sus argumentos.
Se declaran cinco variables. Las dos primeras, src y dst, contienen los descriptores de fichero, son enteros pequeños asignados al abrir un fichero. Las dos siguientes, in y out son los contadores de bytes devueltos por las llamadas al sistema READ y WRITE respectivamente. La última, buf, es elbuffer utilizado para almacenar los datos leídos, y proporcionar los datos a escribir.
La primera instrucción condicional verifica si argc = 3. Si no es así, se termina el programa con código de estado 1. Por convención, un código de estado distinto de 0 indica la aparición de un error. El código de estado es el único informe de error presente en este programa. Una versión comercial mostraría también mensajes de error.
Después se intenta abrir el fichero fuente y crear el fichero destino. Si el fichero fuente se puede abrir, el sistema asigna un entero pequeño a src, para identificación del fichero. Las llamadas al sistema posteriores deben incluir este entero, de forma que el sistema operativo sepa con qué fichero se desea trabajar. Análogamente, si se puede crear el destino, se le da un valor a dst para identificarlo. Si la apertura o la creación fallan, el descriptor correspondiente toma el valor -1, y el programa termina con un código de error.
Después viene el ciclo de copiado, el cual comienza leyendo los datos en bloques de 4K hacia buf. Esto se realiza mediante la función de bibliotecaread, la cual utiliza la llamada al sistema READ. El primer parámetro especifica el fichero, el segundo el buffer, y el tercero el número de bytes a leer. La función read devuelve el número de bytes leídos (esto se guarda en in). Por lo general, este número es 4096, excepto en el caso de que en el fichero queden por leer menos de esos bytes. Cuando se llega al final del fichero, dicho número es 0. Si in es 0 o negativo, la copia no puede continuar, por lo que se ejecuta el enunciado break para finalizar el ciclo (que de otro modo continuaría de forma indefinida).
La llamada a write hace que el contenido del buffer pase al fichero destino. El primer parámetro identifica al fichero, el segundo al buffer, y el tercero indica el número de bytes a escribir, de forma análoga a read. Observe que el número de bytes que realmente se leen está dado por el contador de bytes, y no por BUF_SIZE. Esto es importante, puesto que el último buffer no será de tamaño 4096, a menos que el fichero tenga una longitud múltiplo de 4K.
Después de procesar todo el fichero, la siguiente llamada hace in = 0, con lo que se sale del ciclo. En este punto, se cierran los dos ficheros, y el programa finaliza con un código que indica su conclusión normal.
El ejemplo cliente servidor
En este punto se presenta una visión general de un servidor de ficheros, y un cliente que solicita sus servicios para copiar un fichero. Ambos programas están escritos en C. El cliente y el servidor deben compartir algunas definiciones, éstas se reunen en el fichero header.h, que se muestra en la figura 4.19. Tanto el cliente como el servidor lo incluyen mediante el uso del enunciado:
#include
Analizaremos primero header.h. Empieza con la definición de dos constantes, MAX_PATH y BUF_SIZE, las cuales determinan el tamaño de dos vectores necesarios en el mensaje. El primero indica el número de caracteres máximo que puede tener una trayectoria de fichero (como /etc/passwd). El segundo fija la cantidad de datos que se pueden leer o escribir en una operación, al establecer el tamaño del buffer. La constante siguiente,FILE_SERVER, proporciona la dirección en la red del servidor de ficheros, de forma que los clientes le puedan mandar mensajes.
Figura 4.19. El fichero header.h que utilizan el cliente y el servidor.
El segundo grupo de constantes define los números de operación, necesarios para garantizar que el cliente y el servidor estén de acuerdo en el código que representará una operación. Aquí sólo se muestran cuatro, en un sistema real lo normal es que sean más.
Toda respuesta contiene un código de resultado. Si la operación tiene éxito, es frecuente que este código contenga información útil (como el número de bytes que se leen en realidad). Si no existe un valor por devolver (como cuando se crea un fichero), se emplea el valor OK. Si por alguna razón la operación fracasa, el código de resultado indica por qué, mediante códigos tales como E_BAD_OPCODE, E_BAD_PARAM, etc.
Por último llegamos a la parte más importante de header.h, la definición del propio mensaje. En nuestro ejemplo, es una estructura o registro de 10 campos. Todas las solicitudes del cliente al servidor utilizan este formato, al igual que lo hacen las respuestas. En un sistema real tal vez no se tenga un formato fijo (puesto que no se necesitan los campos en todos los casos), pero esto hace más sencilla la explicación. Los campos source y destidentifican al emisor y al receptor respectivamente. El campo opcode es una de las operaciones definidas antes; es decir, CREATE, READ, WRITE oDELETE. Los campos count y offset se utilizan como parámetros, y otros dos campos, extra1 y extra2, se definen para disponer de un espacio adicional en el caso de que el servidor se modifique posteriormente. El campo result no se utiliza en las solicitudes del cliente al servidor, se utiliza para devolver un resultado en las respuestas del servidor al cliente. Por último, tenemos dos vectores. El primero, name, contiene la trayectoria del fichero al que se accede. El segundo, data, almacena los datos que se envían de vuelta como respuesta a un READ, o los datos que se envían al servidor en un WRITE.
Analicemos ahora el código de la figura A.20. En a) tenemos el servidor; en b) el cliente. El servidor es directo. El ciclo principal comienza con una llamada a receive para obtener un mensaje de solicitud. El primer parámetro identifica a quién hizo la llamada, mediante su dirección, el segundo apunta a un buffer de mensajes donde se guarda el mensaje que llegará. El procedimiento de biblioteca receive realiza una llamada al sistema para que se bloquee el servidor hasta que llegue un mensaje. Cuando llega una, el servidor se desbloquea y se encarga del tipo de opcode. Para cada opcode se llama a un procedimiento distinto. Se dan como parámetros el mensaje de entrada y un buffer para el mensaje de salida. El procedimiento examina el mensaje de entrada, m1, y construye la respuesta en m2. También devuelve el valor del resultado en el campo result. Después de terminar send, el servidor vuelve a la parte superior del ciclo para ejecutar receive y esperar a que llegue el siguiente mensaje.
En la figura 4.20 b) se ve un procedimiento para copiar un fichero utilizando el servidor. Su cuerpo consta de un ciclo que lee un bloque del fichero fuente y lo escribe en el fichero destino. El ciclo se repite hasta copiar todo el fichero fuente, lo cual se indica mediante un código de retorno de lectura nulo o negativo.
La primera parte del ciclo se encarga de construir un mensaje para la operación READ y enviarla al servidor. Después de recibir la respuesta, se entra en la segunda parte del ciclo, que toma los datos recién recibidos y los envía de vuelta al servidor en un WRITE al fichero destino. Los programas de la figura 4.20 son únicamente un bosquejo del código. Se han omitido muchos detalles. Por ejemplo, no se muestran los procedimientos do_xxx y no se realiza una verificación de los errores. Aún así, debe quedar clara la idea de la interacción del cliente y el servidor.
Fig 4.20 .Ejemplo Cliente_Servidor.
Del código del servidor se deduce que solamente puede atender a una petición a la vez. Si el servicio de una petición es muy lento, porque, por ejemplo, precisa realizar entradas/salidas, se pueden demorar las solicitudes de otros clientes. Una solución, en un sistema operativo que posea el concepto de hilo, es que el servidor al aceptar una petición cree un hilo para que la sirva, siendo éste el responsable de contestar al cliente. Así se pueden atender varias solicitudes concurrentemente, un hilo pueden aprovechar las E/S de los otros hilos para ejecutar su código. Hay que decir que algunos sistemas operativos no permiten la creación dinámica (en tiempo de ejecución) de hilos, y de estar permitida existe un máximo de hilos por proceso. Si la creación es estática (en tiempo de compilación), se pueden crear, por ejemplo, 5 hilos, y que cada uno reciba una solicitud, la tramite y responda a ella.
En este apartado, y en los dos siguientes, vamos a exponer tres ejemplos clásicos de
sincronización entre procesos, proponiendo su solución utilizando semáforos. El problema de los productores y los consumidores ejemplifica la sincronización de varios procesos "productores" y "consumidores", los procesos de un grupo controlan tanto el progreso de los procesos de su grupo como los del otro grupo.
Especifiquemos el problema. Un conjunto de procesos "productores" y un conjunto de procesos "consumidores" se comunican entre sí a través de unbuffer, en el que los productores van depositando elementos, y del cual, los consumidores los van sacando. Los productores llevan a cabo de forma continua un ciclo "producir un elemento - guardar el elemento en el buffer", y los consumidores repiten un ciclo parecido: "sacar un elemento del buffer- consumir el elemento". Un productor típico puede ser un proceso de tipo computacional que vaya colocando líneas de resultados en un buffer, mientras que el consumidor correspondiente puede ser el proceso que imprime estas líneas. El buffer tiene una capacidad limitada, pudiendo almacenar sólo N elementos del mismo tamaño. La sincronización que se requiere en este caso es doble: en primer lugar, los productores no pueden colocar elementos en el buffer si éste está lleno, y en segundo lugar, los consumidores no pueden sacar elementos del buffer si éste está vacío.
Además, el buffer y las variables compartidas deben protegerse del acceso concurrente por parte de los distintos procesos, pues son zonas compartidas de memoria modificables por los procesos. De ahí que el acceso al buffer y a las variables compartidas se realice en exclusión mutua.
La solución que se presenta utiliza un buffer circular, cuyos elementos son enteros, dos variables compartidas, que controlan dónde insertar o sacar elementos del buffer, y tres semáforos. Los programas se expresan en un lenguaje similar a C.
La sincronización se logra mediante los semáforos espacio y elementos, la exclusión mutua mediante el semáforo exmut. El operador % realiza la operación módulo (resto de la división entera).
10.0 INTERBLOQUEOS
10.1 Definiciones Previas
Cuando un proceso de un sistema de multiprogramación espera en balde a que se presente un evento específico, se dice que se encuentra en un estado de interbloqueo o bloqueo mutuo. Los procesos que pueden encontrase en esta situación pueden ser uno o varios.
En los sistemas de multiprogramación, compartir recursos es uno de los principales objetivos del sistema operativo. Cuando se comparten recursos entre una población de usuarios o procesos, cada uno de los cuales mantiene un control exclusivo sobre ciertos recursos asignados a él, es posible que se produzcan bloqueos mutuos que impedirán la terminación de algunos de los procesos del sistema.
Todos los interbloqueos suponen demandas contradictorias de recursos por parte de dos o más procesos. La figura 5.1 ilustra este conflicto de forma abstracta en el caso de dos procesos y dos recursos. Los dos ejes del diagrama representan el avance de los dos procesos en términos de instrucciones ejecutadas. El avance conjunto de los dos procesos se representa entonces con una secuencia discreta de puntos en el espacio. Las líneas horizontales o verticales representan el intervalo de tiempo en el que sólo uno de los procesos está ejecutándose (intercalado); una línea diagonal significa ejecución simultánea (solapamiento). Supóngase que existe un punto en la ejecución de cada proceso en el que se requiere el uso exclusivo de ambos recursos, R1 y R2, para continuar. En el ejemplo, llega un punto en el que el proceso P1 ha adquirido el recurso R1 y el proceso P2 ha adquirido el recurso R2, y cada proceso necesita el otro recurso. Este es el punto de interbloqueo.
En este tema se analizará el problema del interbloqueo y las distintas alternativas de solución que se pueden adoptar clasificadas en las siguientes cuatro áreas : prevención, evitación, detección y recuperación del bloqueo mutuo. Para cada una de las estrategias adoptadas, se analizará el equilibrio entre la sobrecarga debida a los mecanismos de corrección del interbloqueo y los beneficios que reportan. En algunos casos es excesivo el precio (gasto extra) que hay que pagar para conseguir a toda costa que no se produzcan interbloqueos. Sin embargo, en algunos casos, como en los sistemas de tiempo real, no hay más alternativa que pagar el precio, ya que puede resultar catastrófico permitir la posibilidad de un bloqueo mutuo.
Un problema afín : el aplazamiento indefinido
En cualquier sistema que mantenga los procesos en espera mientras se les asigna un recurso o se toman decisiones de planificación, la programación de un proceso puede postergarse indefinidamente mientras otro recibe la atención del sistema. Tal situación se conoce con varios nombres, entre los que se incluyen aplazamiento indefinido, bloqueo indefinido e inanición, y puede resultar tan peligrosa como el interbloqueo.
El aplazamiento indefinido puede ocurrir debido a predisposiciones en las políticas de planificación de recursos del sistema. Cuando los recursos se planifican por prioridad, es posible que un proceso dado espere de forma indefinida un recurso porque siguen llegando otros procesos con mayor prioridad. Los sistemas deben diseñarse para administrar los procesos en espera de manera justa además de eficiente. En algunos sistemas, el aplazamiento indefinido se evita aumentando la prioridad del proceso mientras espera (técnica de envejecimiento). En algún momento la prioridad de ese proceso superará la prioridad de los entrantes y el proceso en espera será atendido.
10.2 Casos de Interbloqueos
El caso más simple de interbloqueo sería el de un sólo proceso que espera la ocurrencia de un evento y, sin embargo, el sistema no incluye la posibilidad de señalar dicha ocurrencia. Es muy difícil detectar los bloqueos mutuos de esta naturaleza. La mayor parte de los bloqueos mutuos implican una competencia entre varios procesos por varios recursos.
Holt (1972) utilizó grafos dirigidos para representar situaciones de interbloqueo. Estos grafos tienen dos tipos de nodos : procesos, que se representan con círculos, y recursos, representados por cuadrados. Si in proceso está utilizando un recurso, previamente solicitado y concedido, se traza un arco desde el nodo del recurso (cuadrado) hasta el proceso (círculo). En la figura 2, el recurso R está en ese momento asignado al proceso A. En b), el proceso B está solicitando el recurso s. Por último en c) se representa un situación de interbloqueo : el proceso C está a la espera del recurso T, que está asignado al proceso D. El proceso D no ha dejado T, porque está esperando a que quede libre el recurso U, que, a su vez, está siendo utilizado por C. Ambos esperarán indefinidamente.
El siguiente ejemplo servirá para ilustrar el empleo de grafos de recursos. Supongamos que tenemos tres procesos, A, B y C, y tres recursos, R, S, y T. La figura 5.2 representa las secuencias de petición y liberación que realizan los tres procesos. El sistema operativo tiene en todo momento completa libertad para ejecutar cualquiera de los procesos que no estén bloqueados, así que, por ejemplo, podría decidirse a ejecutar A hasta que éste terminara su trabajo, después B hasta que acabe y, finalmente C.
Este secuenciamiento no produce interbloqueo, ( ya que no se compite por los recursos), pero suprime completamente el paralelismo. Además de pedir y liberar recursos, los procesos también realizan E/S y procesamiento de datos. Si se ejecutan uno tras otro, se elimina completamente la posibilidad de que, mientras uno de ellos está esperando que acabe una E/S, otro pueda utilizar el procesador.
Supongamos, sin embargo, que los procesos realizan tanto E/S como procesamiento de datos, de forma que la planificación por turno rotatorio es la más adecuada. En este caso, la secuencia de petición de recursos podría ser la representada en la figura 3 (d). Si las seis peticiones se llevan a cabo en ese orden, se producirían los seis grafos de los casos (e)-(j). Después de la petición 4, A está bloqueado en espera de captar S, como se muestra en (h). Los procesos B y C se bloquean en las dos etapas siguientes, lo que conduce finalmente a un bucle cerrado y al correspondiente interbloqueo representado en (j).
Figura 5.3 Ejemplo de Interbloqueo y como evitarlo.
El sistema operativo no está obligado a ejecutar los procesos en ningún orden en particular. En concreto, si la concesión de un recurso a un proceso determinado puede provocar interbloqueo, el sistema operativo es muy libre de suspender al proceso y no atender su petición hasta que esté seguro de que esto no conduce a una situación problemática. En la figura 5.3, por ejemplo, si el sistema operativo supiera que se avecinaba un interbloqueo, podría decidir suspender al proceso B antes de concederle el recurso S. La ejecución sólo de los procesos A y C produciría las secuencias de petición y liberación de la figura 5.3 (k), en lugar de las de la figura 5.3 (d). Esta secuencia de ejecución produce los grafos de recursos (l)-(q), y no produce interbloqueo.
Después de la etapa (q), no hay ningún problema en conceder S a B, ya que A ha terminado y C tiene todo lo que necesita. Aunque B se bloqueara al solicitar T, no se produciría interbloqueo; B simplemente esperaría hasta que terminara C.
10.3 Condiciones Necesarias para Producir un Interbloqueo
Coffman, Elphick y Shoshani (71) establecen que deben darse las siguientes cuatro condiciones necesarias para que ocurra un bloqueo mutuo.
Condición de exclusión mutua : los procesos exigen un control exclusivo de los recursos que necesitan.
Condición de espera : los procesos mantienen la posesión de los recursos ya asignados a ellos mientras esperan recursos adicionales.
Condición de no apropiación : los recursos no pueden arrebatarse a los procesos a los cuales están asignados hasta que termine su utilización.
Condición de espera circular : existe una cadena circular de procesos en la que cada proceso tiene uno o más recursos que son requeridos por el siguiente proceso en la cadena.
Como dichas condiciones son necesarias para que se presente un interbloqueo, la existencia de un bloqueo mutuo implica que se han dado todas y cada una de las cuatro condiciones. Como se verá más adelante, tener en mente semejante observación será de gran ayuda para desarrollar esquemas que eviten los interbloqueos.
10.4 Estrategias para Resolver Interbloqueos
Los resultados de la investigación sobre el bloqueo mutuo han sido satisfactorios en cuanto a que se han encontrado métodos limpios y rápidos para manejar la mayoría de los problemas más comunes. Existen cuatro áreas de interés relacionadas con los interbloqueos que pueden resumirse como prevención, técnicas para evitarlos, detección y recuperación de los mismos.
En la prevención del interbloqueo interesa ajustar el sistema para eliminar toda posibilidad de que ocurra un bloqueo mutuo. La prevención suele funcionar pero sus métodos ocasionan, en general, un aprovechamiento pobre de los recursos. No obstante, estos métodos se utilizan con frecuencia.
Las técnicas que tienen como objetivo evitar el interbloqueo imponen condiciones menos atractivas que en la prevención, para tratar de obtener un aprovechamiento de los recursos. No elimina como las técnicas de prevención todas las posibilidades de que se produzca un bloqueo mutuo, pero se esquiva cuanto está a punto de suceder (algoritmo del banquero de Dijkstra).
Los métodos de detección del interbloqueo es utilizan en sistemas que permiten la ocurrencia de los mismos, ya sea de manera voluntaria o involuntaria. Su objetivo es determinar si ha ocurrido un bloqueo mutuo y saber exactamente cuáles son los procesos y recursos implicados en él.
Los métodos de recuperación están íntimamente ligados a los de detección. Sirven para eliminar los interbloqueos detectados en un sistema para poder seguir trabajando y para que los procesos implicados puedan terminar su ejecución y liberen sus recursos. La recuperación es un problema complejo, en el mejor de los casos, los sistemas se recuperan de un bloqueo mutuo eliminando completamente uno o varios de los procesos implicados. Después, se inician de nuevo los procesos eliminados, perdiéndose la mayor parte o todo el trabajo previo realizado por el proceso.
10.4.1 Desentenderse. El Algoritmo de la Avestruz
La estrategia más sencilla es el algoritmo del avestruz : esconder la cabeza bajo tierra y pretender que el problema no existe. La gente reacciona a esta estrategia de distintos modos según su formación. Los matemáticos consideran que es inaceptable y argumentan que los interbloqueos se deben evitar a toda costa. Los ingenieros se interrogan sobre la frecuencia del problema, la frecuencia con el que el sistema se para por otras causas y la importancia de los interbloqueos. Si éstos se presentan de una vez cada cinco años, y los sistemas se paran una vez al mes por errores en el hardware, en elcompilador o en el sistema operativo, a casi ningún ingeniero le gustaría tener que sufrir una degradación seria de las prestaciones del sistema para garantizar la eliminación de los interbloqueos.
Por ejemplo, Unix pude sufrir interbloqueos que ni siquiera se detectan, y que, por supuesto, no se eliminan automáticamente. El número total de procesos en el sistema viene determinado por el número de posiciones de la tabla de procesos, que, en definitiva, constituye un recurso limitado. Supongamos ahora que un sistema Unix con 100 posiciones en la tabla de procesos tiene ejecutándose diez programas, cada uno de los cuales ha de crear 12 subprocesos. Después de que cada proceso haya creado otros 9, los 10 procesos originales y los 90 nuevos llenarán por completo la tabla. Los 10 procesos originales se encontrarán ahora en un bucle infinito intentando crear un nuevo proceso sin poder : se ha producido un interbloqueo. Otros ejemplos de recursos que suelen ser limitados son : el número máximo de ficheros que pueden estar abiertos está limitado, el área en el disco para intercambio con memoria principal. En realidad, casi todas las tablas del sistema operativo representan recursos limitados, ¿deberíamos, por tanto, limitar estos recursos para no producir un interbloqueo?
La estrategia UNIX es simplemente desentenderse del problema, suponiendo que la mayoría de los usuarios preferirán un interbloqueo ocasional antes que la imposición de que cada usuario pueda crear un solo proceso, abrir un solo fichero y usar sólo una unidad de lo que sea. Veremos a continuación que se puede adoptar alguna estrategia adecuada que nos permitirá prevenir, evitar o detectar y recuperar situaciones de interbloqueo.
10.4.2 Prevención de Interbloqueos
La estrategia empleada con más frecuencia por los diseñadores para tratar el bloqueo mutuo es la prevención. En esta sección se examinan los métodos de prevención, junto con los efectos que tienen sobre los usuarios y los sistemas, sobre todo desde la perspectiva del rendimiento.
Havender (68) llegó a la conclusión de que si falta alguna de las cuatro condiciones necesarias no puede haber un interbloqueo. Este autor sugiere las siguientes estrategias para negar varias de esas condiciones :
Cada proceso deberá pedir todos sus recursos al mismo tiempo y no podrá seguir la ejecución hasta haberlos recibido todos.
Si a un proceso que tiene recursos se le niegan los demás, ese proceso deberá liberar sus recursos y, en caso necesario, pedirlos de nuevo junto con los recursos adicionales.
Se impondrá un ordenamiento lineal de los tipos de recursos en todos los procesos ; es decir, si a un proceso le han sido asignados recursos de un tipo específico, en lo sucesivo sólo podrá pedir aquellos recursos que siguen en el ordenamiento.
Como vemos Havender presenta tres estrategias y no cuatro. Cada una de ellas, está diseñada para negar una de las condiciones necesarias. La primera de estas condiciones, esto es, que los procesos exijan el uso exclusivo de los recursos que requieren, es una condición que no es deseable impedir, porque específicamente queremos permitir la existencia de recursos no compartibles o dedicados.
Negación de la condición de espera
La primera de las estrategias requiere que los recursos que necesita un proceso sean pedidos de una sola vez. El sistema debe proporcionarlos según el principio de todo o nada. Si está disponible el conjunto de los recursos que necesita un proceso, entonces el sistema puede asignarle todos los recursos y éste seguir su ejecución. Si no está disponible alguno de ellos, el proceso debe esperar. Mientras espera no puede tener ningún recurso. Con esto se elimina la condición de espera y no puede ocurrir un interbloqueo.
Todo esto suena bien, pero puede llevar a un grave desperdicio de recursos. Supongamos que un proceso necesita diez unidades de un determinado recurso para su ejecución. Como debe solicitarlas todas antes de comenzar, los mantendrá en su poder durante toda su ejecución. Pudiera suceder, que el programa únicamente utilice estos recursos al principio de su ejecución, por tanto, los recursos están ociosos el resto del tiempo.
Dividir el programa en varios pasos que se ejecuten de manera relativamente independiente es una técnica empleada con frecuencia para conseguir una mejor utilización de los recursos en estas circunstancias. La asignación de recursos se controla por etapas. Esta solución reduce el desperdicio pero implica mucho trabajo extra tanto en el diseño de las aplicaciones como en al ejecución.
Por otro lado, esta estrategia puede provocar un aplazamiento indefinido, pues los recursos requeridos pueden no estar disponibles todos al tiempo. El sistema podría, entonces, permitir que se fueran acumulando recursos hasta conseguir todos los que necesita un proceso. Pero mientras se acumulan no se pueden asignar a otros procesos y volvemos a infrautilizarlos.
Negación de la condición de no apropiación
La segunda estrategia de Havender consiste en liberar los recursos que un proceso tiene asignados cuando se le niegan peticiones de recursos adicionales. De esta forma, se anula la condición de no apropiación. Los recursos se pueden quitar al proceso que los tiene antes de que termine su ejecución.
En este caso también existe un costo excesivo. Cuando un proceso libera recursos puede perder todo el trabajo realizado hasta ese momento. El costo puede parecer muy alto, pero la pregunta es : ¿con qué frecuencia ha de pagarse ese precio ? Si ocurre de tarde en tarde, entonces éste parece ser un buen método para prevenir el interbloqueo. Si, por el contrario, es muy frecuente, entonces el costo es sustancial y sus efectos demasiado perjudiciales (por ejemplo, para procesos de alta prioridad o plazo fijo).
Esta estrategia también adolece de aplazamiento indefinido. Un proceso puede aplazarse continuamente mientras pide y libera muchas veces los mismo recursos. Si esto ocurre, el sistema puede verse obligado a eliminar el proceso para que otros puedan ejecutarse.
Negación de la condición de espera circular
La tercera estrategia de Havender anula la posibilidad de un espera circular. Como todos los recursos tienen una numeración única y como los procesos deben pedir los recursos en un orden lineal ascendente, es imposible que se presente una espera circular (figura 5.4). Esta estrategia presenta las siguientes dificultades :
Los recursos deben pedirse en un orden ascendente por número de recursos. El número de recurso es asignado por la instalación y debe tener un tiempo de vida largo (meses o años) . Si se agregan nuevos tipos de recursos, puede ser necesario reescribir los programas y los sistemas.
Lógicamente, cuando se asignan los números de recursos, éstos deben reflejar el orden normal en que los usan la mayoría de las tareas. Pero los procesos que necesiten los recursos en un orden diferente que el previsto por el sistema, los deberán adquirir y conservar, quizá durante tiempo antes de utilizarlos realmente, lo que significa un desperdicio considerable.
Una de las metas más importantes de los sistemas operativos actuales es crear ambientes amables con el usuario. Los usuarios deben ser capaces de desarrollar sus aplicaciones sin tener en cuenta molestas restricciones de hardware y software. El ordenamiento lineal impide al usuario escribir sus códigos libremente.
10.4.3 Evitación de Interbloqueos
Aún presentándose las condiciones para un interbloqueo, todavía es posible evitarlo mediante una asignación cuidadosa de los recursos. Tal vez el algoritmo más famoso para evitar el interbloqueo sea el algoritmo del banquero de Dijkstra (73), cuyo interesante nombre se debe a que atañe a un banquero que otorga préstamos y recibe pagos a partir de una determinada fuente de capital.
Algoritmo del Banquero
En principio, estudiaremos este algoritmo suponiendo que todos los recursos del mismo tipo. Considérese la asignación de una cantidad t, de unidades de cintas idénticas.
Un sistema operativo comparte un número fijo, t, de unidades de cinta entre un número fijo de, p, de procesos. Cada proceso especifica por adelantado el número máximo de unidades de cinta que necesitará durante su ejecución. El sistema operativo aceptará la petición de un usuario si la necesidad máxima de ese proceso no es mayor que t. Un proceso puede obtener o liberar unidades de cinta una a una. Algunas veces un usuario puede verse obligado a esperar para obtener una unidad adicional, pero el sistema operativo garantiza una espera finita. El número real de unidades asignadas a un proceso nunca será superior a la necesidad máxima declarada por ese usuario. Si el sistema operativo es capaz de satisfacer la necesidad máxima del proceso, entonces éste debe garantizar al sistema operativo que las unidades de cinta serán utilizadas y liberadas en un tiempo finito.
Se dice que el estado del sistema es seguro si el sistema operativo puede garantizar que todos los procesos terminan en un tiempo finito. En otro caso, el sistema está en un estado inseguro.
Sea préstamo (i) la representación del préstamo actual de unidades de cinta para el proceso i. Sea máx(i) la necesidad máxima de cintas de un proceso y, por último, sea petición (i) la petición actual del usuario, que es igual a su necesidad máxima menos el préstamo actual. Por ejemplo, el proceso 7 tiene una necesidad máxima de 6 unidades y un préstamo actual de 5, entonces tiene
petición(7) = máx(7) - préstamo(7) = 6 - 5 = 2
El sistema operativo controla t unidades de cinta. Sea a el número de unidades de cinta todavía disponibles para asignar. Entonces a es igual a t menos la suma de los préstamos de los usuarios.
El algoritmo del banquero permite la asignación de unidades de cinta a los usuarios solamente cuando la asignación conduzca a estados seguros, y no a estados inseguros. Un estado seguro es una situación tal en la que todos los procesos son capaces de terminar en algún momento. Un estado inseguro es aquel en el cual puede presentarse un bloqueo mutuo.
Ejemplo de estado seguro
Supóngase que un sistema tiene doce unidades de cinta y tres procesos que las comparten.
La tabla anterior representa un estado seguro porque el proceso 2 tiene un préstamo de 4 unidades y necesita como máximo 6, o sea, 2 más. El sistema tiene 12 de las cuales 10 están en uso y mantiene 2 disponibles. Si las que están disponible se asignan al proceso 2, cubriendo su demanda máxima, este proceso podrá terminar. Al acabar, devolverá todos los recursos, 6 unidades de cinta, y el sistema podrá asignarlas al proceso 1 y al 3. De esta forma, la clave de un estado seguro es que exista al menos una forma en la que terminen todos los procesos.
Ejemplo de estado inseguro
Ahora 11 de las 12 unidades de cinta están asignadas y solamente hay una disponible. En este momento, no se puede garantizar que terminen los tres procesos. Si el proceso 1 pide y obtiene la última unidad de cinta y los tres vuelven a solicitar una unidad de cinta más se produciría un bloqueo triple.
Es importante señalar, que un estado inseguro no implica la existencia, ni siquiera eventual, de un interbloqueo. Lo que sí implica un estado inseguro es la posibilidad de que ocurra por una desafortunada secuencia de eventos.
Ejemplo de transición de estado seguro a estado inseguro
Saber que un estado es seguro no implica que serán seguros todos los estados futuros. La política de asignación de recursos debe considerar cuidadosamente todas las peticiones antes de satisfacerlas. Por ejemplo supongamos la situación que se muestra en la siguiente tabla.
Ahora supóngase que el proceso 3 pide un recurso más. Si el sistema satisface esta petición, el nuevo estado será el que se muestra en la tabla de abajo.
Según vemos, aunque, en principio el sistema no estaba bloqueado, ha pasado de un estado seguro a uno inseguro. La última de las tablas caracteriza un sistema en el cual no puede garantizarse la terminación de todos los procesos. Solamente hay un recurso disponible, pero deben estarlo al menos dos para asegurar que el proceso 2 o el 3 puedan terminar, devolver sus recursos al sistema y permitir que los otros procesos acaben.
Algoritmo del banquero para múltiples recursos
Figura 5.5 Algoritmo del banquero para múltiples recursos
La figura 5.5 representa dos matrices. La de la izquierda muestra el número de recursos asignados en ese instante (préstamo actual) a cada uno de los cinco procesos. En la derecha aparece el número de recursos que todavía necesita cada proceso para llevar a cabo su función (petición). Al igual que el caso de un único recurso, los procesos deben comunicar sus necesidades máximas antes de empezar a ejecutarse, de forma que en todo momento el sistema pueda calcular la matriz de la derecha.
Para describir los recursos existentes en el sistema, los que están en posesión y los que están disponibles, emplearemos tres vectores como los siguientes : E =(6342), P=(5322) y D=(1020). E indica que el sistema tiene 6 unidades de cinta, 3 trazadores, 4 impresoras y 2 cdrom. De ellos se están utilizando 5 unidades de cinta, tres trazadores gráficos, dos impresoras y dos cdrom. Esto se puede deducir sin más que sumar las cuatro columnas de recursos en préstamo de la matriz izquierda. El vector de recursos disponibles es simplemente la diferencia ente lo que el sistema tiene y lo que está usando en ese momento.
Ahora estamos en condiciones de describir en qué consiste el algoritmo de comprobación de estado seguro :
1.-Buscar una fila, F, cuyas necesidades de recursos sean menores o iguales a D. Si no existe tal fila, el sistema puede interbloquearse, ya que ningún proceso puede ejecutarse hasta el final.
2.-Suponer que el proceso de la fila seleccionada solicita todos los recursos que necesita, y termina. Marcar el proceso como terminado y añadir sus recursos al vector D.
3.-Repetir las etapas 1 y 2 hasta que se vayan marcando todos los procesos como terminados (en cuyo caso el estado inicial era seguro) o hasta que se llegue a una situación de interbloqueo (en cuyo caso no lo era).
En el caso de que se pueda seleccionar más de un proceso en el paso 1, la elección sería indiferente: en cualquier caso, el conjunto de recursos disponibles aumenta o, en el peor de los casos, se queda igual.
Volviendo al ejemplo de la figura 5.5 . El estado actual es seguro. Supongamos que el proceso B solicita la impresora. Dado que el estado resultante es todavía seguro, esta petición puede concederse (el proceso D puede terminar, seguido por los procesos A o E y a continuación el resto).
Imaginemos ahora que, después de que B obtiene una de las dos impresoras restantes, E solicita la última impresora. Si se le concede esta petición, el vector de recursos disponibles se reduciría a (1 0 0 0), situación que produce interbloqueo. Por lo tanto, la petición de E debe posponerse de momento.
Ahora debe estar claro cómo opera el algoritmo del banquero de Dijkstra cuando asigna recursos. Están permitidas las condiciones de espera circular, espera y no apropiación, pero los procesos sí exigen el uso exclusivo de los recursos que requieren. Los procesos pueden conservar recursos mientras piden y esperan recursos adicionales y los recursos no pueden arrebatarse a los procesos que los tienen. Los procesos facilitan el trabajo al sistema pidiendo un solo recurso a la vez. El sistema puede satisfacer o rechazar cada petición. Si una petición es rechazada, el proceso conserva los recursos que ya tiene asignados y espera un tiempo finito a que se satisfaga la petición. El sistema sólo satisface peticiones que llevan a estados seguros. Una petición que condujese a un estado inseguro se rechazaría repetidamente hasta que pueda quedar satisfecha. Como el sistema se mantiene en un estado seguro, tarde o temprano (en un tiempo finito) todas las peticiones podrán ser atendidas y los procesos terminarán.
Defectos del algoritmo del banquero
El algoritmo del banquero es interesante porque ofrece una forma de asignar los recursos que evita el interbloqueo. Permite ejecutar procesos que tendrían que esperar seguramente con alguna de las estrategias de prevención. Sin embargo, tiene varios defectos importantes :
El algoritmo requiere un número fijo de recursos asignables. Como los recursos a menudo requieren servicio, ya sea por algún fallo o por mantenimiento preventivo, no se puede contar con que será siempre constante.
El algoritmo requiere una población de usuarios constantes. En los sistemas multiprogramables y más en los de tiempo compartido, la población de usuarios cambia constantemente, incluso en cuestión de segundos.
El algoritmo requiere que el banquero satisfaga todas las peticiones en un tiempo finito. Es evidente que en los sistemas reales esto no es una garantía suficiente.
De manera similar, el algoritmo requiere que los procesos salden sus préstamos (es decir, devuelvan sus recursos) en un tiempo finito. Una vez más, esto es insuficiente para un sistema de tiempo real.
El algoritmo requiere que los usuarios declaren por anticipado sus necesidades máximas. A medida que la asignación de recursos se hace más dinámica, conocer las necesidades máximas de un usuario presenta mayor dificultad. De hecho, ahora que los sistemas ofrecen interfaces gráficas, cada vez es más común que los usuarios no tengan la menor idea de los recursos que necesitan.
En resumen, los métodos descritos anteriormente en el apartado de prevención son demasiado restrictivos, mientras que los de evitación que acabas de estudiar requieren información de la que, generalmente, no se dispone.
10.4.4 Detección y Recuperación de Interbloqueos
La detección del bloqueo mutuo es el proceso de determinar si realmente existe un interbloqueo e identificar los procesos y recursos implicados en él. Los algoritmos de detección determinan por lo general si existe una espera circular.
El empleo de algoritmos de detección del interbloqueo implica cierto gasto extra durante la ejecución. Así pues, se presenta de nuevo la cuestión de costeabilidad, tan habitual en los sistemas operativos, ¿el gasto extra debido a los algoritmos de detección del bloqueo mutuo se justifica con los ahorros potenciales debidos a la localización y solución de los interbloqueos?
Para facilitar la detección de interbloqueos, se utilizará una notación en la que un grafo dirigido indica las asignaciones y peticiones de recursos. Los cuadrados representan procesos; los círculos grandes, clases de dispositivos idénticos; los círculos pequeños de color rojo en el interior de los grandes indican el número de dispositivos de cada clase. Por ejemplo, si un círculo grande etiquetado como R1 contiene tres círculos pequeños, significa que ya tres recursos del tipo R1 disponibles para asignación en este sistema.
Figura 5.6 Gráfica de Asignación y Petición de recursos.
La figura 5.6 muestra las relaciones que pueden indicarse en una gráfica de asignación y petición de recursos. Por ejemplo, en (a) el proceso P1 está pidiendo un recurso del tipo R1. La flecha que parte de P1 toca solamente el extremo del círculo grande, lo cual implica que se está estudiando la petición. En (b), el proceso P2 tiene asignado un recurso del tipo R2 (del cual existen dos unidades). La flecha va del círculo pequeño que se encuentra dentro del círculo grande R2 al cuadrado P2. En (c), el recurso R3 ha sido solicitado por el proceso P3, pero ya se ha asignado al proceso P4. Por último, en (d), se representa un interbloqueo. El proceso P5 tiene el recurso R5 que está siendo solicitado por el proceso P6, que tiene el recurso R4 que está siendo solicitado por el proceso P5 (una espera circular).
Reducción de las gráficas de asignación de recursos
Una técnica útil para detectar los interbloqueos consiste en ir reduciendo una gráfica determinando los procesos que pueden completar su ejecución. Si pueden atenderse las peticiones de recursos de un proceso, se dice que la gráfica puede ser reducida por ese proceso. Esta reducción es equivalente a mostrar la gráfica como si el proceso hubiese acabado y hubiera devuelto los recursos al sistema. Si una gráfica puede ser reducida por todos sus procesos, entonces no hay interbloqueo. Si una gráfica no puede ser reducida por todos sus procesos, los procesos irreductibles constituyen el conjunto de procesos en bloqueo mutuo de la gráfica (figura 5.7).
Cuando se ha bloqueado un sistema, el interbloqueo debe romperse mediante la eliminación de una o más de las condiciones necesarias. Por lo general, varios procesos perderán una parte o la totalidad del trabajo efectuado, pero el precio pagado puede ser pequeño, en comparación con las consecuencias de permitir que el sistema siga bloqueado. La recuperación después de un bloqueo mutuo se complica por varias razones :
Puede no estar claro que el sistema se haya bloqueado.
La mayor parte de los sistemas tienen medios muy deficientes para suspender indefinidamente un proceso, eliminarlo del sistema y reanudarlo más tarde. De hecho, algunos procesos como los de tiempo real, que deben funcionar continuamente, sencillamente no se pueden suspender y reanudar.
Aún cuando existieran medios efectivos de suspensión/reanudación, con toda seguridad implicarían un gasto extra considerable.
La recuperación después de un bloqueo mutuo de dimensiones modestas puede significar una cantidad razonable de trabajo, un interbloqueo a gran escala puede requerir una cantidad enorme de trabajo.
En los sistemas actuales la recuperación se suele realizar eliminado un proceso y arrebatándole sus recursos. Por lo general, el proceso eliminado se pierde pero ahora es posible concluir los procesos restantes. Algunas veces es necesario eliminar varios procesos hasta que se hayan liberado los recursos suficientes para que terminen los procesos restantes.
Los procesos pueden eliminarse de acuerdo con algún orden de prioridad. También existen dificultades para ello :
Es posible que no existan prioridades entre los procesos bloqueados, de modo que se tiene que adoptar una decisión arbitraria.
Las prioridades pueden ser incorrectas o un poco confusas debido a consideraciones especiales, como la planificación a plazo fijo, en la cual un proceso de prioridad relativamente baja tiene una prioridad temporal alta a causa de un fin de plazo inminente.
La determinación de una decisión óptima sobre los procesos que se deben eliminar puede requerir un esfuerzo considerable.
Parece ser que el enfoque más deseable para la recuperación después de un bloqueo mutuo sería un mecanismo efectivo de suspensión/reanudación. Ello implicaría suspender temporalmente los procesos y reanudarlos después sin pérdida de trabajo productivo. Para ello sería deseable la posibilidad de especificar puntos de verificación/reinicio. De este modo, se facilita la suspensión/reanudación, que se hará desde el último punto de verificación (es decir, la última grabación del estado del sistema). Pero muchos sistemas de aplicación se diseñan sin aprovechar las ventajas de las funciones de punto de verificación/reinicio. Por lo general, se requiere un esfuerzo consciente por parte de los diseñadores para incorporar la verificación/reinicio, y a menos que las tareas requieran muchas horas de ejecución, su uso es poco común.
10.4 Estrategias para Resolver Interbloqueos
Los resultados de la investigación sobre el bloqueo mutuo han sido satisfactorios en cuanto a que se han encontrado métodos limpios y rápidos para manejar la mayoría de los problemas más comunes. Existen cuatro áreas de interés relacionadas con los interbloqueos que pueden resumirse como prevención, técnicas para evitarlos, detección y recuperación de los mismos.
En la prevención del interbloqueo interesa ajustar el sistema para eliminar toda posibilidad de que ocurra un bloqueo mutuo. La prevención suele funcionar pero sus métodos ocasionan, en general, un aprovechamiento pobre de los recursos. No obstante, estos métodos se utilizan con frecuencia.
Las técnicas que tienen como objetivo evitar el interbloqueo imponen condiciones menos atractivas que en la prevención, para tratar de obtener un aprovechamiento de los recursos. No elimina como las técnicas de prevención todas las posibilidades de que se produzca un bloqueo mutuo, pero se esquiva cuanto está a punto de suceder (algoritmo del banquero de Dijkstra).
Los métodos de detección del interbloqueo es utilizan en sistemas que permiten la ocurrencia de los mismos, ya sea de manera voluntaria o involuntaria. Su objetivo es determinar si ha ocurrido un bloqueo mutuo y saber exactamente cuáles son los procesos y recursos implicados en él.
Los métodos de recuperación están íntimamente ligados a los de detección. Sirven para eliminar los interbloqueos detectados en un sistema para poder seguir trabajando y para que los procesos implicados puedan terminar su ejecución y liberen sus recursos. La recuperación es un problema complejo, en el mejor de los casos, los sistemas se recuperan de un bloqueo mutuo eliminando completamente uno o varios de los procesos implicados. Después, se inician de nuevo los procesos eliminados, perdiéndose la mayor parte o todo el trabajo previo realizado por el proceso.
10.5 Interbloqueos: Sistemas Actuales/Sistemas Futuros
En los sistemas actuales, el interbloqueo se ha considerado generalmente como una molestia limitada. La mayor parte de los sistemas siguen los métodos básicos de prevención sugeridos por Havender, y tales métodos parecen ser satisfactorios.
Sin embargo, en los sistemas futuros el bloqueo mutuo será una consideración mucho más importante por varias razones :
Los sistemas futuros estarán más orientados hacia operaciones asíncronas en paralelo que hacia las operaciones en serie. El multiprocesamiento es ya muy común y la computación paralela será dominante así como la proliferación de redes y sistema distribuidos. En pocas palabras, se realizarán más operaciones en paralelo, habrá más conflictos por los recursos y, por tanto, más oportunidad de que aparezca un interbloqueo.
En los sistemas futuros, la asignación tenderá a ser dinámica. Los procesos podrán adquirir y liberar recursos según sus necesidades. Los usuarios no necesitarán saber mucho acerca de sus requisitos de recursos antes de la ejecución de un programa. De hecho, con las interfaces cada vez más amables, la mayoría de los usuarios no se preocupan demasiado por el consumo de los recursos de sus procesos.
Con la creciente tendencia de los diseñadores de sistemas operativos a contemplar los datos como un recurso más, aumentará notablemente el número de recursos que debe administrar un sistema operativo.
Por lo tanto, la tarea de asignar recursos sin la posibilidad de interbloqueos en los sistemas de cómputo recaerá sobre el sistema operativo. Con el abaratamiento y la creciente potencia de los recursos, es razonable que se amplíen las funciones de la computadora y del sistema operativo.
UNIDAD 3 11.0 “ADMISTRACIÓN DE LA MEMORIA”
11.1 La organización y gestión de la memoria. Conceptos generales
Para que un proceso pueda ejecutarse debe estar ubicado en la memoria principal del ordenador. Una parte del sistema operativo se va a encargar de gestionar la memoria principal, de forma que los procesos puedan residir en la memoria sin conflictos. La gestión de la memoria implica varias tareas, una de ellas es llevar un registro de qué zonas están libres (es decir, no están siendo utilizadas por ningún proceso), y qué zonas están ocupadas por qué procesos. Otra tarea importante surge en sistemas en los que no todos los procesos, o no todo el código y datos de un proceso, se ubican en la memoria principal. En estos sistemas, a menudo se debe pasar parte, o la totalidad del código y datos de un proceso, de memoria a disco, o viceversa; siendo el sistema operativo responsable de esta tarea. De esta forma se libera al usuario de realizar estas transferencias de información, de las cuales no es consciente.
Otros dos temas importantes en la gestión de la memoria son el de la carga de los programas de disco a memoria y el de la protección. Desde el momento en que varios procesos deben compartir la memoria del ordenador surge el problema de la protección. En general, se pretende que un proceso no pueda modificar las direcciones de memoria en las que no reside. Esto es así ya que en las direcciones de memoria donde no está ubicado el proceso pueden residir otros procesos, o código o estructuras de datos del S.O. Si un proceso puede modificar indiscriminadamente la memoria, podría, por ejemplo, cambiar el valor de una dirección de memoria donde residiera una variable de otro proceso, con la consecuente ejecución incorrecta del proceso propietario de la variable. Algunos sistemas ni siquiera permiten que un proceso pueda leer las direcciones de memoria en las que no reside, con esto se consigue privacidad sobre el código y datos de los procesos. Conforme avance este tema y el siguiente se profundizará en todos estos aspectos.
Existen varias formas de gestionar la memoria. Por lo común, la forma de gestión dependerá de la máquina virtual que se quiera proporcionar y delhardware subyacente. Con independencia de la forma de gestión es necesario decidir qué estrategias se deben utilizar para obtener un rendimiento óptimo. Las estrategias de administración de la memoria determinan el comportamiento de una organización de memoria determinada cuando se siguen diferentes políticas: ¿ Cuándo se coge un nuevo programa para colocarlo en la memoria ? ¿ Se coge el programa cuando el sistema lo necesita, o se intenta anticiparse a las peticiones del sistema ? ¿ En qué lugar de la memoria principal se coloca el siguiente programa por ejecutar ? ¿ Se colocan los programas lo más cerca posible unos de otros en los espacios disponibles de la memoria principal para reducir al mínimo el desperdicio de espacio, o se colocan lo más rápido posible para reducir el tiempo empleado en tomar la decisión ?
Los sistemas actuales son en su mayor parte sistemas con almacenamiento virtual, muchas de la formas de gestión estudiadas en este tema tienen principalmente valor histórico, pero sientan las bases de los sistemas actuales.
Jerarquía de la memoria
Los programas y datos necesitan estar en la memoria principal para ser ejecutados, o para poder ser referenciados. Los programas o datos que no se necesitan de inmediato pueden guardarse en la memoria secundaria hasta que se necesiten, y en ese momento se transfieren a la memoria principal para ser ejecutados o referenciados. Los soportes de memoria secundaria, como cintas o discos, son en general menos caros que la memoria principal, y su capacidad es mucho mayor. Normalmente, es mucho más rápido el acceso a la memoria principal que a la secundaria.
En los sistemas con varios niveles de memoria hay muchas transferencias constantes de programas y datos entre los distintos niveles. Estas transferencias consumen recursos del sistema, como tiempo de la CPU, que de otro modo podrían utilizarse provechosamente.
En los años sesenta se hizo evidente que la jerarquía de la memoria podía extenderse un nivel más, con una clara mejora del rendimiento. Este nivel adicional, la memoria caché, es una memoria de alta velocidad, mucho más rápida que la memoria principal. La memoria caché es extremadamente cara, si se compara con la principal, por lo que sólo se utilizan memorias caché relativamente pequeñas. La figura 6.1 muestra la relación que existe entre la memoria caché, la principal y la secundaria.
La memoria caché introduce un nivel adicional de transferencia de información en el sistema. Los programas en memoria principal se pasan a la memoria caché antes de ejecutarse. En la memoria caché se pueden ejecutar mucho más rápido que en la principal. La esperanza de los diseñadores es que el trabajo extra requerido por la transferencia de programas sea mucho menor que el incremento del rendimiento obtenido por la ejecución más rápida en la caché.
11.2 Gestión de la memoria en los sistemas monoprogramados
En los sistemas de monoprogramación sólo existe un proceso de usuario, que disfruta de todos los recursos del ordenador. Esto va a simplificar notablemente la gestión de la memoria, ya que ésta sólo debe ser compartida por los programas del sistema operativo, y por el único proceso de usuario existente. Esto se muestra en la figura 6.2. Dependiendo de detalles de diseño, el sistema operativo ocupará la parte baja de la memoria RAM, como se muestra en la figura 6.2 (a); o la parte alta de la memoria ROM, como se muestra en la figura 6.2 (b). El PC de IBM ubica parte del sistema operativo en RAM, y los gestores de dispositivos en ROM; a esta última parte se le llama BIOS (Basic Input/Output System, sistema básico de entrada/salida), esto último se ilustra en la figura 6.2 (c).
Si el usuario conoce la ubicación en la memoria del sistema operativo, entonces puede escribir programas en términos de direcciones absolutas de memoria. Una dirección absoluta de memoria es una dirección física (es decir, real) de la memoria. En contraposición se tienen las direcciones relativas. Un programa está escrito en término de direcciones relativas cuando se escribe suponiendo que empieza a cargarse en la dirección cero de la memoria. Por lo general, los usuarios escriben programas en lenguajes de alto nivel, por lo que son los traductores los encargados de generar las direcciones que ocupan las variables, procedimientos, etc, en la memoria. Los compiladores no generan direcciones absolutas de memoria, pues no saben dónde se almacenarán los procesos.
Por lo común, los sistemas operativos monousuario de monoprogramación (muy comunes en las microcomputadoras) no tienen protección de la memoria. Por lo tanto, el único proceso de usuario que existe en la memoria, puede modificar posiciones de memoria pertenecientes al sistema operativo, esto provocaría errores al ejecutarse la zona modificada. La protección se puede realizar mediante un registro de límite integrado en la CPU. Si se tiene un esquema como el de la figura 6.2 (b) el registro de límite contendrá la dirección de inicio de carga del S.O. El hardware, en tiempo de ejecución, verifica que las direcciones generadas por el proceso de usuario no son superiores al valor del registro de límite. En caso de ser superior, el proceso de usuario intenta acceder al S.O., esto provoca una interrupción hardware que gestiona el S.O., normalmente eliminando al proceso.
11.3 Gestión de la memoria en los sistemas multiprogramados
En un sistema de multiprogramación la memoria debe ser compartida por varios procesos de cara a obtener una mayor utilización de los recursos del ordenador. Esto provoca que la gestión de la memoria se complique sustancialmente. En primer lugar, hay que llevar un recuento de las zonas de memoria ocupadas por los procesos. Así, cuando un nuevo proceso entre en la memoria se le asignará una zona que estaba libre. Otro problema a resolver viene dado por el hecho de que en el momento de escribir un programa no se sabe en qué zona de memoria se ubicará, siendo posible que durante la vida de un proceso éste cambie varias veces de emplazamiento. Habrá que tener en cuenta, también, la protección de las zonas de memoria ocupadas por los procesos, máxime en sistemas multiusuario donde los procesos pueden pertenecer a distintos usuarios.
En lo que resta de este tema, y en el tema siguiente, se estudiarán varias formas de gestión de la memoria utilizadas en sistemas de multiprogramación.
11.4 Asignación de memoria contigua
En un esquema de asignación de memoria contigua un proceso se ubica en su totalidad en posiciones consecutivas de memoria. Un ejemplo de este tipo de asignación es el utilizado en los sistemas de monoprogramación vistos previamente. En este apartados se estudian dos métodos de asignación contigua empleados históricamente en sistemas multiprogramados.
11.4.1 Particiones estáticas
Esta forma de gestión consiste en dividir la memoria en varias zonas, pudiendo ser cada zona de un tamaño diferente. Esto se ilustra en la figura 6.3. El tamaño de las zonas podrá ser modificado eventualmente por algún usuario responsable de la administración del ordenador.
Los trabajos se traducían mediante compiladores y ensambladores absolutos, para ejecutarse en una partición específica. Una vez introducido un proceso en una partición, permanece en ella hasta su finalización. Si un trabajo se iniciaba, y la partición para la que estaba compilado estaba ocupada, tenía que esperar, aunque estuvieran libres otras particiones. Esto provoca una pérdida de eficiencia.
De cara a mejorar el rendimiento es preciso que un proceso se pueda cargar en cualquier partición. Para ello, los programas se escriben en términos de direcciones relativas a la dirección de comienzo de carga cero. Sin embargo, los programas no se cargan a partir de la dirección cero, esta circunstancia se debe resolver mediante la reasignación o reubicación, ¿cómo se realiza ésta ?. Una posible implantación viene proporcionada por el hardware. Existe un registro, denominado registro base, en el que el sistema operativo, dentro de la operación de cambio de proceso, escribe la dirección de memoria a partir de la cual se almacenó el proceso. Esta dirección coincidirá con la de comienzo de la partición en que reside, y forma parte de su descriptor(PCB). Cuando la CPU genera una dirección de memoria, ésta es transformada por el hardware antes de ser introducida en el bus del sistema. La transformación consiste en sumarle a la dirección el registro base.
Para clarificar esto, supóngase que la instrucción que actualmente ejecuta la CPU guarda el contenido del acumulador en la dirección relativa 100 de la memoria. Esta dirección, 100, (que podría, por ejemplo, guardar el contenido de una variable de otro proceso) es relativa a una dirección 0 de comienzo del programa. Si el programa se ha cargado en la posición 10000 de la memoria, el registro base contendrá el valor 10000. Cuando la CPU ejecuta la instrucción, genera la dirección 100 de memoria (la cual físicamente pertenece a otro proceso). Sin embargo, el hardware suma 10000 a este valor, introduciéndose 10100 en el bus del sistema, dirección que realmente ocupa la variable. Observe que con este esquema, si se quiere reubicar el proceso a otro lugar de la memoria, sólo hay que desplazarlo de lugar, y modificar el registro base con la nueva dirección de comienzo de carga.
Una solución software al problema de la reasignación consiste en modificar las instrucciones cuando el programa se carga en la memoria. Para que esto ocurra es preciso que el enlazador (el programa que a partir de los ficheros objeto genera un único objeto) incluya en el programa binario una lista que indique qué partes del programa son direcciones a reasignar, y cuáles no (constantes, códigos de operadores u otros elementos que no deban ser reasignados). Con esta solución, cada reubicación en la memoria implica una reasignación de las direcciones de memoria del programa.
Protección
Si se tiene el esquema hardware del registro base, para lograr la protección de las zonas de memoria basta con añadir un nuevo registro, denominadoregistro límite. Este registro guarda la última dirección de la partición, y forma también parte del PCB del proceso. El hardware, después de sumar el registro base a la dirección relativa, comprueba que la dirección obtenida no supere el valor del registro límite. Si se supera el valor, se está intentando acceder a una zona que no corresponde al proceso; en esta situación, el hardware genera una interrupción. El sistema operativo sirve a la interrupción, lo normal es que mande una señal al proceso por violación de memoria. Si el proceso no tiene definido atrapar esa señal, lo cual es lo más probable, se eliminará al proceso.
Cuando un proceso quiera ejecutar código del sistema operativo, por ejemplo, para realizar una E/S, no tiene acceso directo a las rutinas que tiene el sistema operativo en memoria para implementar dicha función, sino que debe realizar una llamada al sistema para no violar la protección. Este esquema es necesario, pues los programas de usuario tienen que avisar al sistema operativo de que le solicitan servicios (al hacer una llamada al sistema), el sistema operativo atenderá las peticiones si son correctas, o si pueden ser factibles en dicho momento (por ejemplo, no se asignará una impresora que está siendo utilizada por otro proceso). Los procesos de usuario no pueden llamar directamente al sistema operativo gracias a la protección de memoria.
Una última observación, al margen de la protección: cuando un proceso se introduce en una partición, lo más probable es que su tamaño no sea el mismo (es decir, sea algo menor) que el de la partición. Esto origina un problema de desperdicio de memoria conocido como fragmentación interna.
11.4.2 Particiones dinámicas
En este método se va asignando la memoria dinámicamente a los procesos, conforme se introducen en la memoria. A cada proceso se le asigna exactamente la memoria que necesita.
En la figura 6.4 se ilustra cómo evoluciona la ocupación de la memoria en un sistema de este tipo. Al principio sólo se encuentra el proceso A en la memoria. Después, se insertan los procesos B y C . En la figura 6.4-d A concluye. Luego, D entra y B sale. Por último E entra.
Con este método de gestión de la memoria se evita el problema de la fragmentación interna. Sin embargo, aparece el problema de la fragmentación externa entre particiones, el cual se aprecia en la figura 6.4-f. El problema consiste en que se creen huecos libres demasiado pequeños como para que quepan procesos, aunque la unión de todos esos huecos produciría un hueco considerable, lo que acarrea el desperdicio de la memoria. Una posible solución es la compactación de la memoria, que consiste en desplazar todos los procesos hacia la parte inferior de la memoria mientras sea posible. Como la compactación lleva mucho tiempo, a veces no se realiza, o se hace por la noche, en horas de poco uso del ordenador. Hay que tener en cuenta que el sistema debe detener todas sus actividades mientras realiza la compactación. Ello puede ocasionar tiempos de respuesta irregulares para usuarios interactivos, y podría ser devastador en un sistema de tiempo real. Además, con una combinación normal de trabajos que cambia rápidamente, es necesario compactar a menudo. En este caso, los recursos del sistema que se consumen quizá no justifiquen las ventajas de la compactación.
El esquema de los registro base y límite sigue siendo válido para la reasignación y la protección. Otro tema a tener en cuenta es la cantidad de memoria por asignar a un proceso recién creado. Si los procesos se crean con un tamaño fijo invariante, la asignación es muy sencilla, se asigna exactamente lo que se necesite.
Si, por el contrario, los segmentos de datos de los procesos pueden crecer, como es el caso de la asignación dinámica de memoria a partir de una pila, que ocurre en muchos lenguajes de programación, aparece un problema cuando un proceso intenta crecer. Si hay un hueco adyacente al proceso, éste puede ser asignado, y el proceso podrá crecer hacia el hueco. Sin embargo, si el proceso es adyacente a otro proceso, el proceso de crecimiento deberá ser desplazado a un hueco de la memoria lo suficientemente grande; o bien, habrá que eliminarlo.
Si es de esperar que la mayoría de los procesos crezcan conforme se ejecuten, sería una buena idea asignar un poco de memoria adicional siempre que un proceso pase a la memoria, con el fin de reducir el gasto excesivo asociado con el traslado de procesos que ya no caben en su memoria asignada. En la figura 5-a vemos una configuración de la memoria en la que se asignó a dos procesos el espacio adicional para el crecimiento.
Si los procesos pueden tener dos segmentos de crecimiento, como por ejemplo, el segmento de datos, que se utiliza como una pila, y el stack, se sugiere un método alternativo, el de la figura 5-b. En esta figura se puede ver que cada proceso tiene un stack de crecimiento hacia abajo, en la parte superior de la memoria asignada a él; además, tiene un segmento de datos justo encima del programa, el cual crece hacia arriba. La memoria entre ellos se puede utilizar para cualquiera de los segmentos. Si el espacio se agota, puede ocurrir que el proceso sea desplazado a un hueco con el espacio suficiente; o bien, ser aniquilado.
Registro de la ocupación de la memoria
En el sistema de particiones estáticas es sencillo llevar el registro de la ocupación de la memoria, basta con guardar sobre cada partición si está libre, u ocupada por qué proceso, así como sus direcciones de comienzo y fin de partición. Por contra, con las particiones dinámicas, el número de éstas varía con el tiempo, así como su tamaño. Una forma posible de registrar la ocupación de la memoria es utilizar una lista enlazada de los segmentos de la memoria asignados o libres. La memoria de la figura 6.6-a se presenta en la figura 6-c como una lista enlazada de segmentos. Cada entrada de la lista especifica un hueco (H) o un proceso (P), la dirección donde comienza, su longitud, y un puntero a la siguiente entrada.
En este ejemplo, la lista de segmentos está ordenada por direcciones. Este orden tiene la ventaja de que al terminar un proceso la actualización de la lista es directa. Un proceso que termina, tiene dos vecinos (a menos que se encuentre en la parte superior o inferior de la memoria). Estos pueden ser procesos o huecos, lo que produce las cuatro combinaciones de la figura 6.7. En la figura 6.7-a, la actualización de la lista requiere el reemplazo de una P por una H. En la figura 6.6 (b) y (c), dos entradas se funden en una, y la lista se acorta en una entrada. En la figura 6.6-d tres entradas se fusionan en una. Puesto que en el descriptor del proceso que termina se guardará un puntero a la entrada de la lista enlazada que ocupa dicho proceso, sería conveniente que la lista fuera doblemente enlazada. Esta estructura facilita la búsqueda de la entrada anterior y, por tanto, la verificación de si es posible una fusión.
Figura 6.6. (a) Una parte de la memoria, con cinco procesos y 3 huecos. La marca muestra las unidades de asignación de la memoria. Las regiones sombreadas ( 0 en el mapa de bits) están libres. (b) El mapa de bits correspondiente. (c) La misma información como lista enlazada.
11.4.3 Estrategias de colocación
Cuando en un sistema de particiones dinámicas se debe asignar memoria principal para un nuevo proceso, y los procesos y huecos se mantienen en una lista ordenada por direcciones, se pueden utilizar diversos algoritmos para la elección del hueco de memoria donde ubicar al proceso. Supongamos que se conoce la cantidad de memoria por asignar.
El algoritmo más simple es el primero en ajustarse (first fit). Se revisa la lista de huecos hasta encontrar un espacio lo suficientemente grande. El espacio se divide entonces en dos partes, una para el proceso, y otra para la memoria no utilizada, excepto en el caso poco probable de un ajuste perfecto. Este algoritmo es rápido, ya que busca lo menos posible.
Otro algoritmo es el mejor en ajustarse (best fit), el cual busca en toda la lista, y elige el mínimo hueco suficientemente grande como para ubicar al proceso. Este algoritmo intenta que los huecos que se creen en la memoria sean lo más pequeños posible.
Como ejemplo de los algoritmos, retomemos la figura 6.6. Si se necesita un bloque de tamaño 2, el primero en ajustarse asignará el espacio en 5, mientras que el mejor en ajustarse asignará el espacio en 18.
Realizando simulaciones se ha demostrado que el algoritmo del mejor ajuste desperdicia más la memoria, pues al crear huecos demasiado pequeños, éstos no pueden ser utilizados por procesos. Un algoritmo que enfrenta el problema de la manera contraria es el del peor ajuste (worst fit). En este algoritmo se elige el hueco más grande disponible. De esta forma aumenta la probabilidad de que el nuevo hueco creado sea lo suficientemente grande como para albergar un proceso.
11.4.4 Intercambio (swapping)
En un sistema con particiones estáticas el número de procesos con posibilidades de estar en estado listo viene determinado por el número de particiones, y en uno de particiones dinámicas por el tamaño de la memoria principal y el tamaño de los procesos, ya que en ambos métodos un proceso permanece en una partición hasta que finaliza. Supongamos un sistema en que dicho número es cinco, es muy probable que en un momento dado los cinco procesos que ocupan las particiones estén bloqueados (por ejemplo, porque esperan la finalización de una operación de E/S). Mientras los cinco procesos permanezcan bloqueados se desperdicia la CPU. Para remediar este inconveniente muchos sistemas operativos optaron por permitir ejecutar concurrentemente más procesos de los que pueden entrar físicamente en la memoria principal del ordenador. Para ello se utiliza la memoria secundaria (generalmente los discos) que, aunque más lenta, tiene mayor capacidad de almacenamiento que la principal. La solución consiste en tener en disco una copia de la parte de la memoria que ocupa todo proceso. En el disco se encuentran todos los procesos, en la memoria sólo unos cuantos. Para que un proceso se pueda ejecutar debe residir en memoria principal.
La razón por la que se aumenta el número de procesos con posibilidades de tener instrucciones en memoria principal es porque cuanto mayor sea este número, es menos probable que se dé la circunstancia de que todos estén bloqueados y, por lo tanto, es menor la posibilidad de que la CPU permanezca inactiva.
Algunos sistemas UNIX utilizaban el intercambio en un sistema de particiones dinámicas. El movimiento de procesos entre la memoria principal y el disco lo realizaba el planificador de nivel medio, conocido como el intercambiador (swapper a medio plazo). El intercambio de la memoria principal al disco (swapping out) se iniciaba cuando el S.O. precisa memoria libre y estaba toda ocupa debido a alguno de los siguientes eventos:
Una llamada al sistema fork que necesitaba memoria para un proceso hijo.
Una llamada al sistema brk de solicitud de memoria dinámica en un proceso que no tiene suficiente memoria libre como para aceptar la petición.
Una pila que se agranda, y ocupa un espacio mayor al asignado.
Además, cuando había que recuperar un proceso presente en el disco (swapping in) desde hace mucho tiempo con frecuencia se necesitaba sacar a otro proceso de memoria a disco para disponer de espacio para el primero.
El intercambiador elegía una víctima al examinar los procesos bloqueados en espera de algo (por ejemplo, una entrada del terminal). Es mejor sacar a un proceso bloqueado (pasará a estado suspendido_bloqueado) que sacar a uno listo. Si existían varios procesos bloqueados ubicados en la memoria principal se elegía a uno cuya combinación de prioridad y tiempo de residencia en memoria principal fuera más desfavorable. Así, un buen candidato era un proceso que hubiera consumido mucho tiempo de CPU recientemente, al igual que uno que hubiera permanecido en la memoria durante mucho tiempo, aun cuando durante este tiempo hubiera realizado E/S. Si no se dispone de procesos bloqueados, entonces se elegía a un proceso listo en base a los mismos criterios.
Cada pocos segundos el intercambiador examinaba la lista de procesos intercambiados para ver si alguno estaba listo para su ejecución. En caso de que existiera alguno, se seleccionaba a aquel que hubiese permanecido en el disco durante mucho tiempo. A continuación el intercambiador verificaba si el intercambio sería fácil o difícil. Un intercambio fácil era aquel en el que existiera la suficiente memoria libre, de forma que no había necesidad de sacar a un proceso para hacer espacio para el nuevo. Un intercambio difícil precisaba la eliminación de uno o más procesos. La implantación de un intercambio fácil se llevaba a cabo al traer el proceso a la memoria. Un intercambio difícil se implantaba liberando primero la memoria suficiente sacando a disco a uno o más procesos, y después, cargando en la memoria el proceso deseado.
Este algoritmo se repetía hasta que se cumpliera alguna de estas condiciones: (1) ningún proceso en el disco está suspendido_listo; o (2) la memoria está tan ocupada por procesos recién traídos que no hay espacio para más. Para evitar un trasiego excesivo entre memoria y disco que pudiera afectar al rendimiento no se intercambiaba hacia el disco a un proceso hasta que hubiera permanecido en la memoria durante 2 segundos.
El espacio libre en la memoria principal y en el dispositivo de intercambio se registraba mediante una lista enlazada de huecos. Si se necesitaba espacio en alguno de los dos, el algoritmo del primero en ajustarse leía la lista adecuada de huecos, y devolvía el primer hueco que encontrara y que fuese lo bastante grande, a la vez que eliminaba este espacio de la lista de huecos.
11.5 Asignación de memoria no contigua.
Hasta ahora se han estudiado esquemas de administración de la memoria en los que los procesos se almacenan en posiciones contiguas (consecutivas) de memoria. Sin embargo, un proceso puede dividirse en bloques, y estos bloques pueden situarse en posiciones no contiguas de memoria principal. Es más, no es preciso que se encuentren en la memoria todos los bloques de un proceso para que se pueda ejecutar, basta con que se encuentren los bloques que contienen código o datos actualmente referenciados, el resto puede permanecer en memoria secundaria.
La memoria virtual
La clave del concepto de memoria virtual es la disociación de las direcciones a las que hace referencia un proceso en ejecución de las direcciones disponibles en la memoria principal.
Las direcciones a las que hace referencia un proceso en ejecución, en este esquema, se llaman direcciones virtuales. El intervalo de direcciones virtuales a las que puede hacer referencia un proceso en ejecución se llama espacio de direcciones virtuales, V, del proceso. El intervalo de direcciones reales de la memoria principal de un ordenador concreto se llama espacio de direcciones reales, R. El número de direcciones de V se denota |V|, y el número de direcciones de R, |R|. En los sistemas de almacenamiento virtual ya implantados lo normal es que |V| >> |R|, aunque se han construido sistemas en los que |V| < |R|.
La memoria virtual es una técnica de gestión de la memoria que posibilita que el espacio de direcciones virtuales sea mayor al espacio de direcciones reales. En otras palabras, se permite hacer programas de tamaño mayor al de la memoria principal. Para lograr esto, el sistema operativo se encarga de mantener en la memoria principal solamente aquellas partes del espacio de direcciones del proceso que actualmente están siendo referenciadas, el resto permanece en disco.
La memoria virtual se basa en el hecho de que muchos programas presentan un comportamiento conocido como operación en contexto, según el cual, en cualquier intervalo pequeño de tiempo un programa tiende a operar dentro de un módulo lógico en particular, sacando sus instrucciones de una sóla rutina y sus datos de una sóla zona de datos. De esta forma, las referencias de memoria de los programas tienden a agruparse en pequeñas zonas del espacio de direcciones. La localidad de estas referencias viene reforzada por la frecuente existencia de bucles: cuanto más pequeño sea el bucle, menor será la dispersión de las referencias. La observación de este comportamiento conduce al postulado (Denning, 1970) del llamado principio de localidad: "Las referencias de un programa tienden a agruparse en pequeñas zonas del espacio de direcciones. Estas zonas, además, tienden a cambiar sólo de forma intermitente".
La validez del principio de localidad varía de programa en programa: será, por ejemplo, más válido en programas que lleven a cabo accesos secuenciales a vectores que en programas que accedan a estructuras complejas de datos.
La memoria virtual se compagina con la multiprogramación. Al no tener que almacenar los procesos enteros en la memoria, pueden entrar más en la memoria principal, con lo que es más probable que siempre exista un proceso en estado listo. Por otro lado, cuando un proceso espera a que se cargue en la memoria principal parte de su código o datos, se inicia una E/S con el disco. Mientras dura dicha E/S la CPU puede ejecutar otro proceso.
Aunque los procesos sólo hacen referencia a direcciones virtuales, deben ejecutarse en la memoria real. Por lo tanto, durante la ejecución de un proceso es preciso establecer la correspondencia entre las direcciones virtuales y las reales. Como se verá más adelante esta correspondencia debe realizarse de una manera rápida, pues si no, se ralentizaría demasiado el tiempo de ejecución de los procesos.
Se han desarrollado varios métodos para asociar las direcciones virtuales con las reales. Los mecanismos de traducción dinámica de direccionesconvierten la direcciones virtuales en direcciones reales en tiempo de ejecución. Todos estos sistemas tienen la propiedad de que las direcciones contiguas en el espacio de direcciones virtuales de un proceso no son necesariamente contiguas en la memoria principal. Esto se conoce comocontigüidad artificial (fig. 6.8). Debe quedar claro que toda esta correspondencia es transparente al programador, que escribe sus programas en términos de direcciones consecutivas de memoria virtual.
11.5.1 Esquema general de traducción
Los mecanismos de traducción dinámica de direcciones deben mantener mapas de correspondencia de traducción de direcciones que indiquen qué localidades de la memoria virtual están en memoria principal en un momento dado y dónde se encuentran.
Existen dudas en cuanto a si los bloques en que se dividen los procesos deben ser del mismo tamaño o de tamaños diferentes. Cuando los bloques son del mismo tamaño, se llaman páginas, y la organización de la memoria virtual correspondiente se conoce como paginación. Cuando los bloques pueden tener tamaños diferentes se llaman segmentos, y la organización de la memoria virtual correspondiente se llama segmentación. Algunos sistemas combinan ambas técnicas, con segmentos, que son entidades de tamaño variable, compuestas de páginas de tamaño fijo ( Segmentación paginada ).
Las direcciones en un sistema de correspondencia son bidimensionales. Para referirse a un elemento en particular, el programa especifica el bloque en el que se encuentra el elemento, y su desplazamiento a partir del inicio del bloque. Una dirección virtual, v, se denota por un par ordenado (b,d), donde bes el número de bloque en el que se encuentra el elemento al que se hace referencia, y d es el desplazamiento a partir del inicio del bloque.
La traducción de una dirección virtual v = (b,d) a una dirección real, r, se ejecuta de la siguiente forma (fig. 9). Cada proceso tiene su propia tabla de correspondencia de bloques, mantenida por el sistema operativo dentro de la memoria principal. Un registro especial dentro de la CPU, denominadoregistro de origen de la tabla de correspondencia de bloques, se carga con la dirección real, a, de la tabla de correspondencia de bloques del proceso durante el cambio de proceso. La tabla contiene una entrada por cada bloque del proceso, y las entradas siguen un orden secuencial para el bloque 0, el bloque 1, etcétera. Ahora se suma el número de bloque, b, a la dirección base, a, de la tabla de bloques, para formar la dirección real de la entrada del bloque b en la tabla de correspondencia de bloques. Esta entrada contiene la dirección real, b', de inicio del bloque b. El desplazamiento, d, se suma a la dirección de inicio del bloque, b', para formar la dirección real
deseada, r = b' + d.
Todas las técnicas de correspondencia de bloques empleadas en los sistemas de segmentación, paginación, y paginación y segmentación combinada son similares a la correspondencia mostrada en la figura 6.9.
Es importante señalar que la traducción de una dirección virtual a real la realiza una unidad hardware, que transforma todas las direcciones generadas por la CPU antes de que pasen al bus del sistema. Es esencial que esta transformación la realice el hardware, y no el sistema operativo, pues muchas instrucciones máquina incluyen referencias a memoria, y la correspondencia debe realizarse rápidamente, para no ralentizar en exceso el tiempo de ejecución de los procesos. Por ejemplo, las dos sumas indicadas en la figura 6.9 deben ser más rápidas que las sumas convencionales del lenguaje máquina.
Aunque el hardware consulta las tablas de correspondencia de bloques para la transformación de direcciones, es el sistema operativo el encargado de rellenar y gestionar dichas tablas. Un proceso no tiene por qué tener todos sus bloques en memoria principal, recuérdese que el espacio de direcciones virtuales puede ser muy superior al espacio de direcciones reales, esto hace que a veces un proceso referencie a una dirección de un bloque que no se encuentra en la memoria principal. Para detectar esto, las tablas de correspondencias tienen un "bit de presencia" por entrada (cada entrada representa un bloque), que indica si el bloque se encuentra presente en la memoria principal o no. El hardware de traducción debe verificar este bit en cada referencia a memoria.
Si el bloque no está en memoria principal, el hardware produce una interrupción. Esta interrupción provoca que el control pase al software (sistema operativo), para que éste inicie la transferencia del bloque que falta desde la memoria secundaria a la memoria principal, y actualice de acuerdo con ello la tabla de correspondencias. El proceso en ejecución se hará no listo hasta que se haya completado esta transferencia. La posición de los bloques en la memoria secundaria puede guardarse en la misma tabla de correspondencias.
11.5.2 Paginación
El concepto de almacenamiento a un sólo nivel, en el que la memoria secundaria aparece como una extensión de la memoria principal, se introdujo por primera vez en el ordenador Atlas de la Universidad de Manchester alrededor de 1960, y desde entonces ha ejercido una profunda influencia en el diseño de los ordenadores.
El almacenamiento a un sólo nivel puede llevarse a cabo mediante una técnica llamada paginación, según la cual el espacio de direcciones virtuales se divide en páginas del mismo tamaño (en el Atlas eran de 512 palabras). La memoria principal se divide también en marcos o páginas físicas del mismo tamaño. Estos marcos son compartidos entre los distintos procesos que haya en el sistema, de forma que en cualquier momento un proceso dado tendrá unas cuantas páginas residentes en la memoria principal (sus páginas activas) y el resto en la memoria secundaria (sus páginas inactivas). El mecanismo de paginación cumple dos funciones:
Llevar a cabo la transformación de una dirección virtual a física, o sea, la determinación de la página a la que corresponde una determinada dirección de un programa, así como del marco, si lo hay, que ocupa esta página;
Transferir, cuando haga falta, páginas de la memoria secundaria a la memoria principal, y de la memoria principal a la memoria secundaria cuando ya no sean necesarias.
La primera función se aborda a continuación, y se deja para el siguiente tema la segunda función.
Con el fin de determinar la página a la que hace referencia un programa, los bits de mayor peso de la dirección se interpretan como el número de página, y los bits de menor peso como el número de palabra dentro de esta página. De ahí que si el tamaño de página es 2n, los n bits finales de la dirección representarán el número de palabra y los bits restantes del principio el número de página. El número total de bits en la dirección es suficiente para direccionar la totalidad de la memoria virtual. Así, por ejemplo, en el Atlas las direcciones de programa tenían 20 bits de longitud, proporcionando una memoria virtual de 220 palabras; el tamaño de la página era de 512 palabras (29), y de ahí que los 9 bits inferiores representasen el número de palabra y los 11 superiores representasen el número de la página. El número total de páginas en la memoria virtual era por tanto de 211 (en contraposición a las 32 páginas físicas de que disponía la memoria principal).
Es de destacar el hecho de que la división de la dirección en número de palabra y número de página, es tarea del hardware, y es transparente al programador: por lo que a Jl concierne está programando en un espacio secuencial de direcciones muy grande.
La transformación de número de página y de palabra en la dirección física de memoria se realiza a través de una tabla de páginas, cuyo p-ésimo elemento contiene la posición p' del marco que contiene a la página p (la posibilidad de que la p-ésima página no se encuentre en la memoria principal se abordará dentro de un momento). El número de palabra, w, se suma a p' para obtener la dirección buscada (ver la figura 10).
La transformación de direcciones consiste, pues, en:
f(a) = f(p, w) = p' + w
donde la dirección de programa, a, el número de página, p, y el número de palabra, w, están relacionados con el tamaño de página Z a través de:
p = parte entera de (a/Z)
w = resto de (a/Z)
Así pues, cada vez que la CPU genere una dirección de memoria ésta es transformada por una unidad hardware, de forma que en el bus del sistema se introduce la dirección física correspondiente. Es importante observar que la paginación es en sí misma una forma de reubicación dinámica. Cada dirección lógica es transformada en alguna dirección física por el hardware de paginación. Observe también que si el tamaño de página (como es lo usual) es una potencia de dos, el hardware no precisa realizar ninguna división, simplemente sabe que los últimos n bits, si el tamaño de página es de 2n, representan el desplazamiento, y los primeros bits la página.
Cada proceso debe tener su propia tabla de páginas, y su dirección de comienzo en la memoria principal forma parte de la porción del PCB utilizada para realizar un cambio de proceso.
Como el número de marcos (cantidad de memoria real) asignados a un proceso será normalmente menor que el número de páginas que éste utiliza, es muy posible que una dirección del programa haga referencia a una página que no se encuentre en aquel momento en la memoria principal. En este caso el elemento correspondiente de la tabla de páginas estará vacío, provocando el hardware una interrupción de "fallo de página" si se intenta acceder a ella. Esta interrupción provoca que el control pase al software (al sistema operativo), para que éste inicie la transferencia de la página que falta desde la memoria secundaria a la memoria principal, y actualice de acuerdo con ello la tabla de páginas. El proceso en ejecución se hará no listo hasta que se haya completado esta transferencia. La posición de las páginas en la memoria secundaria puede guardarse en una tabla separada o en la misma tabla de páginas. En este último caso, es necesario un "bit de presencia" en cada elemento de la tabla de páginas, para indicar si la página se encuentra presente o no en la memoria principal, y si el campo de direcciones debe interpretarse como una dirección de marco, o bien como una dirección de la memoria secundaria.
Si no existe ningún marco vacío en el momento en que ocurre un fallo de página, hay que guardar en la memoria secundaria alguna otra página con el fin de hacer sitio a la nueva. La elección de la página que habrá que sacar es el resultado de un algoritmo de reemplazo de página, del cual veremos varios ejemplos en el tema siguiente. Por el momento, vamos a destacar tan sólo el hecho de que la información que necesita el algoritmo de cambio de página, puede estar contenida en algunos bits adicionales que se añaden a cada elemento de la tabla de páginas.
Quizás habría que aclarar, que toda la operación de transformaciones de direcciones la lleva a cabo el hardware, excepto en el caso en que haya que traer una página de la memoria secundaria. En este caso, la aplicación del algoritmo de cambio de página, así como la actualización de la tabla de páginas, las lleva a cabo el software.
La anterior discusión proporciona una visión general de cómo funciona la paginación. En la práctica hay que hacer una serie de modificaciones para llegar a una implementación viable. Una de ellas es que la transformación de dirección virtual a física debe ser rápida.
11.5.2.1 Memoria asociativa
En el sistema que hemos descrito el tiempo necesario para cada referencia a memoria queda doblado, debido a la necesidad de acceder primero a la tabla de páginas. Una forma de evitarlo podría ser la de tener guardada la tabla de páginas en un conjunto de registros rápidos en lugar de sobre la memoria ordinaria. Sin embargo, el tamaño de la tabla de páginas es proporcional al tamaño del espacio de direcciones virtuales; de ahí que el número de registros necesarios sea demasiado grande para que esta alternativa resulte económicamente viable. La solución al problema consiste en adoptar una técnica diferente para acceder a las páginas activas. Esta técnica representa el tener que incorporar a la máquina una memoria asociativa, que consistirá en un pequeño conjunto de registros de dirección de página (PARs, del inglés page address registers), cada uno de los cuales contiene el número de página de una página activa. Los PARs presentan la propiedad de poderse buscar en ellos de forma simultánea el número de página asociado a una dirección de programa en particular.
Por ejemplo, en la figura 6.11, la dirección de programa 3243 se divide en el número de página 3 y el número de palabra 243 (vamos a suponer, por comodidad, que el tamaño de la página sea 1000). El número de página se compara entonces de forma simultánea con el contenido de todos los PARs, y se encuentra que coincide con el valor del PAR 5. Ello indica que la página 3 ocupa en la actualidad la página física número 5, de forma que la dirección buscada será la 5243.
El empleo de un almacenamiento de tipo asociativo reduce el tiempo empleado en la transformación de direcciones en un orden de magnitud con respecto al caso en el que se guardaba la tabla de páginas sobre memoria principal.
Con el fin de que se pueda hacer referencia a todas las páginas activas a través de un PAR, hay que disponer de tantos como marcos haya en la memoria. Ello es posible en sistemas con una memoria principal reducida (como por ejemplo, el Atlas), pero en sistemas mayores no es viable, desde el punto de vista económico, disponer de todos los PARs necesarios para ello (aunque es de esperar que estos argumentos de tipo económico cambien a medida que se desarrolla la tecnología). Se puede llegar a una solución de compromiso, guardando para cada proceso una tabla de páginas completa en la memoria, y utilizando una pequeña memoria asociativa para referenciar unas pocas páginas asociadas a los procesos activos más recientes. En este caso, el marco al que hará referencia cada PAR, no vendrá implícito por la situación de éste, sino que deberá incluirse como un campo adicional en el mismo PAR. El hardware de direccionamiento de la memoria lleva a cabo, entonces, la operación de transformación de direcciones que se muestra en la figura 6.12. Como antes, sólo se requiere la intervención del software en el caso de que haya que sustituir una página.
Un problema que no ilustra la figura 6.11 es el de distinguir en la memoria asociativa las páginas asociadas al proceso en ejecución de las páginas correspondientes a otros procesos. Una solución consistiría en ampliar los PARs para incluir la identificación de los procesos, junto con el número de la página. Cada dirección que se presente a la memoria asociativa deberá incluir, según esto, el identificador del proceso junto con los bits de la página.
Evidentemente, es de desear que la memoria asociativa contenga los números de las páginas a las que haya mayores posibilidades de acceder. Lamentablemente, no existe ningún algoritmo general que nos asegure que así suceda (véase el siguiente tema). En la práctica se cargan cíclicamente en la memoria asociativa las direcciones de las páginas a las que se ha hecho referencia con más frecuencia recientemente. Este algoritmo, más bien primitivo, es, de hecho, bastante eficaz.
El porcentaje de veces que se encuentra un número de página entre los registros asociativos está relacionado claramente con el número de registros asociativos. Con 8 o 16 registros asociativos, puede obtenerse un porcentaje del 80 al 90%. Un porcentaje del 80% significa que el 80% de las veces encontramos el número de página deseado entre los registros asociativos. Si explorar los registros asociativos lleva 50 nanosegundos, y 750 nanosegundos acceder a memoria, entonces un acceso a memoria "mapeada" lleva 800 nanosegundos cuando el número de página se encuentra en los registros asociativos. Si no conseguimos encontrar el número de página (50 ns), entonces tenemos que acceder a la memoria en primer lugar para buscar el número de marco en la tabla de páginas (750 ns) y entonces acceder a la palabra deseada en memoria (750 ns), dando en total 1550 nanosegundos. Para encontrar el tiempo efectivo de acceso a memoria, tenemos que ponderar cada caso con su probabilidad:
t. efectivo de acceso a memoria = 0,80 x 800 + 0,20 x 1550 = 950 ns
En este ejemplo, sufrimos un 26,6% de retardo en el tiempo de acceso a memoria (de 750 a 950 nanosegundos).
11.5.2.2 Páginas compartidas
Otra ventaja de la paginación es la posibilidad de compartir programas de uso corriente. Esto es particularmente importante en un entorno de tiempo compartido. Consideremos un sistema que soporta 40 usuarios, cada uno de los cuales ejecuta un editor de textos. Si el editor de textos consta de 30K de código y 5K de espacio para datos, necesitaríamos 1400K para permitir a los 40 usuarios. No obstante, si el programa es reentrante, podría compartirse como se muestra en la figura 6.13. Aquí vemos un editor de tres páginas que es compartido por tres procesos. Cada proceso tiene su propia página de datos
El código reentrante (también llamado código puro) es un código no automodificable. Si el código es reentrante, entonces nunca cambia durante la ejecución. Así, dos o más procesos pueden ejecutar el mismo código al mismo tiempo. Cada proceso, para su ejecución, tiene su PCB y su memoria para mantener los datos. Por supuesto, los datos de todos esos procesos diferentes varían para cada uno de ellos.
Tan sólo hace falta mantener una copia del editor en la memoria física. Cada tabla de páginas de usuario-proceso hace referencia a la misma copia física del editor, pero las páginas de datos lo hacen a marcos diferentes. Así, para permitir 40 usuarios, precisamos solamente una copia del editor, 30K, más 40 copias del espacio de 5K por usuario. El espacio total requerido es ahora de 230K, en lugar de 1400K, un ahorro significativo.
También pueden compartirse otros programas muy utilizados: compiladores, ensambladores, sistemas de bases de datos, etc. Para que sea compartible, el código tiene que ser reentrante (no automodificable). Este término significa que nunca debería darse una tentativa de almacenar algo en el código, que es de sólo búsqueda o sólo lectura. Obviamente, es crucial que las páginas compartidas sean inamovibles. Si un usuario cambiara una posición, cambiaría para todos los usuarios. La naturaleza de sólo lectura del código compartido no debería dejarse a merced de la corrección del código. El sistema operativo debe reforzar esa propiedad.
11.5.2.3 Protección
La protección de la memoria en un entorno paginado se consigue por medio de unos bits de protección asociados a cada página. Normalmente estos bits se mantienen en la tabla de páginas. Un bit puede definir que una página sea de lectura/escritura o de sólo lectura. Cada referencia a memoria pasa a través de la tabla de páginas para encontrar el número de marco correcto. Al tiempo que se calcula la dirección física, pueden verificarse los bits de protección para asegurar que no se escribe sobre una página de sólo lectura. Una tentativa de escribir sobre una página de sólo lectura ocasiona una excepción hardware al sistema operativo (por violación de acceso a una zona de la memoria principal).
Esta concepción de la protección puede ser extendida fácilmente para obtener una protección más detallada. Podemos disponer de hardware que ofrezca protección de sólo lectura, lectura-escritura o sólo ejecución. O bien, por medio de bits de protección independientes para cada tipo de acceso, puede permitirse cualquier combinación de estos accesos, al tiempo que las tentativas ilegales generan una excepción al sistema operativo.
11.5.2.4 Dos visiones de la memoria
Un aspecto muy importante de la paginación es la clara separación entre la visión de la memoria que tiene el usuario y la memoria física real. El programa de usuario cree que la memoria es un espacio contiguo, conteniendo solamente ese único programa. En realidad, el programa de usuario está disperso por la memoria física, que también contiene otros programas. La diferencia que existe entre la visión que el usuario tiene de la memoria y la memoria física real se salva por medio del hardware de traducción de direcciones o de transformación (mapping). El hardware de transformación traduce las direcciones lógicas en direcciones físicas. Esta operación permanece oculta al usuario, y la controla el sistema operativo.
Un resultado de la distinción entre direcciones físicas y lógicas es que de hecho pueden no ser iguales. Por ejemplo, en el XDS-940, una dirección lógica es de 14 bits y una dirección física es de 16 bits. Un número de página de 3 bits se usa como índice en la tabla de páginas para seleccionar un número de marco de 5 bits. Así, puede haber hasta 4 veces más memoria física que la que un usuario puede direccionar.
Esta técnica fue adoptada en particular por los fabricantes de miniordenadores. Muchos miniordenadores fueron diseñados en los años 60, cuando la memoria era cara y los programas tenían que ser pequeños. De esta manera las direcciones estaban limitadas a 15 o 16 bits. Con la disponibilidad de la memoria de semiconductores, más barata, se hizo factible aumentar la memoria física de estos miniordenadores. Pero incrementar el tamaño de la dirección para obtener direcciones de 17 o 18 bits, precisas para la memoria física aumentada, significaba, o bien rediseñar el conjunto de instrucciones, o bien extender el tamaño de palabra para acomodar los bits extra. Cualquier solución implicaría un cambio importante, invalidando todos los programas y documentación existentes. La solución que adoptaron la mayoría de los fabricantes fue el mapping de memoria. Las direcciones lógicas (15 o 16 bits), se transforman en direcciones físicas (17 o 18 bits). Multiprogramando el sistema, puede utilizarse toda la memoria. Sin embargo, los usuarios individuales no pueden emplear más memoria que antes, puesto que el espacio para la dirección lógica no ha sido incrementado. No obstante, hay que tener claro que en los sistemas actuales el rango de direcciones virtuales suele ser muy superior al rango de direcciones reales.
El sistema operativo controla esta transformación, y puede activarla para el usuario y desactivarla para el sistema operativo. Puesto que el sistema operativo gestiona memoria física, tiene que estar al tanto de la memoria física: qué marcos están asignados, qué marcos están disponibles, cuántos marcos hay en total, etc. Esta información se mantiene generalmente en una estructura denominada tabla de marcos. La tabla de marcos tiene una entrada para cada marco, que indica si está libre o asignado y, si está asignado, a qué página de qué proceso.
Además, el sistema operativo tiene que conocer qué procesos de usuario operan en el espacio de usuario, y tiene que transformar todas las direcciones lógicas para generar direcciones físicas. Si un usuario realiza una llamada al sistema (para realizar E/S) y da una dirección como parámetro (por ejemplo, un buffer), esa dirección tiene que ser traducida para generar la dirección física correcta. El sistema operativo puede utilizar la dirección de la tabla de páginas del proceso (que se guarda en su descriptor o PCB) para traducir las direcciones lógicas en físicas siempre que tenga que realizar por él mismo la operación.
11.5.3 Segmentación
Un aspecto importante de la gestión de la memoria que la paginación convierte en inevitable es la separación de la visión que el usuario tiene de la memoria y la memoria física real. La visión del usuario no coincide con la memoria física real. La visión del usuario se transforma en la memoria física. La traducción de direcciones permite esta diferencia entre la memoria lógica y la física.
11.5.3.1 Visión del usuario de la memoria
¿Cuál es la visión de la memoria que tiene el usuario ? Concibe el usuario la memoria como una tabla lineal de palabras, algunas de las cuales contienen instrucciones mientras que otras contienen datos, o bien se prefiere alguna otra visión de la memoria ? Hay un acuerdo general en que el usuario o programador de un sistema no piensa en la memoria como una tabla lineal de palabras. Más bien prefieren concebirla como una colección de segmentos de longitud variable, no necesariamente ordenados (fig. 6.14).
Consideremos cómo ve usted un programa cuando lo está escribiendo. Piensa en él como un programa principal, con un conjunto de subrutinas, procedimientos, funciones o módulos. También puede haber diversas estructuras de datos: tablas, matrices, pilas, variables, etc. Cada uno de estos módulos o elementos de datos se referencian por un nombre. Usted habla de la "tabla de símbolos", A "la función Sqrt", "el programa principal", sin tener en cuenta qué direcciones de memoria ocupan estos elementos. Usted no se preocupa de si la tabla de símbolos se almacena antes o después de la función Sqrt. Cada uno de estos elementos es de longitud variable; la longitud está definida intrínsecamente por el propósito del segmento en el programa. Los elementos dentro de un segmento están identificados por su desplazamiento desde el principio del segmento: la primera instrucción del programa, la decimoséptima entrada de la tabla de símbolos la quinta función Sqrt, etc.
La segmentación es un esquema de administración de la memoria que soporta la visión que el usuario tiene de la misma. Un espacio de direcciones lógicas es una colección de segmentos. Cada segmento tiene un nombre y una longitud. Las direcciones especifican tanto el nombre del segmento como el desplazamiento dentro del segmento. Por lo tanto, el usuario especifica cada dirección mediante dos cantidades: un nombre de segmento y un desplazamiento. (Compárese este esquema con la paginación, donde el usuario especificaba solamente una única dirección, que el hardware particionaba en número de página y desplazamiento, siendo todo ello invisible al programador).
Por simplicidad de implementación, los segmentos están numerados y se referencian por un número de segmento en lugar de por un nombre. Normalmente el programa de usuario se ensambla (o compila), y el ensamblador (o el compilador) construye automáticamente segmentos que reflejan el programa de entrada. Un compilador de Pascal podría crear segmentos separados para (1) las variables globales, (2) la pila de llamada de procedimientos, para almacenar parámetros y devolver direcciones, (3) el código de cada procedimiento o función, y (4) las variables locales de cada procedimiento y función. El cargador tomaría todos esos segmentos y les asignaría números de segmento.
11.5.3.2 Hardware
Aunque el usuario ahora puede referenciar los objetos del programa por medio de una dirección de dos dimensiones, la memoria física real es todavía, por supuesto, una secuencia unidimensional de palabras. La transformación se efectúa por medio de una tabla de segmentos.
El empleo de una tabla de segmentos se muestra en la figura 6.15. Una dirección lógica consta de dos partes: un número de segmento s y un desplazamiento dentro de ese segmento, d. El número de segmento se utiliza como un índice en la tabla de segmentos. Cada entrada de la tabla de segmentos tiene una base de segmento y un límite. El desplazamiento d de la dirección lógica tiene que estar comprendido entre 0 y el límite de segmento. En caso contrario se produce una excepción al sistema operativo (tentativa de direccionamiento lógico más allá del fin de segmento). Si este desplazamiento es legal, se añade a la base para producir la dirección de la tabla deseada en la memoria física. La tabla de segmentos es así esencialmente una matriz de pares registros base/límite.
11.5.3.3 Implementación de tablas de segmentos
Al igual que la tabla de páginas, la tabla de segmentos puede situarse bien en registros rápidos o bien en memoria. Una tabla de segmentos mantenida en registros puede ser referenciada muy rápidamente: la adición a la base y la comparación con el límite pueden realizarse simultáneamente para ahorrar tiempo. El PDP-11/45 utiliza este método; tiene 8 registros de segmento. Una dirección de 16 bits se forma a partir de un número de segmento de 3 bits y de un desplazamiento de 13 bits. Esta disposición permite hasta 8 segmentos; cada segmento puede ser de hasta 8 K-bytes. Cada entrada en la tabla de segmentos tiene una dirección base, una longitud y un conjunto de bits de control de acceso que especifican acceso denegado, acceso de sólo lectura, o acceso de lectura/escritura al segmento.
El Burroughs B5500 permitía 32 segmentos de hasta 1024 palabras cada uno. Estas especificaciones definían un número de segmento de 5 bits y un desplazamiento de 10 bits. Sin embargo, la experiencia con este sistema mostró que los segmentos eran pocos y que el límite del tamaño del segmento era demasiado pequeño (las tablas mayores de 1K tenían que fragmentarse entre varios segmentos). Por ello, el GE 645 utilizado por Multics permite hasta 256 K-segmentos de hasta 64 K-palabras.
Con tantos segmentos no es factible mantener la tabla de segmentos en registros, de modo que tiene que mantenerse en memoria. Un registro de base de tabla de segmentos (STBR) apunta a la tabla de segmentos. Puesto que el número de segmentos utilizado por un programa puede variar ampliamente, también se utiliza un registro de longitud de tabla de segmentos (STLR). En el caso de una dirección lógica (s, d) verificamos primero que el número de segmento s es legal (s < STLR), Entonces, añadimos el número de segmento al STBR resultando la dirección en memoria de la entrada de la tabla de segmentos (STBR + s). Esta entrada se lee en la memoria y actuamos igual que antes: se verifica el desplazamiento frente a la longitud de segmento, y se calcula la dirección física de la palabra deseada como la suma de la base del segmento y el desplazamiento.
Igual que con la paginación, esta transformación requiere dos referencias a memoria por dirección lógica, el ordenador disminuirá su velocidad en un factor de 2, a menos que se haga algo para evitarlo. La solución normal consiste en utilizar un conjunto de registros asociativos para mantener las entradas utilizadas más recientemente en la tabla de segmentos. Un conjunto de registros asociativos relativamente pequeño (8 \ 16) puede reducir generalmente el retardo a los accesos a memoria hasta no más allá de un 10% o 15% más lentos que los accesos a memoria "mapeada".
11.5.3.4 Compartición y protección
Una ventaja importante de la segmentación es la asociación de la protección con los segmentos. Puesto que los segmentos representan una porción del programa definida semánticamente, es probable que todas las entradas en el segmento se utilicen de la misma manera. De ahí que tengamos algunos segmentos que son instrucciones, mientras que otros son datos. En una arquitectura moderna las instrucciones son no automodificables, de modo que los segmentos de instrucciones pueden definirse como de sólo lectura o sólo ejecución. El hardware verificará los bits de protección asociados a cada entrada en la tabla de segmentos para impedir accesos ilegales a memoria, tales como tentativas de escribir en un segmento de sólo lectura o de utilizar un segmento de sólo ejecución como datos. Situando una tabla en un segmento propio, el hardware verificará automáticamente que toda indexación en la tabla es legal, y no sobrepasa los límites de la misma. Así, muchos errores frecuentes en programas serán detectados por hardware antes de que puedan ocasionar un daño serio.
Otra ventaja de la segmentación está relacionada con la compartición de código y datos. Los segmentos se comparten cuando las entradas en las tablas de segmentos de dos procesos diferentes apuntan a las mismas posiciones físicas.
La compartición se produce a nivel de segmento. Por lo tanto, cualquier información puede compartirse definiéndole un segmento. Pueden compartirse varios segmentos, de modo que es posible compartir un programa compuesto de más de un segmento.
Por ejemplo, consideremos el uso de un editor de textos en un sistema de tiempo compartido. Un editor completo podría resultar bastante largo, y formado por muchos segmentos. Estos segmentos pueden compartirse entre todos los usuarios, limitando la memoria física necesaria para soportar las tareas de edición. En lugar de necesitar n copias del editor, precisamos solamente una. Aún necesitamos segmentos únicos e independientes para almacenar las variables locales de cada usuario. Estos segmentos, por supuesto, no deben ser compartidos.
También es posible compartir solo partes de programas. Por ejemplo, subrutinas de uso frecuente pueden compartirse entre muchos usuarios definiéndolas como segmentos de sólo lectura compartibles. Por ejemplo, dos programas Fortran pueden utilizar la misma subrutina Sqrt, pero sólo será precisa una copia física de la rutina Sqrt.
Aunque esta compartición parece ser bastante sencilla, tiene algunas sutilezas. Típicamente, los segmentos de código tienen referencias a sí mismos. Por ejemplo, un salto condicional tiene normalmente una dirección de transferencia. La dirección de transferencia es un nombre de segmento y un desplazamiento. El número de segmento de la dirección de transferencia será el del segmento de código. Si tratamos de compartir este segmento, todos los procesos que lo compartan tienen que definir el segmento de código compartido con el mismo número de segmento.
Por ejemplo, si queremos compartir la rutina Sqrt y un proceso quiere definirla como segmento 4 y otro lo hace como segmento 17, ¿cómo podría la subrutina Sqrt referenciarse a sí misma? Puesto que solamente hay una copia física de Sqrt, tiene que referenciarse a sí misma de la misma manera para ambos usuarios: tiene que tener un número de segmento único. A medida que crece el número de usuarios que comparten el segmento, también crece la dificultad de encontrar un número de segmento aceptable.
Los segmentos de datos de sólo lectura (sin punteros) pueden compartirse aún usando números de segmento diferentes; lo mismo puede hacerse con segmentos de código que no se referencian directamente a sí mismos, sino sólo indirectamente. Por ejemplo, la bifurcación condicional que especifica la dirección de desplazamiento a partir del valor actual del contador de programa o respecto a un registro que contiene el número de segmento actual, permite que el código no tenga que realizar una referencia al número de segmento actual.
El ordenador GE 645 utilizado con Multics tenía 4 registros que contenían los números de segmento del segmento actual, del segmento de pila, del segmento de enlace y de un segmento de datos. Los programas pocas veces hacen referencia directamente a un número de segmento, sino siempre indirectamente a través de estos cuatro registros de segmento. Esto permite que el código pueda compartirse libremente.
11.5.3.5 Fragmentación
El sistema operativo tiene que encontrar y asignar memoria para todos los segmentos de un programa de usuario. Esta situación es similar a la paginación, excepto en el hecho de que los segmentos son de longitud variable; las páginas son todas del mismo tamaño. Por tanto, como en el caso de las particiones dinámicas, la asignación de memoria es un problema de asignación dinámica de almacenamiento, resuelto probablemente mediante un algoritmo del mejor o primer ajuste.
La segmentación puede ocasionar entonces fragmentación externa, cuando todos los bloques libres de memoria son demasiado pequeños para acomodar a un segmento. En este caso, el proceso puede simplemente verse obligado a esperar hasta que haya disponible más memoria (o al menos huecos más grandes), o puede utilizarse la compactación para crear huecos mayores. Puesto que la segmentación es por naturaleza un algoritmo de reubicación dinámica, podemos compactar la memoria siempre que queramos.
¿ En qué medida es mala la fragmentación externa en un esquema de segmentación ? La respuesta a estas preguntas depende principalmente deltamaño medio de segmento. En un extremo, se podría definir cada proceso como un segmento; este esquema es el de las particiones dinámicas. En el otro extremo, cada palabra podría situarse en su propio segmento y reubicarse por separado. Esta disposición elimina la fragmentación externa. Si el tamaño medio de segmento es pequeño, la fragmentación externa también será pequeña. (Por analogía, consideremos la colocación de las maletas en el maletero de un coche; parece que nunca encajan bien. Sin embargo, si se abren las maletas y se colocan en el maletero los objetos sueltos, todo encaja). Puesto que los segmentos individuales son más pequeños que el proceso en conjunto, es más probable que encajen en los bloques de memoria disponibles.
11.5.4 Segmentación paginada
Tanto la paginación como la segmentación tienen sus ventajas y desventajas. También es posible combinar estos dos esquemas para mejorar ambos. Veamos como ejemplo el esquema del ordenador GE 645 con el sistema operativo Multics. Las direcciones lógicas estaban formadas a partir de un número de segmento de 18 bits y un desplazamiento de 16 bits. Aunque este esquema crea un espacio de direcciones correspondiente a una dirección de 34 bits, la tabla de segmentos tiene un tamaño tolerable, puesto que el número variable de segmentos conduce naturalmente al uso de un Registro de Longitud de Tabla de Segmentos. Necesitamos tan solo el mismo número de entradas en la tabla de segmentos que segmentos; no tenemos por qué tener entradas vacías en la tabla de segmentos.
No obstante, con segmentos de 64 K-palabras, el tamaño medio de segmento podría resultar bastante grande y la fragmentación externa constituir un problema. Incluso si la fragmentación externa no es significativa, el tiempo de búsqueda para asignar un segmento, utilizando un primer o mejor ajuste, podría ser grande. De esta manera se podría desperdiciar memoria a causa de la fragmentación externa o bien desperdiciar tiempo debido a la búsqueda larga, o bien ambas cosas.
La solución adoptada fue paginar los segmentos. La paginación elimina la fragmentación interna y convierte en trivial el problema de la asignación: cualquier marco vacío puede utilizarse para una página. Obsérvese que la diferencia entre esta solución y la segmentación pura es que la entrada en la tabla de segmentos no contiene la dirección de la base del segmento, sino la dirección de la base de una tabla de páginas para ese segmento. El desplazamiento del segmento se fragmenta entonces en un número de página de 6 bits y un desplazamiento de página de 10 bits. El número de página indexa en la tabla de páginas para dar el número de marco. Finalmente, el número de marco se combina con el desplazamiento de página para formar la dirección física.
Fig.: Acceso a un sistema de memoria Segmentado Paginado.
Ahora debemos tener una tabla de páginas independiente para cada segmento. No obstante, puesto que cada segmento tiene una longitud limitada por su entrada en la tabla de segmentos, la tabla de páginas no tiene por qué tener su tamaño máximo. Sólo precisa tantas entradas como se necesiten realmente. Además, generalmente la última página de cada segmento no estará totalmente llena. De este modo tendremos, por término medio, media página de fragmentación interna por segmento. Consecuentemente, aunque hemos eliminado la fragmentación externa, hemos introducido fragmentación interna e incrementado la sobrecarga de espacio de la tabla.
A decir verdad, incluso la visión de paginación segmentada de Multics que acabamos de presentar es simplista. Puesto que el número de segmento es una cantidad de 18 bits, podríamos tener 262144 segmentos, con lo que precisaríamos una tabla de segmentos muy larga. Para simplificar este problema, Multics pagina la tabla de segmentos. De esta manera, en general, una dirección en Multics utiliza un número de segmento para definir un índice de página en una tabla de páginas para la tabla de segmentos. A partir de esta entrada, localiza la parte de la tabla de segmentos que tiene la entrada para ese segmento. La entrada en la tabla de segmentos apunta a una tabla de páginas para ese segmento, que especifica el marco que contiene la palabra deseada.
Suscribirse a:
Entradas (Atom)