Tema Sistema Operativos (SSOO) 1.1 Introducción Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • • Definición de sistema operativo Funciones del SO Entorno virtual Un poco de historia 2 Definición de SO/OS • Un ordenador moderno consta de uno o más procesadores, una memoria principal, discos, impresoras, un teclado, un ratón, una pantalla o monitor, interfaces de red y otros dispositivos de entrada/salida. • Los ordenadores están equipados con una capa de software llamada sistema operativo, cuyo propósito es proporcionar a los programas de usuario acceso a todos los recursos y administrar cada uno de ellos. 3 Definición de SO/OS Shell: programa basado en texto con el que los usuarios generalmente interactúan GUI (Graphical User Interface; Interfaz gráfica de usuario): cuando está basado elementos gráficos o iconos. 4 Definición de SO/OS • • • • • • • La mayoría de las computadoras tienen dos modos de operación: modo kernel y modo usuario. El SO se ejecuta en modo kernel (modo supervisor). En el modo kernel, el SO tiene acceso a todo el hardware. Las otras aplicaciones se ejecutan en modo usuario. Shell o GUI, es el nivel más bajo del software en modo usuario. No confundir con los sistemas integrados (como los sistemas operativos basados en Java que para separar los componentes utilizan interpretación y no el hardware). El trabajo del SO es proporcionar una asignación ordenada y controlada de los procesadores, memorias y dispositivos de E/S, entre los diversos programas que compiten por estos recursos. 5 Definición de SO/OS Tres funciones básicas: • Interfaz con el hardware: gestión de los recursos del ordenador • Interfaz con las aplicaciones: gestión de los programas en ejecución (aplicaciones) • Interfaz con el usuario: ejecución de las órdenes de los usuarios – – – – – – Gestión de procesos Gestión de memoria Gestión del sistema de ficheros Seguridad Gestión de los dispositivos de entrada y salida Networking (TCP/IP, UDP) 6 Entorno virtual Virtualización del SO • VirtualBox - Vagrant, VMWare, Parallels, Docker 7 Entorno virtual 8 SO para la asignatura Descargar SO 9 Un poco de historia • Los primeros ordenadores se llamaban mainframes (IBM 704 de 1964). • Los usuarios cargaban por turnos sus programas y datos mediante tarjetas perforadas • El programa se cargaba, se ejecutaba y terminaba cuando el programa había concluido… • O había fallado antes de terminar. • Sistemas operativos por lotes (batch). 10 Un poco de historia 11 Un poco de historia • Uno de los primeros sistemas operativos modernos con mayor aceptación fue UNIX • • • • Creado en los 70 por Dennis Ritchie y Ken Thompson • • • Además, un sistema de ficheros unificado y jerárquico Fue escrito en C (lenguaje creado por Ritchie entre los años 1969-73) Se caracterizó por su diseño modular. El SO provee un conjunto de herramientas más o menos sencillas y cada una es capaz de llevar a cabo ciertas tareas. Dispone de una Shell o intérprete de comandos. ¿Quién coordina a todas esas herramientas? – • El núcleo o kernel Además, era portable, multiusuario y multitarea 12 Un poco de historia • En los 80 se empezó a pensar que un SO podría usarse en ordenadores de cualquier tamaño. • Nace así MS-DOS: Seattle Computer Products tenía un sistema operativo conocido como DOS (Disk Operating System; Sistema Operativo en Disco). • • BGates compró DOS y lo ofreció a IBM como DOS/BASIC. • Doug Engelbart en el Stanford Research Institute inventó la Interfaz Gráfica de Usuario GUI. • • • • Xerox PARC copió la idea y la utilizó en sus sistemas. IBM pidió modificaciones y BGates proporcionó MS-DOS (Microsoft Disk Operating System; Sistema Operativo en Disco de Micro-Soft) El primer intento de Job surgió de lo visto en PARC Su segundo intento generó Apple Macintosh. La evolución de MS-DOS estuvo influenciada por el éxito Apple, de ahí lo de Windows 13 Un poco de historia • • Entre 1985 y 1995, Windows fue sólo un entorno gráfico encima de MS-DOS. • En 1998, se liberó una versión ligeramente modificada de este sistema, conocida como Windows 98. • Sin embargo, tanto Windows 95 como Windows 98 aún contenían una gran cantidad de lenguaje ensamblador para los procesadores Intel de 16 bits. En 1995 se liberó una versión independiente de Windows, conocida como Windows 95. 14 Un poco de historia • Otro de los sistemas operativos de Microsoft es Windows NT (NT significa Nueva Tecnología), que es compatible con Windows 95 en cierto nivel, pero fue completamente rediseñado en su interior. Es un sistema completo de 32 bits. • En los 80 aparecen los ordenadores-consolas con sus propios sistemas operativos. Mac OS Amiga Commodore 15 Un poco de historia • • • El OS/2 de IBM (aunque también funcionaban con MSDOS y Windows). La clave: El desarrollo de la GUI (Graphical User Interface) La del Mac OS 7 fue la primera que soportaba los colores 16 Un poco de historia 17 Recordemos MS-DOS Escribir "CMD" en aplicaciones de Windows 18 Kernel • • • • • • La capa más cercana al hardware se denomina kernel (o núcleo). Es la parte fundamental del SO. Gestiona los recursos hardware del sistema Provee acceso seguro al hardware para los diferentes programas que se ejecutan. Y es responsable de decidir cuándo y por cuánto tiempo un programa puede acceder a cierto hardware. Se encarga de: – Gestión de procesos – Memoria principal – Memoria de disco – E/S, Sistema de ficheros – Seguridad – Red 19 Arquitecturas del SO Tipos de arquitecturas del SO según la definición del kernel: • Arquitectura kernel monolítico • Arquitectura microkernel • Arquitecturas híbridas 20 Arquitecturas del SO: kernel monolítico • • • • • • Gran parte de la funcionalidad reside en el kernel Incluyendo planificación, sistema de ficheros, redes, drivers de dispositivos, gestión de memoria,… Suele estar implementado como un único proceso que se ejecuta en modo kernel. El diseño es modular, como en UNIX Cuando el sistema arranca se cargan todos los servicios del SO y se quedan en memoria. Proceso init. 21 Arquitecturas del SO: kernel monolítico 22 Arquitecturas del SO: kernel monolítico Desventajas • • • • • • Podemos tener kernels demasiado grandes. Los errores en el kernel pueden paralizar el sistema. Si un driver falla puede hacer caer todo el sistema. Poco flexible. Pero es muy rápido. Cada procedimiento en el sistema tiene la libertad de llamar a cualquier otro, si éste proporciona cierto cómputo útil que el primero necesita. – Al tener miles de procedimientos que se pueden llamar entre sí sin restricción, con frecuencia se produce un sistema poco manejable y difícil de comprender. 23 Arquitecturas del SO: Microkernel • • • • • Los procesos de usuario se pueden configurar para que tengan menos poder, por lo que un error en ellos tal vez no sería fatal. Asigna solamente unas pocas funciones al kernel (modo privilegiado o modo kernel). Planificación básica, comunicación entre procesos (IPC),… El resto sigue una arquitectura cliente – servidor. Estos se ejecutan en modo usuario o no privilegiado. 24 Arquitecturas del SO: Microkernel • • Los servicios del SO los proporcionan determinados procesos, algunas veces llamados servidores. Los servicios del SO se ejecutan en modo usuario, y el microkernel los trata como a cualquier otra aplicación: e.g. Servidor X (GUI), drivers… 25 Cultura general • • • • • La densidad de los errores depende del tamaño del módulo, su tiempo de vida… Aproximada en los sistemas industriales formales existen 10 errores por cada 1.000 líneas de código. Es probable que un SO monolítico de cinco millones de líneas de código contenga cerca de 50,000 errores en el kernel. No todos son graves, algunos errores pueden ser: emitir un mensaje de error incorrecto en una situación poco común. Los SO tienen tantos errores que los fabricantes de ordenadores colocan botones de reinicio “reset” en ellas (a menudo en el panel frontal). – No pasa lo mismo en equipos como televisiones, estéreos, coches, etc. pese a la gran cantidad de software que hay en estos dispositivos. 26 Arquitecturas del SO: Microkernel • • • • • Sólo el microkernel se ejecuta en modo kernel. El resto se ejecuta como procesos de usuario ordinarios, sin poder relativamente. Al ejecutar cada driver de dispositivo y sistema de archivos como un proceso de usuario separado, un error en alguno de estos procesos puede hacer que falle ese componente, pero no puede hacer que falle todo el sistema. Un error en el driver del dispositivo del audio hará que el sonido sea confuso o se detenga, pero el ordenador seguirá funcionando. En un sistema monolítico con todos los drivers en el kernel, un driver de audio con errores puede hacer uso de una dirección de memoria inválida y paralizar todo el sistema. – Algunos de los microkernel mejor conocidos son Integrity, K42, L4, PikeOS, QNX, Symbian y MINIX 3. 27 Cultura general: Minix 3 • • • • MINIX 3 es un sistema de código fuente abierto en conformidad con POSIX. – Sergio: ¿Qué es POSIX? El microkernel MINIX 3 sólo tiene cerca de 3200 líneas de C y 800 líneas de ensamblador para las funciones de muy bajo nivel (se usan para atrapar interrupciones y conmutar proceso). El código de C administra y planifica los procesos, se encarga de la comunicación entre procesos (al pasar mensajes entre procesos) y ofrece un conjunto de aproximadamente 35 llamadas al kernel para permitir que el resto del SO realice su trabajo. Estas llamadas realizan funciones como: asociar los drivers a las interrupciones, desplazar datos entre espacios de direcciones e instalar nuevos mapas de memoria para los procesos recién creados. 28 Arquitecturas del SO: Microkernel Ventajas • Buen diseño • Protección entre los distintos componentes del sistema • Kernel pequeño y flexible • Pero más lento 29 Arquitecturas del SO: Microkernel Desventajas • Se producen muchísimas llamadas al sistema (más carga en el sistema), más pesado. • Es difícil la gestión entre procesos – IPC – Inter-Process Communication • • Y muchos cambios entre los dos modos de ejecución (modo kernel – modo usuario), que penalizan el rendimiento Ejemplo: Amiga OS 30 Arquitecturas del SO: híbrida • • • • • Los kernels híbridos son los usados en la mayoría de los sistemas operativos comerciales. Windows (desde Windows NT), Mac OS X. Es similar al microkernel y al diseño clienteservidor, pero con algunas mejoras. Se incluye parte del código en modo kernel para que mejore el rendimiento. Estas optimizaciones se llevaron a cabo a mediados de los noventa. 31 Arquitecturas del SO: híbrida • • Se mejoró mucho el rendimiento Y por ello esta arquitectura fue la adoptada por la mayoría de los sistemas operativos. 32 Arquitecturas del SO: otros • Según el número de procesos simultáneos que pueden ejecutar: – Monotarea (MS-DOS) – Multitarea (el SO debe repartir el tiempo del procesador entre los diferentes procesos) • Según el número de usuarios simultáneos: – Monousuario( Windows) – Multiusuario (Linux) 33 Arquitecturas del SO: otros • Según el número de procesadores que puede atender: – Monoprocesador – Multiprocesador • Según el tipo de arquitectura del procesador que puede gestionar: – 16 bits – 32 bits – 64 bits 34 Arquitecturas del SO: otros • Según el uso: – Cliente – Servidor – Empotrado o – de tiempo real • Según la movilidad: – Fijos – Móviles. 35 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 36 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema Sistema Operativos (SSOO) 1.2 Elementos del SO Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • • • Elementos básicos Registros del procesador Ejecución de instrucciones Interrupciones Jerarquía de la memoria 2 Elementos básicos 3 Elementos básicos 4 Elementos básicos Procesador: es el “cerebro” del ordenador (CPU), encargado de obtener las instrucciones de la memoria y ejecutarlas. El ciclo básico de toda CPU es: • Obtener la primera instrucción de memoria • Decodificarla para determinar su tipo y operandos • Ejecutarla y • Después obtener, decodificar y ejecutar las instrucciones subsiguientes. El ciclo se repite hasta que el programa termina. 5 Elementos básicos • El acceso a la memoria para obtener una instrucción o palabra de datos requiere mucho más tiempo que ejecutar una instrucción. • Todas las CPU contienen ciertos registros en su interior para contener las variables clave y los resultados temporales. • El conjunto de instrucciones generalmente contiene instrucciones para cargar una palabra de memoria en un registro y almacenar una palabra de un registro en la memoria. • Otras instrucciones combinan dos operandos de los registros, la memoria o ambos en un solo resultado, como la operación de sumar dos palabras y almacenar el resultado en un registro o la memoria. 6 Registros del procesador Además de los registros generales utilizados para contener variables y resultados temporales, la mayoría de los ordenadores tienen varios registros especiales que están visibles para el programador: • El contador de programa (PC o program counter), el cual contiene la dirección de memoria de la siguiente instrucción a obtener. Una vez que se obtiene esa instrucción, el contador de programa se actualiza para apuntar a la siguiente. • El apuntador de pila (stack pointer), el cual apunta a la parte superior de la pila (stack) actual en la memoria. La pila contiene un conjunto de valores por cada procedimiento al que se ha entrado pero del que todavía no se ha salido. El conjunto de valores en la pila por procedimiento contiene los parámetros de entrada, las variables locales y las variables temporales que no se mantienen en los registros. 7 Registros del procesador PSW (Program Status Word; Palabra de estado del programa). Este registro contiene los bits de código de condición, que se asignan cada vez que se ejecutan las instrucciones de comparación, la prioridad de la CPU, el modo (usuario o kernel) y varios otros bits de control. Los programas de usuario pueden leer normalmente todo el PSW pero por lo general sólo pueden escribir en algunos de sus campos. El PSW juega un papel importante en las llamadas al sistema y en las operaciones de E/S. • El SO está al tanto de todos los registros. Cuando la CPU se multiplexa en el tiempo, el SO detiene con frecuencia el programa en ejecución para (re)iniciar otro. • Cada vez que detiene un programa en ejecución, el SO debe guardar todos los registros para poder restaurarlos cuando el programa continúe su ejecución. 8 Registros del procesador PC Program Counter: Contiene la dirección de la próxima instrucción que será leída de la memoria. IR Instruction Register: contiene la última instrucción leída. 9 Ejecución de instrucciones 10 Ejecución de instrucciones 11 Ejecución de instrucciones 12 Ejecución de instrucciones 13 Interrupciones 14 Interrupciones 15 Jerarquía de memoria Capacidad – Velocidad - Coste • Cuanto mayor tiempo de acceso, mayor coste • Cuanto mayor capacidad, menor coste • Cuanto mayor capacidad, menor velocidad de acceso 16 Jerarquía de memoria 17 Jerarquía de memoria 18 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 19 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema Sistema Operativos (SSOO) 1.3 Introducción a Linux Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • • • Introducción a Linux GNU/Linux y sus distribuciones Arranque del ordenador Arranque secundario Arranque del SO 2 Introducción a Linux Algunas cuestiones importantes: • ¿Quién usa Linux? • ¿Qué es Linux? • ¿Qué es Ubuntu, Debian, Red Hat, Suse...? ¿Cuántos Linux hay? • ¿Puedo usarlo en casa para escuchar música, ver películas, chatear, etc.? ¿Echaré algo en falta? • ¿Por qué tendría que cambiarme a Linux? • ¿Cómo se aprende Linux? 3 GNU/Linux • • • • • El sistema operativo GNU es un sistema completo de software libre compatible con Unix. El término GNU proviene de «GNU No es Unix». Richard Stallman escribió el anuncio inicial del Proyecto GNU en setiembre de 1983. Al principio de los años ochenta, casi todo el software era privativo, lo que significa que tenía dueños que prohibían e impedían la cooperación entre usuarios. De ahí que fuera necesario el Proyecto GNU. Si no existe un sistema operativo libre, ni siquiera se puede comenzar a usar un ordenador sin recurrir al software privativo. Así, el primer elemento en la agenda del software libre tenía que ser un sistema operativo libre. El sistema operativo era compatible con Unix porque el diseño en general ya estaba probado y era portable, y porque la compatibilidad facilitaba a los usuarios de Unix el cambio de Unix a GNU. Fuente original: https://www.gnu.org/distros/free-distros.html 4 GNU/Linux • • • • Un sistema operativo similar a Unix incluye un núcleo, compiladores, editores, procesadores de texto, software de correo, interfaces gráficas, bibliotecas, juegos y muchas otras cosas. En 1990 ya se contaba con los componentes principales excepto uno, el núcleo. En 1991, Linus Torvalds creó Linux basándose en Minix, una pequeña implementación de UNIX para PC, el cual fue escrito totalmente en C por A. Tannenbaum. Linus anunció su primera versión oficial 0.02, el 5 de Octubre de 1991. En 1992 se convirtió en software libre. Fuente original: https://www.gnu.org/distros/free-distros.html 5 Linux • Consta básicamente del Kernel, el shell y el compilador gcc. • Cuando se habla de Linux, realmente se hace referencia al Kernel o núcleo del sistema. El resto de aplicaciones que corren sobre ese kernel (formando usualmente una distribución) debería llamarse GNU / Linux. La idea de usar un pingüino fue de Alan Cox, uno de los desarrolladores del kernel de Linux. Larry Ewing se encargó de dibujarlo usando GIMP, en el año 1996. Su nombre es Tux (Torvalds Linux) Fuente original: https://www.gnu.org/distros/free-distros.html 6 Distribuciones 100% GNU/Linux • • La palabra «libre» en «software libre» se refiere a libertad, no al precio. Se puede o no pagar un precio por obtener software de GNU. Una vez que se obtiene el software, se tienen cuatro libertades específicas para usarlo: – La libertad de ejecutar el programa como se desee; – La libertad de copiar el programa y dárselo a amigos o compañeros de trabajo; – La libertad de cambiar el programa como se desee mediante el acceso completo al código fuente – La libertad de distribuir una versión mejorada, ayudando así a construir la comunidad (si se redistribuye software de GNU, se puede cobrar una tarifa por el acto físico de efectuar la copia, o bien regalar copias) Fuente original: https://www.gnu.org/distros/free-distros.html 7 Distribuciones 100% GNU/Linux Fuente original: https://www.gnu.org/distros/free-distros.html 8 Distribuciones 100% GNU/Linux – Ligeras • Distribuciones para dispositivos con recursos limitados, como por ejemplo un router inalámbrico. • Estas distribuciones no son autónomas sino que deben poder ser desarrolladas y compiladas sobre una de las distribuciones libres completas de la lista anterior, posiblemente con el auxilio de herramientas de desarrollo libres distribuidas junto a la misma. Fuente original: https://www.gnu.org/distros/free-distros.html 9 Distribuciones GNU/Linux – Sin avalar Excepto donde se indica, ninguna de las distribuciones que se incluyen en la siguiente lista respeta las pautas en al menos dos aspectos importantes: • No adoptan ninguna política para incluir únicamente software libre, ni para eliminar el software que no sea libre cuando se detecta. La mayoría de estas distribuciones no tienen en absoluto una política clara sobre qué software aceptan o rechazan. Hay distribuciones que sí tienen una política, pero lamentablemente no son lo suficientemente estrictas, como se explica a continuación. • El núcleo que distribuyen (en la mayoría de los casos, Linux) incluye blobs: piezas de código compilado distribuidas sin el código fuente, generalmente firmware para hacer funcionar algún dispositivo. 10 Distribuciones GNU/Linux – Sin avalar Arch GNU/Linux Canaima CentOS Debian GNU/Linux Fedora Gentoo GNU/Linux Mandriva GNU/Linux Manjaro GNU/Linux Mint GNU/Linux openSUSE Red Hat GNU/Linux Slackware SteamOS SUSE GNU/Linux Enterprise Tails Ubuntu GNU/Linux Otros: Android Sistema BSD Chrome OS Haiku /e/ LineageOS ReactOS https://www.gnu.org/distros/common-distros.html 11 SO para la asignatura Descargar SO 12 Arranque del ordenador i • Cada Pentium contiene (en su tarjeta madre) un programa conocido como BIOS (Basic Input Output System, Sistema básico de entrada y salida) del sistema. – El BIOS contiene software de E/S de bajo nivel, incluyendo procedimientos para leer el teclado, escribir en la pantalla y realizar operaciones de E/S de disco, entre otras cosas. • • Hoy en día está contenido en una RAM tipo flash que es no volátil pero el SO puede actualizarla cuando se encuentran errores en el BIOS. La BIOS (firmware) realiza la inicialización básica del hardware (POST: encendido y autocomprobación (power on self test)) y pasa el control del sistema al siguiente paso. – Primero hace pruebas para ver cuánta RAM hay instalada y si el teclado junto con otros dispositivos básicos están instalados y responden en forma correcta. – Empieza explorando los buses ISA y PCI para detectar todos los dispositivos conectados a ellos. 13 Arranque del ordenador ii • • • • • • Un firmware es un software que maneja físicamente al hardware durante el arranque. Está cargado en la memoria ROM (Read-Only Memory) del ordenador, no en el disco duro. Read-only memory (ROM) es un tipo de memoria no volátil que se usa en equipos y otros dispositivos electrónicos. Permite solo la lectura de la información y no su escritura. Las ROM modernas sí se pueden reprogramar y se llaman EPROM (Erasable Programmable Read-Only Memory) Entre ellas también las flash ROM. 14 Arranque del ordenador iii • El BIOS determina el dispositivo de arranque, para lo cual prueba una lista de dispositivos almacenada en la memoria CMOS. – El usuario puede cambiar esta lista si entra a un programa de configuración del BIOS, justo después de iniciar el sistema. – • • • Por lo general, se hace un intento por arrancar: Disco flexible, Unidad de CD, USB, Red, HDD, otros. La BIOS busca el dispositivo de inicio y pasa el control al primer sector físico del dispositivo conocido como Master Boot Record o MBR. Los dos primeros sectores del disco duro (los primeros 512 bytes) contienen el MBR. El MBR es básicamente una tabla de particiones cuyas entradas son las particiones primarias y lógicas que hay en el disco duro. Este sector contiene un programa que por lo general examina la tabla de particiones al final del sector de arranque, para determinar qué partición está activa. 15 Arranque secundario • • • • Después se lee un cargador de arranque secundario de esa partición. Este cargador lee el sistema operativo de la partición activa y lo inicia. El sistema operativo consulta al BIOS para obtener la información de configuración. Para cada dispositivo, comprueba si tiene el driver correspondiente. De no ser así, pide al usuario que inserte un CD-ROM que contenga el driver (suministrado por el fabricante del dispositivo). Una vez que tiene los drivers de todos los dispositivos, el sistema operativo los carga en el kernel. Después inicializa sus tablas, crea los procesos de segundo plano que se requieran, y arranca un programa de inicio de sesión o GUI. 16 Arranque secundario Cargador de arranque secundario. • El cargador de arranque (bootloader), en nuestro caso GRUB, es el encargado de la segunda fase del proceso de arranque. • GNU GRUB (GNU GRand Unified Bootloader) es un gestor de arranque múltiple, desarrollado por el proyecto GNU que nos permite elegir qué sistema operativo arrancar de los instalados. • Grub se puede instalar en el MBR o en los primeros sectores de una partición primaria activa (es decir, arrancable), identificada como /boot • Si tengo varios sistemas operativos y quiero que Grub sea capaz de arrancar todos, debo instalarlo en el MBR. • Este /boot puede estar en la misma partición que la / o en otra partición (igual que /home por ejemplo, que lo separamos de / ) 17 Particiones para el arranque • • • Partición primaria: partición que si está activa, puede ser usada para arrancar un sistema operativo. Partición extendida: partición física que no se puede usar a menos que sea dividida en particiones lógicas. Particiones lógicas: subdivisiones de la extendida. Imagen tomada de: http://elsitioandres.blogspot.com/2011/09/particion-y-multiple-instalacion-de.html 18 Particiones para el arranque • • • • • • • Se pueden tener hasta cuatro particiones primarias o tres primarias más una extendida. La extendida se puede dividir en hasta 128 particiones lógicas. Podemos indicar que el sistema se inicia desde una partición primaria activa del disco duro primario. Solo puede haber una partición primaria marcada como activa. Partición primaria: partición que si está activa, puede ser usada para arrancar un sistema operativo. La partición / puede estar en una primaria (activa o no) o incluso en una lógica. Pero /boot debe estar en una partición que sea arrancable (primaria activa). 19 Arranque del SO i • • • • • • Si se instala primero Windows y luego Linux, éste sobrescribe el gestor de arranque de Windows(BCD o Boot Configuration Data en Windows) No hay problema porque Grub reconocerá que están instalado Windows y meterá una entrada en el menú de arranque para poder arrancarlo En caso contrario no. Si instalo primero Linux y luego Windows, el gestor de arranque sobrescribe el Grub y luego no puede inicial Linux. Se carga el sistema de archivos raíz en disco duro. El programa init es ejecutado en primer lugar con el PID=1 preparando el proceso de arranque principal para el comienzo de muchos procesos. Muchos de estos procesos son demonios. – PID Proccess ID: es el número entero usado por el kernel de un SO para identificar un proceso de forma unívoca. 20 Arranque del SO ii • • • • • Un demonio (o daemon, Disk And Execution MONitor) que generalmente se carga en memoria, y está esperando alguna señal (proveniente del núcleo o si es un servicio de red, un cliente que se conecte) para despertarse y ejecutar las funciones necesarias para tratarla. Los daemons que tengamos arrancados no ocupan la CPU mientras no es estrictamente necesario. Es un proceso que se ejecuta en background (es decir, en segundo plano). Todos los demonios tienen un shell script situado en el directorio /etc/init.d/ que permite iniciarlo, pararlo o ver su estado de ejecución. Iniciar/parar un demonio: – sudo /etc/init.d/nombre_demonio {star, stop, restart} – Sudo service nombre_demonio {star, stop, restart} 21 Arranque del SO iii • • • Desde Debian jessie (Debian 8) y las últimas versiones de Ubuntu, se cambió el arranque de init (al estilo Unix System V) por otra forma en la que quien gestiona todo, es un proceso llamado systemd. Este proceso systemd hace lo mismo que init – Álvaro: prueba el siguiente comando en la terminal de Ubuntu: ps -- pid=1 – Explica a toda la clase para qué sirve este comando. – Cómo se te ve mucha disposición, prueba este comando: arch, explica qué muestra. Systemd es un conjunto de herramientas, librerías y servicios diseñados para llevar la llevar la administración y configuración central de los sistemas Linux e interactuar directamente con el núcleo de los mismos. – https://en.wikipedia.org/wiki/Category:Linux_distributions_without_systemd – Silvia: consulta el enlace anterior y comenta de qué trata. 22 Arranque del SO Debian/Ubuntu • • • Systemd se encarga de arrancar todos los demás procesos durante el inicio del sistema. Cuáles se arrancan depende del nivel de ejecución en el que nos encontremos (también llamado runlevel) Por defecto, hay 7 runlevels posibles, desde el runlevel 0 hasta el runlevel 5, aunque esto es posible modificarlo. – Init 0: – Init 1: – Init 2-4: – Init 5: – Init 6: 23 Arranque del SO Debian/Ubuntu • • • • • • Init 0: ejecuta los procesos necesarios para parar el sistema Init 1: modo monousuario. Se ejecuta para realizar tareas de mantenimiento como root con unos servicios (o demonios) mínimos Init 2-4: modo multiusuario. Por defecto están todos configurados iguales (es decir, arrancan los mismos demonios), y están preparados por si queremos modificarlos (añadiendo o quitando demonios). Init 5: Multiusuario con entorno gráfico (sistema X Window) Init 6: Parecido al 0 pero sirve para reiniciar Los comandos halt, reboot, shutdown o poweroff lo único que hacen es llamar al nivel de ejecución 0 o 6 24 Arranque del SO Debian/Ubuntu La forma como se organizan estos daemons en cada nivel de ejecución es muy simple: • Cada nivel de ejecución tiene un directorio situado en /etc/rcX.d/ donde la “X” es el número de runlevel. • En estos directorios encontramos enlaces simbólicos a los shell scripts de los daemons situados en /etc/init.d/, que nos sirven para indicar al sistema si queremos iniciar o parar el daemon al que apuntan. • Con el mismo nombre del enlace se identifica la acción a realizar: si el enlace empieza por “S” (Start) indicamos que queremos iniciar el daemon, mientras que se empieza por “K” (Kill) indica que queremos pararlo. • Si el nombre no empieza por ninguna de estas letras, el sistema no hace nada con él. 25 Arranque del SO Debian/Ubuntu • • • • Después de esta letra se pone un número de 2 cifras entre “00” y “99”, que indica el orden de inicio o parada de los mismos. Este orden es importante, ya que algunos daemons necesitan que otros estén en ejecución antes de ser iniciados. Al cambiar de nivel de ejecución, el sistema inspeccionará los daemons del directorio correspondiente y empezará, primero, parando los daemons indicados y después iniciará los demás. Consulta por ejemplo: – ls /etc/rc0.d – ls /etc/rc5.d 26 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 27 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema 1.4 Sistema Operativos (SSOO) Shell Scripts I Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • Bash Shell scripts 2 Introducción a Bash Es la interfaz entre el usuario final y el Sistema Operativo. • No es el S.O. • Existen múltiples versiones y podemos averiguar cual tenemos instalada haciendo. Existen múltiples Shells en Unix: • Bourne shell (sh), C shell (csh), Korn shell (ksh), TC Shell (tcsh) • Bourne Again shell (bash). La más popular es la “bash” shell. • bash incorpora las prestaciones más útiles de la Korn shell (ksh) y la C shell (csh). • Ofrece mejoras funcionales sobre otras shells desde el punto de vista de programación y de su uso interactivo. 3 Introducción a Bash: tipos de shell Las shells más conocidas son: bash, GNU Bash o Bourne-Again Shell es una implementación GNU de la shell bsh, desarrollada por Stephen Bourne en Laboratorios Bell de AT&T en 1978. La shell bash fue desarrollada por GNU en 1989. csh o C shell, desarrollada por Bill Joy en la Universidad de Berkeley. Se distribuyó por primera vez en 1979 junto con las BSD. dash o Debian Almquist shell es una implementación GNU de la shell Almquist Shell o ash de las BSD. Desarrollada por Herbert Xu a principios de 1997, adoptando el nombre dash en 2002. ksh o Korn shell, desarrollada por David Korn en en los Laboratorios Bell de AT&T en 1980. sh, desarrollada por Ken Thompson en 1971 en los Laboratorios Bell de AT&T. Es uno de las primeros desarrollos de shell que, 50 años después, continúa utilizándose. tcsh o TENEX shell, desarrollada por Ken Greer entre finales de los años 70 y principios de los años 80. Es una mejora de la shell csh y en 1984 reemplazo a esta en las FreeBSD. 4 Introducción a Bash: tipos de shell zsh, desarrollada por Paul Falstad en 1990, cuando era estudiante en la Universidad de Princeton, como actualización y reemplazo de la shell bsh o Bourne Shell. A lo largo de la vida del sistema operativo macOS (Mac OS X, OS X y macOS) se han utilizado las shells tcsh, bash y zsh. Apple utiliza, en las últimas versiones del sistema operativo macOS (macOS 10.15 Catalina y macOS 11 Big Sur), la shell zsh que reemplaza a la shell bash. Consultar la versión de la Shell: $echo $SHELL $bash --versión $echo $BASH_VERSION $whereis bash $cat /etc/shells 5 Introducción a Bash Cambiar la Shell actual a bash: usa el comando chsh • Desde la Terminal se pueden listar todas las shells disponibles en el SO con el comando cat • /etc/shells Para cambiar la shell desde la Terminal se utiliza el comando chsh -s /bin/nombre_de_la_Shell (reiniciar la terminal) 6 Introducción a Shell Scripts bash no es únicamente una excelente shell por línea de comandos. • Es un lenguaje de scripting que permite utilizar las capacidades de la shell para automatizar muchas tareas que implicarían distintos comandos introducidos de manual. Scripting no es un lenguaje de programación: • Los lenguajes de programación son por lo general, más potentes y • • mucho más completos que los lenguajes de scripting. Los lenguajes de programación parten del código fuente, el cual luego es compilado para crear los ejecutables. Un ejecutable permite que los programas sean portables entre diferentes SSOO. 7 Comandos Linux • • • • • • • • • • • • chmod rm -rf cd $HOME mv chown ls –al clear, echo tree, lstree cat, nano who –u/b whereis, pwd ps –a | grep bash 8 Introducción a Shell Script • Un lenguaje de scripting también comienza por el código fuente, pero no se compila en un ejecutable • En su lugar, un intérprete lee cada instrucción del fichero fuente y las ejecuta de forma secuencial. • Los programas interpretados son por lo general son más lentos que los compilados. Ejecuta tu primer script Crea un fichero llamado “scr01.sh”: #!/bin/bash echo “Hola Mundo” Interpretar: indicar que el fichero es interpretado por bash para su ejecución Permisos: es importante hacer que el script sea ejecutable: $ chmod 700 scr01.sh $ ls –l: -rwx------ scr_01.sh 9 Introducción a Shell Script Ejecuta tu segundo script Crea un fichero llamado “scr02.sh”: #!/bin/bash mkdir log_apache mkdir log_tomcat cp ./servers/server1/*.log log_apache/ cp ./servers/server2/*.log log_tomcat/ $ chmod 700 scr02.sh $ ls –l: -rwx------ scr_02.sh 10 Shell Script: variables • • • • • • • Los valores se almacenan como cadenas de texto. No es necesario declarar las variables, con asignarle un valor es suficiente. Los operadores matemáticos que convierten las variables en número para realizar cálculos. Para consultar el valor de una variable se antepone el símbolo $ al nombre. #!/bin/bash cadena = “¡Hola Gente!” #esto es un comentario echo $cadena No existe el casting de los tipos de las variables, por lo que se podrá asignar a una misma variables diferentes valores sin importar su tipo. Se recomienda usar el mismo tipo de datos a una variable dentro de un mismo script. El carácter de escape de la bash \ mantiene el carácter siguiente. 11 Shell Script: uso de comillas • • • Las cadenas de textos deben ir acompañadas de comillas simples o dobles. El uso de comillas dobles “…” permite referenciar otras variables dentro de la cadena, e.g. cadena = “Tu edad es $edad” El uso de comillas simples permite mostrar una cadena sin la posibilidad de referenciar otras variables dentro de la misma cadena. – cadena = ‘Tu edad es $edad’ Ejercicio: Mostrar la siguiente cadena de texto: El valor de la variable ‘edad’ es “31” 12 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 13 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema Sistema Operativos (SSOO) 1.5 Shell Scripts II Grado en Ingeniería Informática Escuela Politécnica Superior Índice • Shell scripts 2 Shell Script: variables • • • • • • • Los valores se almacenan como cadenas de texto. No es necesario declarar las variables, con asignarle un valor es suficiente. Los operadores matemáticos que convierten las variables en número para realizar cálculos. Para consultar el valor de una variable se antepone el símbolo $ al nombre. #!/bin/bash cadena = “¡Hola Gente!” #esto es un comentario echo $cadena No existe el casting de los tipos de las variables, por lo que se podrá asignar a una misma variables diferentes valores sin importar su tipo. Se recomienda usar el mismo tipo de datos a una variable dentro de un mismo script. El carácter de escape de la bash \ mantiene el carácter siguiente. 3 Shell Script: uso de comillas • • • Las cadenas de textos deben ir acompañadas de comillas simples o dobles. El uso de comillas dobles “…” permite referenciar otras variables dentro de la cadena, e.g. cadena = “Tu edad es $edad” El uso de comillas simples permite mostrar una cadena sin la posibilidad de referenciar otras variables dentro de la misma cadena. – cadena = ‘Tu edad es $edad’ Ejercicio: Mostrar la siguiente cadena de texto: El valor de la variable ‘edad’ es “31” 4 Shell Script: variables entre procesos • • El comando export pone una variable en el entorno de forma que sea accesible por los procesos hijos. Si el proceso hijo modifica el valor de la variable cadena, no modificará el valor original del proceso padre. Verificarlo cambiando el valor de cadena desde un proceso hijo. Observa este ejemplo: $ cadena=libro $ bash # Ejecuta una nueva shell (proceso hijo) $ echo $cadena # No debería mostrar nada cadena $ exit # Regresa al proceso padre $ export cadena $ bash $ echo $cadena libro # El resultado es... 5 Shell Script: variables Hay dos tipos de variables de entorno: – Variables locales – Variables del entorno Las Variables del entorno se establecen por el sistema y se pueden encontrar utilizando el comando env. Las variables de entorno contiene valores especiales. Las variables del entorno se definen en /etc/profile, /etc/profile.d/ y ~/.bash_profile. Estos ficheros son de inicialización y son leídos cuando se invoca la bash shell. Cuando la login shell sale, la bash lee ~/.bash_logout 6 Shell Script: variables HOME: argumento por defecto (directorio home) del comando cd. PATH: el path de búsqueda de comandos. Es una lista de directorios separados por ‘:’ en los que se busca cuando se teclea cualquier comando. Normalmente, introducimos los comandos de la siguiente manera: – $ ./trash.sh Estableciendo PATH=$PATH:. Nuestro directorio de trabajo se incluye en path de búsqueda de comando y simplemente podremos introducir: – $ trash.sh 7 Shell Script: variables • • • • • • LOGNAME: contiene el nombre de usuario HOSTNAME: contiene el nombre de la máquina MACHTYPE: sistema hardware UID: contiene el id del usuario que no puede ser modificado SHLVL: contiene el nivel de anidamiento de la shell PS1: secuencia de caracteres monstrados antes del prompt – \t hora – \d fecha – \w directorio actual – \W última parte del directorio actual – \u nombre de usuario – \$ caracter del prompt 8 Shell Script: otras variables • • • • • • $#: número argumentos $*: todos los argumentos de la shell $@: semejante a la variable anterior $-: opciones suministradas a la shell $?: devolver valor de la última orden ejecutada $!: identificación del proceso de la última orden que comenzó con & 9 Shell Script: Exit Exit se puede utilizar para finalizar la ejecución de un script o para devolver un valor, el cuál estará disponible al proceso padre del script. • Cuando un script termina con exit sin parámetros, el estado de salida será el del último comando ejecutado en el script. • Cuando se ejecuta el script con el comando exit con parámetros, la sintaxis es: exit nnn, donde nnn=0-255 y el estado de salida es nnn 10 Shell Script: Operadores + suma, - resta, * multiplicación, / división, ** exponenciación % módulo Prueba lo siguiente: $ a=(5+2)*3 $ echo $a $ b=2**3 $ echo $a+$b 11 Shell Script: Leer de teclado Read permite solicitar un valor de entrada para almacenarlo en una variable. Opciones read –s (no hace echo de la entrada) read –nN (acepta sólo N caracteres de entrada) read –p “mensaje” (muestra un mensaje) read –tT (acepta una entrada por un tiempo máximo de T segundos) Ejemplo (copiar.sh) #!/bin/bash echo -n “Introduzca nombre de fichero a copiar: ” read fichero cp -i $fichero echo “El fichero $fichero ha sido copiado!“ 12 Shell Script: Leer de teclado Ejemplo: $ read –s –n1 -p “si (S) o no (N)?” respuesta si (S) o no (N) ? S $ echo $respuesta S 13 Shell Script: Ejecutar comandos El símbolo ` tiene un uso diferente de ´. Se utiliza para sustitución de instrucciones. Es decir si dentro de un script aparece el texto `comando` entonces se ejecutará lo orden que está entre las ` $ LISTA=`ls` $ echo $LISTA # Lista los archivos fichero.sh, scr01.sh Otra forma de realizar la sustitución de comandos: $(comando) $ LISTA=$(ls) $ echo $LISTA hola.sh leer.sh ls $( pwd ) ls $( echo /bin ) 14 Shell Script: Estructura de control Condicional: la forma más básica es: – if [expresión]; then instrucciones elif [expresión]; then instrucciones else instrucciones fi – Las secciones elif(else if) y else son opcionales 15 Shell Script: Expresiones Una expresión puede ser: comparación de cadenas, comparación numérica, operadores de fichero y operadores lógicos y se representa mediante [expresión]: Comparación de cadenas: = != -n evalúa si la longitud de la cadena es superior a 0 -z evalúa si la longitud de la cadena es igual a 0 Ejemplos: [ s1 = s2 ] (true si s1 es igual a s2, sino false) [ s1 != s2 ] (true si s1 no es igual a s2, sino false) [ s1 ] (true si s1 no está vacía, sino false) [ -n s1 ] (true si s1 tiene longitud mayor que 0, sino false) [ -z s2 ] (true si s2 tiene longitud 0, sino false) 16 Shell Script: Expresiones Comparación cadenas: = != #!/bin/bash echo -n “Introduzca su nombre de usuario: ” read login if [ “$login” = “$USER” ]; then echo “Hola, $login. Cómo está hoy?” else echo “Tú no eres $USER!!!” fi 17 1 Shell Script: Expresiones Comparación numérica: -eq -ge -le -ne -gt -lt Ejemplos: [ n1 -eq n2 ] [ n1 -ge n2 ] #!/bin/bash echo -n “Introduzca un número 1 < x < 10: "2 read num if [ “$num” -lt 10 ]; then if [ “$num” -gt 1 ]; then echo “$num*$num=$(($num*$num))” else echo “¡Número fuera de rango!” fi else echo “¡Número fuera de rango!” fi [ n1 -le n2 ] [ n1 -ne n2 ] [ n1 -gt n2 ] [ n1 -lt n2 ] 18 Shell Script: Expresiones Operadores de archivos: -d verifica si el path dado es un directorio -f verifica si el path dado es un archivo -s verifica si el path dado en un link simbólico -e verifica si el fichero existe -s verifica si el fichero tiene un tamaño mayor a 0 -r verifica si el fichero tiene permiso de lectura Ejemplos: [ -d nombre_fichero] [ -f nombre_fichero ] [ -e nombre_fichero ] [ -s nombre_fichero ] [ -r nombre_fichero ] [ -w nombre_fichero ] [ -x nombre_fichero ] -w verifica si el fichero tiene permiso de escritura -x verifica si el fichero tiene permiso de ejecución #!/bin/bash if [ -f /etc/fstab ]; then 3 cp /etc/fstab . echo “Hecho.” else echo “Archivo /etc/fstab no existe.” exit 1 fi 19 Shell Script: Expresiones Operadores lógicos: ! = NOT -a = AND -o = OR && = AND || = OR #!/bin/bash echo -n “Introduzca un número entre 1 < x < 10:” read num if [ “$num” -gt 1 –a “$num” -lt 10 ]; then echo “$num*$num=$(($num*$num))” else echo “Número introducido incorrecto !” fi #!/bin/bash echo -n “Introduzca un número 1 < x < 10: " read num if[ “$number” -gt 1 ] && [ “$number” -lt 10 ]; then echo “$num*$num=$(($num*$num))” else echo “Número introducido incorrecto !” fi 20 5 4 Shell Script: parámetros Los parámetros posicionales se asignan desde la shell cuando se invoca. Parámetro posicional “N” se referencia como “${N}”, o “$N” cuando “N” lo forma un sólo dígito Parámetros especiales $# número de parámetros pasados $0 devuelve el nombre del shell script que se está ejecutando y su ubicación en el sistema de archivos $* devuelve en una cadena de caracteres todos los parámetros pasados al script $@ devuelve un array con los parámetros pasados al script 6 #!/bin/bash echo “$#; $0; $1; $2; $*; $@” Así puedes probar tu script No 6 $ ./scr06.sh estudiante1 estudiante2 ./scr06.sh; estudiante1; estudiante2; estudiante1 estudiante2; estudiante1 estudiante2 21 Shell Script: case case $var in val1) instrucciones;; val2) instrucciones;; *) instrucciones;; esac #!/bin/bash echo -n “Introduzca un número entre 1 < x < 10: ” read x case $x in 1) echo “Valor de x es 1.”;; 2) echo “Valor de x es 2.”;; 3) echo “Valor de x es 3.”;; 4) echo “Valor de x es 4.”;; 5) echo “Valor de x es 5.”;; 6) echo “Valor de x es 6.”;; 7) echo “Valor de x es 7.”;; 8) echo “Valor de x es 8.”;; 9) echo “Valor de x es 9.”;; 0 | 10) echo “Número incorrecto.”;; *) echo “Valor no reconocido.”;; esac 22 Shell Script: for for for var in lista do statements done #!/bin/bash let sum=0 for num in 1 2 3 4 5 do let “sum = $sum + $num” done echo $sum 7 8 #!/bin/bash for x in papel lapiz boli; do echo “El valor de la variable x es: $x” sleep 1 done 23 Shell Script: for for for var in lista do statements done #!/bin/bash lista=“antonio luis maria pepa” for x in $lista do echo “El valor de la variable x es: $x” sleep 1 done 9 10 #!/bin/bash for x in “papel A4” “lapiz STADTLER” “boli BIC”; do echo “El valor de la variable x es: $x” sleep 1 done 24 Shell Script: for #!/bin/bash # Lista todos los ficheros del directorio /bin for x in /bin do ls -l “$x” done 11 #!/bin/bash # Lista todos los ficheros del directorio actual for x in * do ls -l “$x” sleep 1 done 12 #!/bin/bash read –p “Introduzca el nombre de un directorio: ” directorio echo “enlaces simbólicos en el directorio $directorio “ for fichero in $( find $directorio -type l ) do echo "$fichero" done 13 25 Shell Script: arrays Crear un array mascota[0]=perro mascota[1]=gato mascota[2]=pez pet=( perro gato pez ) Longitud máxima de un array son 1024 elementos. Para extraer una entrada del array ${array[i]} $ echo ${mascota[0]} perro $ echo ${mascota[2]} pez 26 Shell Script: arrays Para extraer todos los elementos se utiliza un asterisco: echo ${array[*]} Para saber cuántos elementos hay en el array: echo ${#array[*]} Podemos combinar los arrays con bucles utilizando for: for x in ${array[*]} do echo ${array[$x]} done 27 Shell Script: arrays Estructura tipo C alternativa para for for (( EXPR1 ; EXPR2 ; EXPR3 )) do instrucciones done #!/bin/bash echo “Introduzca un número: ”; read x 14 let sum=0 for (( i=1 ; $i<$x ; i=$i+1 )) ; do let “sum = $sum + $i” done echo “La suma de los primeros $x números es: $sum” 28 Shell Script: while while expresion_evalua_a_true do instrucciones done #!/bin/bash 15 echo –n “Introduzca un número: ”; read x let sum=0; let i=1 while [ $i –le $x ]; do let “sum = $sum + $i” let “i = $i + 1” done echo “La suma de los primeros $x números es: $sum” 29 Shell Script: until until expresion_evalua_a_true do instrucciones done #!/bin/bash echo “Introduzca un número: ”; read x echo ; until [ “$x” -le 0 ]; do echo $x x=$(($x –1)) sleep 1 done echo ; echo FIN 30 16 Shell Script: funciones #!/bin/bash function check() { 17 if [ -e "/home/$1" ] then return 0 else return 1 fi } echo “Introduzca el nombre del archivo: ” ; read x if check $x then echo “$x existe !” else echo “$x no existe !” fi 31 Shell Script: hacer debug Bash ofrece dos formas de depurar los shell scripts -v : muestra cada línea completa del script antes de ser ejecutada -x : muestra cada línea abreviada del script antes de ser ejecutada Uso: #!/bin/bash –v, o #!/bin/bash –x #!/bin/bash –x echo –n “Introduzca un número: ”; read x let sum=0 for (( i=1 ; $i<$x ; i=$i+1 )) ; do let “sum = $sum + $i” done echo “La suma de los $x primeros números es: $sum” 32 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 33 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema Sistema Operativos (SSOO) 2.1 Definición y Gestión de procesos Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • • Definición de proceso Gestión de procesos Estados de los procesos Gestión de procesos en Linux 2 Definición de proceso Un proceso puede informalmente entenderse como un programa en ejecución. • Formalmente un proceso es "Una unidad de actividad que se caracteriza por la ejecución de una secuencia de instrucciones, un estado actual, y un conjunto de recursos del sistema asociados". 3 Definición de proceso La gestión de procesos es una de las tareas fundamentales de cualquier sistema operativo El sistema operativo debe: • Asignar recursos a los procesos • Permitir el intercambio de información entre los mismos • Proteger los recursos de un proceso del resto • Y facilitar la sincronización de los procesos 4 Definición de proceso ¿Es lo mismo un programa que un proceso? 5 Definición de proceso Para que el SO pueda llevar estas tareas, este mantiene una estructura de datos para cada proceso que describe: • Su estado • Los recursos que posee Esto permite al sistema operativo imponer un control sobre los procesos (es decir, gestionar los procesos) 6 Gestión de procesos Principal problema: El cuello de botella que se forma por la diferencia de velocidad entre el procesador y los dispositivos de entrada y salida (E/S). Si un proceso que está usando el procesador necesita realizar una operación de E/S (por ejemplo, escribir en disco duro), el SO debe dar paso a otro proceso para que el procesador no esté inactivo. El SO sería algo parecido a un policía de tráfico. 7 Gestión de procesos En resumen, el SO debe gestionar el uso que cada proceso hace de los recursos hardware del sistema (en este tema, el procesador y el disco duro), repartiendo los tiempos que necesitan cada uno de los procesos. 8 Estados de los procesos Un proceso puede estar en los siguientes estados principales: • • • • • Ejecución: es un proceso que está haciendo uso del procesador. Bloqueado: no puede ejecutarse hasta que un evento externo sea llevado a cabo. Listo: ha dejado disponible al procesador para que otro proceso pueda ocuparlo. Nuevo: proceso que se acaba de crear, pero que aún no ha sido admitido en la lista de procesos ejecutables por el sistema operativo (no ha sido aún cargado en la memoria principal). Terminado: el proceso ha sido excluido por el sistema operativo, bien porque se detuvo o bien porque fue abandonado por alguna otra razón 9 Gestión de procesos en Linux ¿Cómo se gestionan los procesos en Linux? La orden más importante es la orden ps. • Lista todos los procesos en ejecución del sistema • Y toda su información asociada 10 Gestión de procesos en Linux Con ps a secas podemos ver los procesos del usuario (si en vez del UID queréis verlo con el username se pone ps u, y además sale %CPU y %MEM) ¿Cómo identifico mi UID? $echo $UID 11 Gestión de procesos en Linux • Ver todos los procesos del sistema escribo: ps -ef • Para ver las primeras líneas: ps -ef | head -5 • Valores importantes mostrados en ps (ps –ef): – – – – UID – usuario que ha lanzado el proceso PID: ID del proceso PPID: ID del proceso padre CMD: orden que ha lanzado el proceso 12 Gestión de procesos en Linux • • Con ps –u joselito se pueden ver qué procesos está ejecutando el usuario joselito Con ps –e se pueden ver todos los procesos del sistema 13 Gestión de procesos en Linux Otra opción muy común para lanzar la orden ps es ps aux • La lista muestra muchos procesos, para ello usa el comando en conjunción con grep (si quiero filtrar) o con more (paginar) – – • ps aux | grep bash ps aux | more También, para ver las primeras líneas: – ps aux | head -5 14 Gestión de procesos en Linux Valores importantes mostrados en ps aux: USER – usuario que ha lanzado el proceso PID: ID del proceso %CPU y %MEM: % uso de CPU y memoria TIME: tiempo de CPU acumulado STAT 15 Gestión de procesos en Linux Estado del proceso (STAT) → ver man ps S: (interruptible sleep): en pausa, esperando un evento para continuar R: (running o runnable): en ejecución T: Marks a stopped process. Parado U: process in uninterruptible wait I (iddle): Marks a process that is idle (sleeping for longer than about 20 seconds) Z: Marks a dead process (a “zombie') ver man ps 16 Gestión de procesos en Linux Procesos padre y procesos hijos • Para verlos, lanzar varias instancias del shell con la orden bash, y ver con ps -ef los PID y el PPID • ps -ef | grep bash (ver su PID y el PPID) Para ver quién es su padre: • ps -p 538 (o el PPID que sea) • bash (lanzo otro proceso hijo bash) • ps -ef | grep bash (ver su PID y el PPID, que será el PID del primer bash) 17 Gestión de procesos en Linux Para mostrar el árbol de procesos se usa la orden pstree Posiblemente habrá que instalarlo con apt-get install Forma de ejecutarlo: • pstree -p (aparecen los PIDs) • pstree 1581 (el árbol de un proceso en concreto con PID 1581) • También se puede ver algo parecido con ps axjf 18 Gestión de procesos en Linux Más información de los procesos: < High-priority (not nice to other users) N Low-priority (nice to other users) + Is in the foreground process group 19 Gestión de procesos en Linux La orden top: Muestra valores actualizándose instantáneamente • Parecido al monitor del sistema y al administrador de tareas (task manager) • Pero desde aquí no se pueden administrar los procesos Opciones en top: top –d 5 (Donde 5 es el número de segundos a transcurrir entre cada muestreo) top –o %CPU (Donde %CPU es el valor por el que vamos a ordenar los procesos ) 20 Gestión de procesos en Linux Trabajos: listado de trabajos (procesos creados por un usuario) ejecutándose • También se le llaman tareas • Se usa la orden jobs A cada trabajo se le asigna un número N como identificador. Un trabajo (proceso) puede ejecutarse en: • Modo foreground (primer plano) o • Backgroung (segundo plano) 21 Gestión de procesos en Linux Background: $ nombre_del_proceso & Ejemplo: • Orden sleep: la orden sleep ejecutaría un proceso después del tiempo especificado Por ejemplo: sleep 10; date Mostraría la fecha a los diez segundos 22 Gestión de procesos en Linux Background: $ nombre_del_proceso & Ejemplo: • Orden sleep: la orden sleep ejecutaría un proceso después del tiempo especificado Por ejemplo: sleep 10; date Mostraría la fecha a los diez segundos Prueba: • sleep 60 & > /dev/null • Para verlo: jobs (identificado con [1]) • ps aux | grep sleep (identificado con su PID) 23 Gestión de procesos en Linux Suspender un trabajo en foreground: [ctrl-z] • sleep 60 • ctrl-z Ver jobs 24 Gestión de procesos en Linux Para pasar un trabajo de foreground a background (y viceversa): • Primero suspenderlo [ctrl-z] • Lo veo en jobs Escribir luego • $ bg %n (fg para foreground), siendo n el número de trabajo que se ve en jobs • No hace falta poner % 25 Gestión de procesos en Linux Si sleep 60 es el trabajo 2, lo paso a foreground así: • fg 2 Lo suspendo otra vez: [Ctrl-z] Lo veo en jobs Lo paso a background así: • bg 2 Parar un trabajo foreground antes de que acabe: [Ctrl-C] • No lo veré en jobs 26 Gestión de procesos en Linux Otro ejemplo: • Ejecuto top en foreground • ¿Qué diferencia hay entre pulsar [Ctrl+c] y [Ctrl+z] • Una vez suspendido reanudarlo en foreground • Pasarlo a background desde foreground • ¿Cómo lo paro ahora, estando en background? 27 Gestión de procesos en Linux No puedo usar [Ctrl+c] • Debo matar la tarea: kill %1 Otra opción sería matar el proceso. Para ello debería buscar antes el PID y luego hacer un kill a ese PID, sin el % • ps aux | grep top • kill 1767 (1767 = PID del proceso) Fijaos que no se pone el % ¿Qué pasa si se pone kill 1 en vez de kill %1? 28 Gestión de procesos en Linux ¿Quién puede matar un proceso? • Sólo el propietario de ese proceso • Recordad que lo puedo saber por el UID asociado al proceso Cuando se ejecuta la orden kill, el SO envía una señal al proceso (señal 15 por defecto o de terminación de proceso) • Existen más de 20 señales • Existen algunos procesos como el propio Shell que no mueren cuando reciben esta señal • ¿Qué hacemos entonces para matarlo? 29 Gestión de procesos en Linux Intenta matar la shell • Kill de la muerte: sudo kill -9 PID Ejemplo: • Identificar con ps –ef y grep el PID del shell También se puede hacer poniendo solo ps Intentar matarlo con un kill • Matarlo con el kill -9 30 Gestión de procesos en Linux Al igual que Apache, multitud de servicios necesitan ser reiniciados, y la mayoría de ellos responde al argumento ‘HUP’ (Hang up) de kill. Mediante el siguiente comando, el servicio perteneciente a Apache, se reiniciará y volverá a cargar el fichero de configuración, permitiéndonos ver si los cambios han surtido efecto y volviendo a dar servicio a los usuarios. • kill –HUP [PID de Apache] 31 Gestión de procesos en Linux Si queremos matar un proceso por su nombre y no por su PID usaremos la orden killall • killall sleep • killall Firefox Esta orden mataría el proceso Firefox y todos los que dependen de él. • Otro ejemplo con sleep y shell scripts: la orden who (también w sólo) dice quién está en el sistema. • Mediante (sleep 3600; who >> log) & crearíamos un log con el registro de usuarios en el sistema una hora después. 32 Gestión de procesos en Linux ¿Cómo funciona? • Se crea un proceso en modo background que duerme (suspende su operación) durante 3600 segundos; luego se despierta, ejecuta la orden who y coloca la salida en un fichero de nombre log. Otro ejemplo: mediante este script: (while true do sleep 60 finger done) & Finger dice qué usuarios han hecho login en el sistema 33 Gestión de procesos en Linux Prioridad: se usa la orden nice • La orden nice en Linux sirve para ejecutar un programa con su prioridad de programación modificada. • Se le asignará de esta forma más o menos tiempo de CPU y se ejecutará por lo tanto más lento (o más rápido) • Los valores van desde el -20 (mayor prioridad al proceso) al 19 (menor prioridad) • Solo los usuarios root pueden modificar la prioridad de todos los procesos. • Los demás usuarios podrán modificar la prioridad de los procesos de los que son propietarios. 34 Gestión de procesos en Linux Prioridad Aumentar la prioridad: • nice -n-20 orden (-20 es la máxima prioridad) Disminuir la prioridad • nice -n19 orden (19 es la mínima prioridad) Necesitamos ser root (o sudo) para cambiar la prioridad 35 Gestión de procesos en Linux Prioridad Ejemplo: sudo su nice -n-19 sleep 120 & ps –l (ver su prioridad PRI) nice -n19 sleep 130 & ps –l (ver su prioridad PRI) 36 Gestión de procesos en Linux Prioridad • Podemos restablecer la prioridad de este proceso, con pid 898, con el comando renice • renice 898 (898 sería el pid de sleep; verlo con ps al) • Su prioridad volvería a ser 0 37 Gestión de procesos en Linux Prioridad • Si se observa que un usuario del sistema está ocupando mucho tiempo de CPU, se puede asignar a todos los procesos que este lance una prioridad más baja (o más alta) Haga la siguiente prueba: • Como root: renice +20 -u alumno • Salir de root (logout) • Y al volver a ser el usuario, lanzad top & • Ver su prioridad con ps al 38 Gestión de procesos en Linux Otras órdenes: time: la orden time se utiliza para determinar la duración de ejecución de un determinado comando. • Da el tiempo del sistema, el tiempo del usuario y el tiempo real • Ya lo veremos con los algoritmos de gestión de procesos 39 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 40 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema Sistema Operativos (SSOO) 2.1 Gestión de procesos Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • • • Creación de procesos. Terminación de procesos. Ciclo de vida de un proceso. Tipos de planificación. Algoritmos de planificación 2 Creación de procesos Los SO proveen mecanismos para que los procesos puedan crear otros procesos → Llamada al sistema El proceso de creación se puede repetir recursivamente creándose una “estructura familiar” → Árbol de procesos Esto no quiere decir que la comunicación entre padre e hijo sea natural y sencilla, NO. Asignación de recursos al nuevo proceso: – Los obtiene directamente del SO – El padre debe repartir sus recursos con el proceso hijo o compartir todos o parte de ellos con él. Se evita así que un proceso bloquee el sistema multiplicándose indefinidamente. 3 Creación de procesos Cuando se crea un proceso: – En términos de ejecución – El padre continua ejecutándose en paralelo con su/s hijo/s. – El padre espera a que alguno o todos sus hijos hayan terminado. – En términos del espacio en memoria – El proceso hijo es un clon del proceso padre. – El proceso hijo tiene ya un programa cargado en memoria. 4 Creación de procesos ¿Qué necesita saber el SO sobre cada proceso? • Un proceso necesita la memoria suficiente para almacenar el programa y los datos que utiliza • Atributos para que el SO pueda controlar el proceso. A estos atributos se les llama Bloque de Control del Proceso (BCP) • A los programas, datos y atributos se le llama imagen del proceso 5 Creación de procesos ¿Qué tiene en concreto el BCP? • • Identificación del proceso: PID, PPID y UID del usuario que creó el proceso (ver orden top) Información del estado del procesador – Si se suspendió el proceso, se guardan aquellos registros del procesador que permitan reanudarlo más adelante. ¿Dónde se guarda la imagen del proceso? • En memoria principal (RAM) – si está en ejecución todo o parte tiene que estar aquí • En memoria de disco (memoria virtual) – si está suspendido, todo. Si no, puede estar solo parte de la imagen. 6 Creación de procesos En la familia Unix se distingue entre crear procesos y ejecutar nuevos programas. • La llamada al sistema para crear un nuevo proceso se denomina fork(). • Esta llamada crea una copia casi idéntica del proceso padre. Ambos procesos, padre e hijo, continúan ejecutándose en paralelo. El padre obtiene como resultado de la llamada a fork() el pid del hijo y el hijo obtiene 0. Algunos recursos no se heredan (p.ej. señales pendientes). 7 Creación de procesos El proceso hijo puede invocar la llamada al sistema exec*() – sustituye su imagen en memoria por la de un programa diferente El padre puede dedicarse a crear más hijos, o esperar a que termine el hijo – wait() lo saca de la cola de “listos” hasta que el hijo termina 8 Creación de procesos Ineficiencias del modelo fork() – Se copian muchos datos que podrían compartirse – Si al final se carga otra imagen, todavía es peor porque todo lo copiado se deshecha. Muchos UNIX usan COW – Copy-on-Write es una técnica que retrasa o evita la copia de los datos al hacer el fork. – Los datos se marcan de manera que si se intentan modificar se realiza una copia para cada proceso (padre e hijo). – Ahora fork() sólo copia la tabla de páginas del padre (no las páginas) y crea un nuevo BCP para el hijo. 9 Creación de procesos www.u3cm.es 10 Creación de procesos www.u3cm.es 11 Creación de procesos www.u3cm.es 12 Terminación de procesos Cuando un proceso termina todos los recursos asignados son liberados: – memoria, ficheros abiertos, entradas en tablas,... y el kernel notifica al proceso padre el evento. Un proceso puede terminar de 2 formas: • Voluntariamente: Llamada al sistema exit() • Involuntariamente: – Excepciones: división por cero, violación de segmento – Abortado por el usuario (ctrl-c) u otro proceso (kill), es decir, señales que no puede manejar o ignorar. 13 Terminación de procesos Cuando un proceso termina pueden suceder dos cosas: – Sus hijos no se ven afectados – Todos los hijos acaban también → terminación en cascada (Ej. VMS) En Unix, – Los hijos del proceso terminado pasan a depender del proceso init – El proceso finalizado pasa a estado Zombie hasta que el proceso padre recoge su código de finalización. 14 Terminación de procesos Las terminación de un proceso y la eliminación de su BCP son tareas diferenciadas: – Cuando el padre obtiene la información del hijo, se procede a eliminar las estructuras de datos – Llamada al sistema wait() • Bloquea al proceso hasta que termina el/un hijo • Devuelve el PID del hijo finalizado 15 Ciclo de vida de un proceso www.u3cm.es 16 Ciclo de vida de un proceso • Cuando existen muchos procesos en ejecución el rendimiento puede bajar por excesiva paginación. – Solución: El Sistema Operativo puede expulsar totalmente procesos al área de intercambio del disco. • Introduce nuevos estados de los procesos. – Bloqueado y suspendido. – Listo y suspendido. 17 Ciclo de vida de un proceso 18 www.u3cm.es Tipos de planificación (Niveles) Planificación a corto plazo – Selecciona el siguiente proceso a ejecutar. Planificación a medio plazo – Selecciona qué procesos se añaden o se retiran (expulsión a swap) de memoria principal. Planificación a largo plazo – Realiza el control de admisión de procesos a ejecutar. – Muy usada en sistemas batch. 19 Tipos de planificación • No apropiativa. – El proceso en ejecución conserva el uso de la CPU mientras lo desee. • Apropiativa. – El sistema operativo puede expulsar a un proceso de la CPU. 20 Puntos de decisión de planificación Momentos en los que se puede decidir la planificación de un proceso: 1. 2. 3. Cuando un proceso se bloquea en espera de un evento – Realización de una llamada al sistema. Cuando se produce una interrupción. – Interrupción del reloj. – Interrupción de fin de E/S. Fin de proceso. Planificación no apropiativa: 1 y 3. – Windows95, MacOS anteriores a versión 8. Planificación apropiativa: 1, 2 y 3. 21 Pilas de procesos Los procesos listos para ejecutar se mantienen en una cola. Alternativas: • Cola única. • Colas por tipos de procesos. • Colas por prioridades. 22 Algoritmos de planificación (Medidas) • Utilización de CPU: – Porcentaje de tiempo que se usa la CPU. – Objetivo: Maximizar. • Productividad: – Número de trabajos terminados por unidad de • tiempo. – Objetivo: Maximizar. Tiempo de retorno (Tq) – Tiempo que está un proceso en el sistema. Instante final (Tf) menos instante inicial (Ti). – Objetivo: Minimizar. 23 Algoritmos de planificación (Medidas) • Tiempo de servicio (Ts): – Tiempo dedicado a tareas productivas (cpu, entrada/salida). Ts = TCPU+ TE/S • Tiempo de espera (Te): – Tiempo que un proceso pasa en colas de espera. Te = Tq – Ts • Tiempo de retorno normalizado (Tn): – Razón entre tiempo de retorno y tiempo de servicio. Tn = Tq/Ts – Indica el retardo experimentado. 24 Algoritmos de planificación Grupo 1: Asignación FCFS First to Come First to Serve: Primer en llegar primero en servir. – Algoritmo no apropiativo. – Penaliza a los procesos cortos. Grupo 2: Asignación SJF Shortest Job First: Primero el trabajo más corto. – – – – Algortimo no apropiativo. Selecciona el trabajo más corto. Solamente se puede aplicar si se conoce de antemano la duración de cada trabajo. Posibilidad de inanición: • Si continuamente llegan trabajos cortos, los trabajos largos nunca llegan a ejecutarse. 25 Algoritmos de planificación Grupo 3: Cíclico o Round-Robin – Mantiene una cola FIFO con los procesos listos para ser ejecutados. – Un proceso recibe el procesador durante un cuanto o rodaja de tiempo. – Algoritmo apropiativo. Grupo 4: Planificación en Windows Principales características: – Basado en prioridades y uso de cuantos de tiempo. – Planificación apropiativa. – Planificación con afinidad de procesador. 26 No olvidemos que… • • • • • • La creación de un proceso implica la creación de su imagen de memoria y de su BCP. Un proceso pasa por distintos estados durante su ejecución. El sistema operativo realiza la planificación de los procesos. La planificación puede ser apropiativa y no apropiativa. Los distintos algoritmos de planificación de procesos pueden favorecer más o menos a un tipo de procesos. Los sistemas operativos modernos usan planificación apropiativa. 27 Bibliografía • • • • U3CM, www.u3cm.es, Material de la asignatura Sistemas Operativos CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-2054462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 28 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema 3.1 Sistema Operativos (SSOO) Procesos e Hilos Grado en Ingeniería Informática Escuela Politécnica Superior Índice • • • Procesos e hilos. Multiprocesamiento simétrico. Micronúcleos. 2 Procesos e hilos • En los SO tradicionales, cada proceso tiene un espacio • • de direcciones y un solo hilo de control. De hecho, ésa es casi la definición de un proceso. Un proceso es algo más complejo de lo que se ha visto hasta este momento. Contiene dos conceptos diferentes y potencialmente independientes: – uno relativo a la propiedad de recursos y – Otro relativo a la ejecución. • Esta distinción ha llevado al desarrollo de los hilos o threads. 3 Procesos e hilos Características de un proceso: 1. Recursos: un proceso incluye un espacio de direcciones virtuales para el manejo de la imagen del proceso. – La imagen de un proceso es la colección de programa, datos, – – pila y atributos definidos en el bloque de control del proceso. A un proceso se le puede asignar control o propiedad de recursos tales como la memoria principal, canales E/S, dispositivos E/S y archivos. El sistema operativo se encarga de la protección para evitar interferencias no deseadas entre procesos en relación con los recursos. 4 Procesos e hilos Características de un proceso: 2. Planificación y ejecución: la ejecución de un proceso sigue una ruta de ejecución (traza) a través de uno o más programas. – La ejecución puede estar intercalada con ese u otros procesos. – Un proceso tiene un estado de ejecución: Ejecutando, Listo, – etc.. Tiene asignada una prioridad de activación, siendo ésta la entidad que planifica y activa el sistema operativo. 5 Procesos e hilos Estas dos características son independientes y podrían ser tratadas como tales por el sistema operativo. Para distinguir estas dos características, la unidad que se activa se suele denominar hilo (thread), o proceso ligero, mientras que la unidad de propiedad de recursos se suele denominar proceso o tarea. 6 Procesos e hilos ¿Por qué definir hilos? • • • Muchas aplicaciones realizan varias actividades a la vez. Algunas de ésas se pueden bloquear de vez en cuando. Al descomponer una aplicación en varios hilos secuenciales que se ejecutan en cuasi-paralelo, el modelo de programación se simplifica. ¿No era lo mismo para los procesos? • • • Sí, se pensaba en procesos paralelos. Los hilos añaden un nuevo elemento: la habilidad de las entidades en paralelo de compartir un espacio de direcciones y todos sus datos entre ellas. Esta habilidad es esencial para ciertas aplicaciones, razón por la cual no funcionará el tener varios procesos (con sus espacios de direcciones separados). 7 Procesos e hilos ¿Por qué definir hilos? • • • • • Los hilos son más ligeros que los procesos. Más fáciles de crear y de destruir (de 10 a 100 veces más rápido). Los hilos no producen aumento del rendimiento cuando todos están ligados en la CPU. Cuando hay una gran cantidad de cálculos y operaciones de E/S, el uso de hilos permite solapar con lo cual agiliza la velocidad de la aplicación. Los hilos son útiles en los sistemas con varias CPU, donde si es posible un verdadero paralelismo. 8 Multihilo Capacidad de un sistema operativo de dar soporte a múltiples hilos de ejecución en un solo proceso. El enfoque de un solo hilo de ejecución por proceso, en el que no se identifica con el concepto de hilo, se conoce como estrategia monohilo. – – – MS-DOS solo soporta un único proceso y un único hilo. Java soporta un único proceso con múltiples hilos. Windows, Solaris, Os soporta múltiples procesos y múltiples hilos. 9 Multihilo 10 Multihilo Ejemplos de uso de un sistema Multihilo. • Trabajo en primer plano y en segundo plano: – Esta forma de trabajo a menudo incrementa la velocidad que se percibe de la aplicación, permitiendo al programa solicitar el siguiente mandato antes de que el mandato anterior esté completado. • Procesamiento asíncrono: – Los elementos asíncronos de un programa se pueden implementar como hilos. • Velocidad de ejecución: – Un proceso Multihilo puede computar una serie de datos mientras que lee los siguientes de un dispositivo. Aunque un hilo pueda estar bloqueado por una operación de E/S mientras lee datos, otro hilo se puede estar ejecutando. 11 Multihilo Ejemplos de uso de un sistema Multihilo. • Estructura modular de programas: – Los programas que realizan diversas tareas o que tienen varias fuentes y destinos de entrada y salida, se pueden diseñar e implementar más fácilmente usando hilos. 12 Multihilo La planificación y la activación se realizan a nivel de hilo; por ello la mayor parte de la información de estado relativa a su ejecución se mantiene en estructuras de datos que están a su nivel. 13 Multihilo – Estado de los hilos • • Los principales estados de los hilos son: Ejecutando, Listo y Bloqueado. No tiene sentido usar estados de suspensión a un hilo porque este es estado aplicado a nivel de proceso. ¿Si se expulsa un proceso, todos sus hilos se deben expulsar porque comparten el espacio de direcciones del proceso? Las cuatro operaciones asociadas a los hilos son: • Creación: con un nuevo proceso se crea un hilo. Un hilo puede luego crear • • • otro hilo dentro del mismo proceso, facilitando argumentos e instrucciones al nuevo hilo. Bloqueo: si un hilo necesita esperar por un evento se bloquea (salva registros de usuario, el CP y punteros de pila). El procesador ejecuta otro hilo en estado Listo, dentro del mismo proceso o en otro diferente. Desbloqueo: cuando ocurre el evento por el que se ha bloqueado el hilo Finalización: al completar el hilo (se libera su registro y pilas) 14 Multihilo – Sincronización de hilos • • • Los hilos de un proceso comparten el mismo espacio de direcciones y otros recursos. Cualquier alteración de un recurso por cualquiera de los hilos, afecta al entorno del resto de los hilos del mismo proceso. Es necesario sincronizar las actividades de los hilos para que no interfieran entre ellos o corrompan estructuras de datos. – • Imagine el caso en que dos hilos intentan añadir simultáneamente, un elemento a una lista doblemente enlazada. Podría perderse un elemento o la lista podría acabar malformada. POSIX: IEEE definió un estándar para los hilos conocido como 1003.1c. Este paquete se conoce como Pthreads y la mayoría de los sistemas UNIX aceptan dicho paquete. – El estándar define más de 60 llamadas a funciones, que son demasiadas como para verlas en este libro. 15 Multihilo – POSIX • • • • IEEE definió un estándar para los hilos conocido como 1003.1c. Este paquete se conoce como Pthreads. La mayoría de los sistemas UNIX aceptan dicho paquete. El estándar define más de 60 llamadas a funciones, que son demasiadas como para verlas en este libro. 16 Tipos de implementación de hilos • Hilos en espacio de usuario ULT: consiste en ubicar los hilos en espacio de usuario. En este caso el kernel no conoce la existencia de dichos hilos, este cree que administra procesos con un solo hilo. 17 Tipos de implementación de hilos Hilos en espacio de usuario ULT • Ventajas – – – • Un paquete de hilos de nivel usuario puede implementarse en un sistema operativo que no acepte hilos. Cada proceso tenga su propio algoritmo de planificación personalizado. El procedimiento que guarda el estado del hilo y el planificador son sólo procedimientos locales, por lo que es mucho más eficiente invocarlos que realizar una llamada al kernel (la planificación de hilos es muy rápida). Problemas – – – – La manera en que se implementan las llamadas al sistema de bloqueo. Los hilos pueden utilizar llamadas de bloqueo para evitar que un hilo bloqueado afectara a los demás, pero esto suele generar muchos problemas. Cambiar esta implementación requiere modificar muchas aplicaciones de usuario. Se usa el sistema de envoltura para comprobar posibles bloqueos (es torpe). 18 Tipos de implementación de hilos Hilos en espacio de usuario ULT • Problemas – – – Fallos de página: el ordenador se pueden configurar para que no todo el programa se encuentre en memoria a la vez. Si el programa llama o salta a una instrucción que no esté en memoria, ocurre un fallo de página y el sistema operativo obtiene la instrucción faltante (y las instrucciones aledañas) del disco. El proceso se bloquea mientras la instrucción necesaria se localiza y se lee. Si un hilo produce un fallo de página, el kernel (quien no sabe de la existencia de los hilos) bloquea naturalmente todo el proceso hasta que se complete la operación de E/S, incluso si otros hilos pudieran ser ejecutados. 19 Tipos de implementación de hilos • Hilos en el kernel KLT: el kernel tiene una tabla de hilos que lleva la cuenta de todos los hilos en el sistema. Cuando un hilo desea crear un nuevo hilo o destruir uno existente, realiza una llamada al kernel, la cual se encarga de la creación o destrucción mediante una actualización en la tabla de hilos del kernel. 20 Tipos de implementación de hilos Hilos en el kernel KLT: características – – – • Cuando un hilo se bloquea, el kernel puede ejecutar otro hilo del mismo proceso (si hay otro listo) o un hilo de un proceso distinto. Los hilos de kernel no requieren de nuevas llamadas al sistema sin bloqueo. Si un hilo en un proceso produce un fallo de página, el kernel puede comprobar con facilidad si el proceso tiene otros hilos que puedan ejecutarse y de ser así, ejecuta uno de ellos mientras espera a que se traiga la página requerida desde el disco. Problemas – – – – El costo de una llamada al sistema es considerable, por lo que si las operaciones de hilos son comunes, habrá sobrecarga. El uso de fork() para crear otro proceso con muchos hilos Las señales se envían a los procesos, no a los hilos (modelo clásico). Los hilos de kernel son mejores que los hilos de usuario, pero estos son más lentos. 21 Recordar: Interrupción Interrupciones: – – – – • Señal que envía un dispositivo de E/S a la CPU para indicar que la operación de la que estaba ocupado, ya ha terminado. Las interrupciones son manejadas por el procesador después de que finaliza la instrucción actual. Interrupciones por Hardware: el hardware avisa al SO cuando el dispositivo de E/S ha terminado para que este intervenga y hacer que el programa que estaba esperando el dispositivo, continúe su ejecución. Interrupciones por Software: se produce cuando un usuario solicita una llamada del sistema (a través de un programa). Ambas permiten al SO utilizar la CPU en otras aplicación, mientras otra permanece a la espera de que concluya una operación en un dispositivo de E/S. Interrupciones TRAP: – Estas instrucciones permiten que un programa genere una interrupción. Estas instrucciones se emplean fundamentalmente para solicitar los servicios del sistema operativo. 22 Recordar: Interrupción Interrupciones TRAP: • • • • Estas instrucciones permiten que un programa genere una interrupción. Estas instrucciones se emplean fundamentalmente para solicitar los servicios del SO. La forma en que se realiza una llamada al sistema consiste en colocar un conjunto de parámetros en un lugar específico, para después ejecutar una instrucción del lenguaje máquina del procesador denominada trap (en castellano, trampa). La ejecución de esta instrucción máquina hace que el hardware guarde el contador de programa y la palabra de estado del procesador (PSW, Processor Status Word) en un lugar seguro de la memoria, cargándose un nuevo contador de programa y una nueva PSW. Este nuevo contador de programa contiene una dirección de memoria donde reside una parte (un programa) del SO, el cual se encarga de llevar a cabo el servicio solicitado. Cuando el sistema operativo finaliza el servicio, coloca un código de estado en un registro para indicar si hubo éxito o fracaso, y ejecuta una instrucción return from trap, esta instrucción provoca que el hardware restituya el contador de programa y la PSW del programa que realizó la llamada al sistema, prosiguiéndose así su ejecución. 23 Multiprocesamiento simétrico: SMP Los dos enfoques más populares para proporcionar paralelismo a través de la réplica de procesadores: multiprocesamiento simétricos (SMP) y clústers. La arquitectura SMP puede encajar dentro de las categorías de procesamiento paralelo. • • • • SISD SIMD MISD MIMD 24 Multiprocesamiento simétrico: SMP • • • • Única instrucción, único flujo de datos – Single instruction single data (SISD) stream. Un solo procesador ejecuta una única instrucción que opera sobre datos almacenados en una sola memoria. Única instrucción, múltiples flujos de datos – Single instruction multiple data (SIMD) stream. Una única instrucción de máquina controla la ejecución simultánea de un número de elementos de proceso. Cada elemento de proceso tiene una memoria de datos asociada, de forma que cada instrucción se ejecuta en un conjunto de datos diferente a través de los diferentes procesadores. Los procesadores vectoriales y matriciales entran dentro de esta categoría. Múltiples instrucciones, único flujo de datos – Multiple instruction single data (MISD) stream. Se transmite una secuencia de datos a un conjunto de procesadores, cada uno de los cuales ejecuta una secuencia de instrucciones diferente. Esta estructura nunca se ha implementado. Múltiples instrucciones, múltiples flujos de datos – Multiple instruction multiple data (MIMD) stream. Un conjunto de procesadores ejecuta simultáneamente diferentes secuencias de instrucciones en diferentes conjuntos de datos. 25 Multiprocesamiento simétrico: SMP • • • • MIMD permite establecer un propósito general para los procesadores, porque deben ser capaces de procesar todas las instrucciones necesarias para realizar las transformaciones de datos apropiadas. MIMD se puede subdividir por la forma en que se comunican los procesadores. Si cada procesador tiene una memoria dedicada, cada elemento de proceso es en sí un ordenador. La comunicación entre los computadores se puede realizar a través de rutas prefijadas o bien a través de redes. Este sistema es conocido como un cluster, o multicomputador. Si los procesadores comparten una memoria común, entonces cada procesador accede a los programas y datos almacenados en la memoria compartida, y los procesadores se comunican entre sí a través de dicha memoria; este sistema se conoce como multiprocesador de memoria compartida. El diseño de SMP y clústers es complejo, e involucra temas relativos a la organización física, estructuras de interconexión, comunicación entre procesadores, diseño del sistema operativo y técnicas de aplicaciones software. 26 Organización de un SMP 27 Consideraciones de diseño del SO • • • • • Procesos o hilos simultáneos concurrentes. Las rutinas del núcleo necesitan ser reentrantes para permitir que varios procesadores ejecuten el mismo código del núcleo simultáneamente. Planificación. La planificación se puede realizar por cualquier procesador, por lo que se deben evitar los conflictos. Sincronización. Con múltiples procesos activos, que pueden acceder a espacios de direcciones compartidas o recursos compartidos de E/S, se debe tener cuidado en proporcionar una sincronización eficaz. Gestión de memoria. La gestión de memoria en un multiprocesador debe tratar con todos los aspectos encontrados en las máquinas uniprocesador. Fiabilidad y tolerancia a fallos. El sistema operativo no se debe degradar en caso de fallo de un procesador. 28 Micronúcleos Ventajas • • • • • • • Interfaces uniformes. Extensibilidad Flexibilidad Portabilidad Fiabilidad Soporte de sistemas distribuidos Soporte de sistemas operativos orientados a objetos (OOOS). 29 Micronúcleos • • • • • • El micronúcleo nos lleva por sí mismo al soporte de sistemas distribuidos, incluyendo clústeres controlados por sistemas operativos distribuidos. Cuando se envía un mensaje desde un cliente hasta un proceso servidor, el mensaje debe incluir un identificador del servicio pedido. Si se configura un sistema distribuido (por ejemplo, un clúster) de tal forma que todos los procesos y servicios tengan identificadores únicos, entonces habrá una sola imagen del sistema a nivel de micronúcleo. Un proceso puede enviar un mensaje sin saber en qué máquina reside el servicio pedido. Una arquitectura micronúcleo funciona bien en el contexto de un sistema operativo orientado a objetos. Un enfoque orientado a objetos puede servir para diseñar el micronúcleo y para desarrollar extensiones modulares para el sistema operativo. 30 Micronúcleos: otros aspectos • • Una potencial desventaja que se cita a menudo de los micronúcleos es la del rendimiento. Lleva más tiempo construir y enviar un mensaje a través del micronúcleo. Gestión de memoria a bajo nivel. El micronúcleo tiene que controlar el concepto hardware de espacio de direcciones para hacer posible la implementación de protección a nivel de proceso. Conceder (Grant). El propietario de un espacio de direcciones (un proceso) puede conceder alguna de sus páginas a otro proceso. El núcleo borra estas páginas del espacio de memoria del otorgante y se las asigna al proceso especificado. Proyectar (Map). Un proceso puede proyectar cualquiera de sus páginas en el espacio de direcciones de otro proceso, de forma que ambos procesos tienen acceso a las páginas. Esto genera memoria compartida entre dos procesos. El núcleo mantiene la asignación de estas páginas al propietario inicial, pero proporciona una asociación que permite el acceso de otros procesos. Limpiar (Flush). Un proceso puede reclamar cualquier página que fue concedida o asociada a otro proceso. 31 Micronúcleos: otros aspectos • • Comunicación entre procesos (Interprocess Communication). La forma básica de comunicación entre dos procesos o hilos en un sistema operativo con micronúcleo son los mensajes. Gestión de E/S e interrupciones. Con una arquitectura micronúcleo es posible manejar las interrupciones hardware como mensajes e incluir los puertos de E/S en los espacios de direcciones. – – El micronúcleo puede reconocer las interrupciones pero no las puede manejar. Este genera un mensaje para el proceso a nivel de usuario que está actualmente asociado con esa interrupción. 32 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-205-4462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 33 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema 3.2 Sistema Operativos (SSOO) Gestión de Hilos y SMP Grado en Ingeniería Informática Escuela Politécnica Superior Índice • Gestión de Hilos y SMP Windows Linux 2 Gestión de hilos: Windows • Las estructuras de los procesos y los servicios proporcionados por el núcleo de Windows son relativamente sencillos y de propósito general. – – – • • Los procesos Windows están implementados como objetos. Un proceso ejecutable puede contener uno o más hilos. Tanto el objeto proceso como el objeto hilo, tienen funcionalidades de sincronización preconstruidas. Cuando Windows crea un nuevo proceso, utiliza el objeto definido para el proceso Windows como plantilla para generar la nueva instancia del proceso. En el momento de la creación se asignan los valores de los atributos. 3 Gestión de hilos: Windows • Un proceso Windows debe contener por lo menos un hilo que ejecutar. – – • El contexto es un atributo que permita al hilo suspender y reanudar su ejecución. – • Ese hilo puede a su vez crear otros hilos. ¿En un sistema multiprocesador, múltiples hilos de un mismo proceso pueden ejecutar en paralelo? Es posible cambiar el comportamiento de un hilo, alterando su contenido cuando el hilo está suspendido. Windows soporta la concurrencia entre procesos ya que hilos de diferentes procesos pueden ejecutar en paralelo. – Múltiples hilos del mismo proceso pueden estar asignados a distintos procesadores y pueden ejecutar de modo concurrente. 4 Gestión de hilos: Windows • • • Los hilos del mismo proceso pueden intercambiar información a través de su espacio de direcciones común. Estos tienen acceso a los recursos compartidos del proceso. Los hilos de diferentes procesos pueden intercambiar información a través del uso de memoria compartida. 5 Gestión de hilos: Windows 6 Gestión de hilos: Windows 7 Gestión de hilos: Windows 8 Gestión de hilos: Windows 9 Gestión de hilos: Windows • • • Listo (ready): el activador del micronúcleo conoce todos los hilos listos y los planifica en orden de prioridad. Substituto (standby): un hilo substituto se ha seleccionado para ejecutar en siguiente lugar en un determinado procesador. Si la prioridad del hilo substituto es suficientemente alta, el hilo actualmente en ejecución en ese procesador podría ser expulsado en su favor. De otra forma, el hilo substituto espera hasta que el hilo en ejecución se bloquea o finaliza su porción de tiempo. Ejecutando (running): una vez que el micronúcleo realiza un intercambio de hilo o proceso, el hilo sustituto pasa al estado de ejecución y ejecuta hasta que es expulsado, finaliza su porción de tiempo, se bloquea o termina. En los dos primeros casos vuelve a la cola de listos. 10 Gestión de hilos: Windows • • • Esperando (waiting): un hilo pasa a estado esperando cuando (1) se bloquea en un evento (por ejemplo, E/S), (2) espera voluntariamente por temas de sincronización, o (3) un subsistema manda al hilo a estado de suspendido. Cuando se satisface la condición de espera, el hilo pasa al estado Listo si todos sus recursos están disponibles. Transición (transition): un hilo entra en este estado después de esperar si está listo para ejecutar pero los recursos no están disponibles. Por ejemplo, la pila del hilo puede no estar en memoria. Cuando los recursos están disponibles, el hilo pasa al estado Listo. Terminado (terminated): un hilo se puede finalizar por sí mismo, por otro hilo o cuando su proceso padre finaliza. Cuando se completan las tareas internas, el hilo se borra del sistema, o puede retenerse por el ejecutivo para futuros reinicios. 11 Gestión de hilos: Solaris Solaris utiliza cuatro conceptos relacionados con los hilos: • Procesos: es un proceso normal UNIX e incluye el espacio de direcciones del usuario, la pila y el bloque de control del proceso. • Hilos de nivel de usuario: implementados a través de una biblioteca de hilos en el espacio de direcciones de un proceso, son invisibles al sistema operativo. Los hilos de nivel de usuario (user-level threads, ULT) son la interfaz para las aplicaciones paralelas. • Procesos ligeros: un proceso ligero (light-weight process, LWP) puede ser visto como una asociación entre ULT e hilos de núcleo. Cada LWP soporta uno o más ULT y se asocia con un hilo de núcleo. Los LWP se planifican de forma independiente por el núcleo y pueden ejecutar en paralelo en múltiples procesadores. • Hilos de núcleo: son entidades fundamentales que se pueden planificar para ejecutar en cualquier procesador del sistema. 12 Gestión de hilos: Solaris Solaris utiliza cuatro conceptos relacionados con los hilos: • Procesos: es un proceso normal UNIX e incluye el espacio de direcciones del usuario, la pila y el bloque de control del proceso. • Hilos de nivel de usuario: implementados a través de una biblioteca de hilos en el espacio de direcciones de un proceso, son invisibles al sistema operativo. Los hilos de nivel de usuario (user-level threads, ULT) son la interfaz para las aplicaciones paralelas. • Procesos ligeros: un proceso ligero (light-weight process, LWP) puede ser visto como una asociación entre ULT e hilos de núcleo. Cada LWP soporta uno o más ULT y se asocia con un hilo de núcleo. Los LWP se planifican de forma independiente por el núcleo y pueden ejecutar en paralelo en múltiples procesadores. • Hilos de núcleo: son entidades fundamentales que se pueden planificar para ejecutar en cualquier procesador del sistema. 13 Gestión de hilos: Unix vs. Solaris 14 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-205-4462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 15 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Tema 3.3 Sistema Operativos (SSOO) Procesos e Hilos en C Grado en Ingeniería Informática Escuela Politécnica Superior Índice • Gestión de Hilos y Procesos Crear procesos con fork() Ejecutar procesos con exec 2 Procesos e Hilos: diferencias Si se quiere que una aplicación ejecute tareas en paralelo existen dos opciones: • Crear un nuevo proceso • Crear un nuevo hilo (thread) Procesos • Un proceso de Unix es cualquier programa en ejecución, el cual es totalmente independiente de otros procesos. • Un proceso no se puede meter en la zona de memoria de otro proceso. • En un proceso puede haber varios hilos de ejecución. • Un proceso es más costoso de lanzar, necesita crear una copia de todo su contenido en memoria. 3 Procesos e Hilos: diferencias Hilos • Dentro de un proceso todos los hilos comparten la misma memoria. • Si un hilo modifica una variable, los demás hilos del mismo proceso verán dicha modificación. • Lo anterior hace necesario el uso de semáforos o mutex (EXclusión MUTua en español) para evitar que dos hilos modifiquen a la vez a la misma estructura de datos. • Si un hilo “corrompe" una zona de memoria, los otros hilos del mismo proceso verán la memoria estropeada. • Un fallo en un hilo puede hacer fallar a todos los hilos del mismo proceso. 4 Procesos e Hilos: diferencias Importante • • • En los hilos, al compartir la memoria y los recursos, es necesario el uso de mutex o semáforos, haciendo compleja su programación. Cuando se lanza un proceso, este se hace independiente de quien lo lanzó, evitando así problemas de memoria. Si se necesita que haya comunicación entre procesos, será necesario pensar en el uso de memorias compartidas y sus semáforos, el uso de colas de mensaje, sockets o cualquier otro mecanismo de comunicación entre procesos en Unix. ¿Cuándo uso procesos y cuándo uso hilos? - Procesos: cuando hay poca comunicación entre ellos. Hilos: cuando es necesario compartir, cuando hay que actualizar datos o cuando se necesitan muchos cálculos en paralelo. 5 Procesos e Hilos: fork() • fork(), en el punto donde se llame, duplica los procesos y estos empiezan a ejecutarse por separado. – • • El retorno de dicha función es, al proceso original, un identificador del proceso nuevo. Al proceso nuevo le devuelve 0. – Cada proceso puede saber si es el original o el proceso padre o el proceso nuevo (proceso hijo), de esta forma cada uno puede hacer cosas distintas. Un fork() en un if, permite que el proceso padre siga por la parte del else y proceso hijo por el then. – – El proceso original podría seguir atendiendo nuevos clientes que quieran conectarse a nuestro programa por un socket. El proceso hijo podrá atender a un cliente que acaba de conectarse y que es el que ha provocado que lancemos el fork(). 6 Procesos e Hilos: fork() • • • • • Recuerde que fork duplica todo el espacio de memoria. Por ello, ambos procesos tienen todas las variables repetidas, pero distintas. Si el proceso padre modifica la variable “counter", el proceso hijo no verá reflejado el cambio en su versión de “counter". Si antes del fork(), por ejemplo, se tiene un fichero abierto (un fichero normal, un socket o cualquier otra cosa), después del fork() ambos procesos tendrán abierto el mismo fichero y ambos podrán escribir en él. Uno de los procesos puede cerrar el fichero mientras que el otro lo puede seguir teniendo abierto. fork() puede devolver -1 en caso de error. Si esto ocurre, no se ha creado ningún nuevo proceso. 7 Procesos e Hilos: fork() • • • • • El proceso padre puede "esperar" que el hijo termine. La función wait() permite “pausar” un proceso. wait() recibe como parámetro la dirección de un entero para que nos lo devuelva relleno. La función wait() deja dormido al proceso que la llama hasta que alguno de sus procesos hijo termina. En el entero se guardará la información de cómo ha terminado el hijo: llamando a exit(), recibe kill, está caido, otro…). 8 Procesos e Hilos: pthread_create • • WIFEXITED(estadoHijo) – – Es 0 si el hijo ha terminado de una manera anormal (caída, con un kill, etc). Distinto de 0 si ha terminado porque ha hecho una llamada a la función exit() WEXITSTATUS(estadoHijo) – Devuelve el valor que ha pasado el hijo a la función exit(), siempre y cuando la macro anterior indique que la salida ha sido por una llamada a exit(). 9 Procesos e Hilos: pthread_create Parámetros de pthread_create() : • pthread_t * puntero a un identificador de thread. La función devuelve este valor relleno con lo que luego posible hacer referencia al hilo. • pthread_attr_t * atributos de creación del hilo. Hay varios atributos posibles, como por ejemplo la prioridad. Un hilo de mayor prioridad se ejecutará con preferencia (tendrá más rodajas de tiempo) que otros hilos de menor prioridad. Si pasa NULL el hilo se creará con sus atributos por defecto. Si necesita un programa que cree y destruya hilos continuamente, evite el uso de NULL debido a que podría dejar memoria sin liberar al terminar un hilo. • void *(*)(void *) es el tipo de una función que admite un puntero void * y que devuelve void *. Eso quiere decir que a este parámetro le podemos pasar el nombre de una función que cumpla lo antes dicho. 10 Procesos e Hilos: pthread_create Parámetros de pthread_create() : • void *(*)(void *) esta función es la que se ejecutará como un hilo aparte. El hilo terminará cuando la función termine o cuando llame a la función pthread_exit(). Es común hacer que esta función cree un bucle infinito y quede suspendido en un semáforo o a la espera de una señal para hacer lo que tenga que hacer (luego volver a quedar dormido). • void * es el parámetro que se le pasará a la función anterior cuando se ejecute en el hilo aparte. El programa principal puede pasar un único parámetro a la función que se ejecutará en el hilo. La función del hilo sólo tendrá que hacer el "cast" adecuado. 11 Llamadas exec UNIX dispone de exec para lanzar a ejecución un programa, almacenado en forma de fichero. Sólo existe una llamada pero las bibliotecas estándares de C disponen de varias funciones, todas comenzando por 'exec' que se diferencian por el tipo de parámetros que se pasan al programa. • execl: es la forma simple y se usa cuando se conoce a priori el número de argumentos. – – int execl ( char* file, char* arg0, char* arg1, ... , 0 ); file: nombre del fichero seguido de todos los argumentos, al final un puntero nulo o con valor cero. – Ejemplo, ejecute la siguiente instrucción: /bin/ls -l /usr/include 12 Llamadas exec • Utilice: execl ( "/bin/ls", "ls", "-l", "/usr/include", 0 ); – • Sino conoce de ante mano el número de argumentos, se emplea la función execv: – • Argumentos: nombre del programa, comando, parámetros, contexto, puntero nulo. execv ( char* fichero, char* argv [] ); El parámetro argv es una lista que representa los argumentos del programa. El útlimo valor de la lista es un nulo o cero. Adaptamos el ejemplo anterior: – – char* agurments [] = { "ls", "-l", "/usr/include", 0 }; execv ( "/bin/ls", agurments ); 13 Llamadas exec • Hasta ahora se ha escrito el nombre completo del fichero o comando a ejecutar "/bin/ls" en vez de "ls". – • • • En este caso, tanto execl como execv no tienen en cuenta la variable PATH. – Para tener en cuenta esta variable, utilice las versiones execlp o execvp. – execvp ( "ls", arguments ); – El programa "/bin/ls“ se ejecutará si "/bin" está definida en el PATH. Retorno de exec: todas las llamadas exec retornan un valor diferente de NULL si el programa no se ha podido ejecutar. En caso de que sí se ejecute el programa, se transfiere el control a éste y la llamada exec nunca retorna. En cierta forma el programa que invoca un exec desaparece del mapa. 14 Sección crítica: sección de código dentro de un proceso que requiere acceso a recursos (critical section) compartidos y que no puede ser ejecutada mientras otro proceso esté en una sección de código correspondiente. Interbloqueo: situación en la cual dos o más procesos son incapaces de actuar porque (deadlock) cada uno está esperando que alguno de los otros haga algo. Círculo vicioso: situación en la cual dos o más procesos cambian continuamente su estado (livelock) en respuesta a cambios en los otros procesos, sin realizar ningún trabajo útil. exclusión mutua: requisito de que cuando un proceso esté en una sección crítica que accede a recursos compartidos, ningún otro proceso pueda estar en una sección crítica que acceda a ninguno de esos recursos compartidos. condición de carrera: situación en la cual múltiples hilos o procesos leen y escriben un dato (race condition) compartido y el resultado final depende de la coordinación relativa de sus ejecuciones. Inanición: situación en la cual un proceso preparado para avanzar es soslayado (starvation) indefinidamente por el planificador; aunque es capaz de avanzar, nunca se le escoge. 15 Bibliografía • • • CARRETERO, Jesús, GARCÍA, Félix, DE MIGUEL, Pedro, PÉREZ, Fernando. Sistemas Operativos: una visión aplicada. McGraw-Hill, 2001. STALLINGS, William. Sistemas operativos: aspectos internos y principios de diseño. 5ª Edición. Editorial Pearson Educación. 2005. ISBN: 978-84-205-4462-5. TANENBAUM, Andrew S. Sistemas operativos modernos. 3ª Edición. Editorial Prentice Hall. 2009. ISBN: 978-607- 442-046-3. 16 marlon.cardenas@ufv.es Grado en Ingeniería Informática Escuela Politécnica Superior Sistemas Operativos II TEMA 4.1 Sincronización y comunicación 4.1.1 PROBLEMAS DE SINCRONIZACIÓN Y COMUNICACIÓN ENTRE PROCESOS Sincronización y Comunicación Concurrencia: ejecución asíncrona de varios procesos con acceso a los mismos recursos. La concurrencia de procesos puede representarse en tres contextos diferentes: 1. Varias aplicaciones ejecutándose a la vez sobre el mismo procesador. 2. Aplicaciones implementadas como conjuntos de procesos concurrentes. 3. Estructuración de los SSOO como conjunto de procesos concurrentes. En un sistema donde está permitida la ejecución concurrente de procesos se debe garantizar la existencia de: ● Mecanismos de acceso exclusivo a los recursos compartidos. ● Mecanismos de sincronización y comunicación que permitan establecer un orden de ejecución en los procesos. Sincronización y Comunicación Ejemplo: E/S por teclado y pantalla. static char sal, ent; (1) void echo() { extern char sal,ent; getc(ent); sal := ent; puts(sal); } // echo void main () { ... echo(); ... } // main P1 y P2 ejecutan a la vez este código 1. P1 ejecuta main, llega a la llamada a echo y ejecuta hasta (1) cargando x en ent. 2. P2 ejecuta todo el código hasta el final, cargando y, y mostrandola por pantalla. 3. P1 termina su ejecución, muestra y. Sincronización y Comunicación Ejemplo: (continúa) Para solucionar la ejecución errónea se puede plantear el siguiente requisito: ● echo() es una función global pero sólo lo puede utilizar un proceso a la vez. La secuencia de ejecución sería la siguiente: ● P1 llama a echo() y es interrumpido justo después de llamar a la función de entrada, en (1). ● P2 llama a echo() pero no puede utilizarlo porque está bloqueado (está siendo usado por otro proceso), por lo que se detiene P2 hasta que pueda acceder a echo(). ● P1 retoma la ejecución y completa echo(). ● P2 puede ahora ejecutar echo() sin cometer ningún error. Conclusión: los recursos globales deben estar protegidos para evitar errores. En sistemas multiprocesador el problema es similar: varios procesos ejecutando a la vez pueden realizar accesos simultáneos a recursos. Sincronización y Comunicación Funciones de Gestión del SO relacionadas con Concurrencia: ● Seguir la pista de los procesos activos: control de PCBs. ● Asignar y retirar recursos a los procesos en función de: ● ● ● Tiempo de procesador (planificación) ● Memoria consumida (gestión de memoria virtual) ● Utilización de archivos ● Utilización de recursos de E/S Protección de datos y recursos asignados a cada proceso. Los resultados de un proceso deben ser independientes de su velocidad de ejecución. No se deben ver afectados por interrupciones en la propia ejecución de un proceso. 4.1.2 EXCLUSIÓN MUTUA. SOPORTES. Exclusión Mutua Requisitos para la exclusión mutua: ● ● ● ● Debe cumplirse la exclusión mutua, es decir, debe permitirse a los procesos acaparar el uso de recursos críticos con exclusividad. Dos procesos no pueden estar simultáneamente en sus secciones críticas. No se pueden hacer suposiciones acerca de la velocidad de ejecución de los procesos o cantidad de ellos en ejecución. Cuando ningún proceso está en la sección crítica, cualquier proceso que lo solicite debe poder entrar en ella. ● Ningún proceso esperará indefinidamente para entrar en sección crítica. ● Los procesos solo pueden estar en la sección crítica durante un periodo finito de tiempo. ● Ningún proceso que se ejecute fuera de su región crítica puede bloquear a otros procesos. Estos requisitos pueden ser implementados bien por SW, bien por HW. Soporte SW para Exclusión Mutua Todas las soluciones SW suponen la existencia de unas primitivas HW para la exclusión mutua en el acceso a memoria. Primer intento: solución por turnos. ● Protocolo del Iglú: “vivienda unipersonal con una pizarra dentro, por cuya puerta solo cabe una persona”. ● Los procesos del sistema se asemejan a los esquimales de este protocolo. ● En la pizarra estará escrito el proceso cuyo turno está activo. ● ● Si un proceso “entra” y “ve” su turno → ejecuta su sección crítica y después cambia el turno. Si un proceso “entra” y NO está su turno → se sale y espera, luego vuelve a entrar para comprobar si ya es su turno. Soporte SW para Exclusión Mutua Primer intento: solución por turnos. La implementación, considerando a turno:0..1 variable compartida sería: Garantiza exclusión mutua. Inconvenientes: ● Los procesos deben alternar estrictamente sus secciones críticas. ● Si uno de los procesos falla, el otro puede quedarse esperando indefinidamente para entrar en la sección crítica. ● Problema de la solución: sólo considera el estado de uno de los procesos a la hora de entrar en la sección crítica. Debería considerar el de los dos. Soporte SW para Exclusión Mutua Segundo intento: variables cerrojo. ● ● Cada esquimal tiene su propio iglú en el que puede leer y escribir, pero en el iglú del prójimo sólo puede leer. A la hora de entrar en la sección crítica, el proceso “mira” la pizarra del otro para ver si está a FALSE. Si es así, ● Escribe en su pizarra TRUE para que el otro sepa que está en su sección crítica. ● Ejecuta su sección crítica. ● Escribe FALSE en su pizarra. Implementación considerando int senial[2] las “pizarras” compartidas: Soporte SW para Exclusión Mutua Segundo intento: variables cerrojo. Esta solución garantiza: ● Que cada proceso puede entrar en su sección crítica todas las veces que lo desee, independientemente de lo que el otro haga. ● Si uno de ambos procesos falla fuera de su sección crítica, el otro todavía puede seguir ejecutándose. Inconvenientes: No garantiza totalmente la exclusión mutua. Ejemplo: ● P0 ejecuta la sentencia while y encuentra senial[1] == 0. ● P1 ejecuta la sentencia while y encuentra senial[0] == 0. ● P0 pone senial[0] = 1 y entra en su sección crítica. ● P1 pone senial[1] = 1 y entra en su sección crítica. ¡ Los dos procesos están a la vez en sus secciones críticas ! La solución no es independiente de la velocidad relativa de ejecución de los procesos. Soporte SW para Exclusión Mutua Tercer intento: El problema de la propuesta anterior radica en que los procesos pueden cambiar su estado después de que el otro proceso lo haya comprobado. Solución: Esta solución garantiza: ● Exclusión mutua. ● ● Cada proceso puede entrar en su sección crítica todas las veces que lo desee, independientemente de lo que el otro haga. Si uno de los procesos falla fuera de su sección crítica, el otro todavía puede seguir ejecutándose. Soporte SW para Exclusión Mutua Tercer intento: Inconvenientes: ● Se puede dar interbloqueo. Por ejemplo, en la siguiente situación: ● P0 pone senial[0] = 1 ● P1 pone senial[1] = 1 ● Ninguno de los dos puede entrar en su sección crítica y como consecuencia, ambos esperarán indefinidamente a que el otro cambie el valor de las variables cerrojo. Los procesos cambian su estado antes de conocer el estado del otro. Sin embargo, el problema de este intento es que cada proceso fija su estado sin tener en cuenta el estado del otro proceso. Solución: “lecciones de educación” Soporte SW para Exclusión Mutua Cuarto intento: Los procesos, tras recibir “lecciones de educación” actúan así: 1.Activan su señal. 2.Se preparan para desactivar su señal y “ceder el paso” al otro proceso. ● ● Garantiza exclusión mutua. Gran retraso en llegar a la solución, sin llegar al interbloqueo. Soporte SW para Exclusión Mutua Cuarto intento: Ejemplo de secuencia de ejecución: 1. P0: senial[0] = 1 2. P1: senial[1] = 1 3.P0 comprueba senial[1], que es 1, y por tanto entra en el bucle. 4.P1 comprueba senial[0], que es 1, y por tanto entra en el bucle. 5.P0: senial[0] 6.P1: senial[1] 7.P0: senial[0] 8. P1: senial[1] = = = = 0 0 1 1 (primera instrucción del bucle de espera) (primera instrucción del bucle de espera) (última instrucción del bucle de espera) (última instrucción del bucle de espera) 9. Vuelta al paso 3 ● Retraso en llegar a la solución hasta que alguno de los procesos realice el cambio a 0 de su señal antes de que el otro compruebe su valor. Soporte SW para Exclusión Mutua Algoritmo de Dekker: ● ● Diseñado por Dijkstra en 1965 para solucionar el problema de acceso en exclusión mutua planteado por el matemático holandés Dekker. Suma a la observación del estado de los procesos la inclusión de un turno. Soporte SW para Exclusión Mutua Algoritmo de Dekker: Esta solución garantiza: ● Exclusión mutua. ● ● ● Cada proceso puede entrar en su sección crítica todas las veces que lo desee, mientras que el otro no muestre intención de entrar en su sección crítica (a través de senial). Si uno de los procesos falla fuera de su sección crítica, el otro todavía puede seguir ejecutándose porque el que falló puso su senial a 0 justo al salir de la sección crítica. No existe interbloqueo gracias a la variable compartida turno. Inconvenientes: ● Demasiado complejo para demostrar su corrección en cualquier caso. ● Difícilmente extensible a n procesos. Soporte SW para Exclusión Mutua Algoritmo de Peterson: Simplificación del algoritmo de Dekker. Utiliza las variables de estado y turno. Estudio de casos: supongamos P0 bloqueado en while. P0 sólo puede entrar cuando una de las dos condiciones deje de cumplirse: ● ● ● P1 no está interesado en entrar en su SC: imposible porque senial[1] == 1. P1 está esperando a entrar en su SC: imposible porque si turno == 1, P1 puede entrar en su SC. P1 monopoliza SC: no puede ocurrir porque P1 pone turno = 0 antes de la SC. El algoritmo de Peterson es fácilmente generalizable para n procesos Soporte HW para Exclusión Mutua Inhabilitar Interrupciones: ● ● El SO, a través de las interrupciones, toma el control y cambia el proceso en ejecución. Se puede resolver la exclusión mutua haciendo que un proceso que vaya a ejecutar su sección crítica deshabilite las interrupciones para que nada le detenga, restaurándolas una vez que terminó su sección crítica. Implementación: repeat <inhabilitar interrupciones> <sección crítica> <habilitar interrupciones> ... forever ● ● Ventaja: garantiza exclusión mutua. Inconvenientes: pérdida de rendimiento (disminuye el grado de multiprogramación), no soluciona el problema en sistemas multiprocesador. Soporte HW para Exclusión Mutua Instrucciones Máquina Especiales: ● ● ● ● ● ● ● ● Problemas de soluciones SW: Necesario utilizar dos instrucciones para leer y escribir . Necesario utilizar dos instrucciones para leer e intercambiar valores en las variables cerrojo. Todas las soluciones SW suponen la existencia de unas primitivas HW para la exclusión mutua en el acceso a memoria. Solución: proponer instrucciones máquina atómicas para estas operaciones. Estas instrucciones se ejecutan “en un ciclo de reloj”. Implementadas en ensamblador como atómicas. En este curso estudiaremos Test and Set e Intercambiar Soporte HW para Exclusión Mutua Test and Set: Definición: int TestAndSet (int *i) { if (*i == 0) { *i = 1; return (1); } else { return (0); } } // TestAndSet Si el valor de la variable compartida es 0, la pone a 1 para indicar que se entra en sección crítica y devuelve 1 (TRUE). Si el valor de la variable compartida es 1 significa que alguien está en sección crítica, así que TS devuelve 0 (FALSE). Solución al problema de exclusión mutua con Test and Set : Soporte HW para Exclusión Mutua Intercambiar: Definición: void Intercambiar (int *r, int *m) { int temp; temp = *m; *m = *r; *r = temp; } // Intercambiar Solución al problema de ex. mutua: Inicialmente cerrojo = 0. El único proceso que puede ejecutar la sección crítica es aquel que encuentre cerrojo a 0. Idealmente: intercambio de valores entre un registro (r) y una posición de memoria (m). Implementación en “un ciclo”. Soporte HW para Exclusión Mutua Ventajas de las soluciones HW: ● ● ● Se pueden aplicar a cualquier número de procesos en sistemas con memoria compartida, sean mono o multiprocesador. Simples y fáciles de verificar. Se pueden usar para definir varias secciones críticas. Desventajas de las soluciones HW: ● ● ● Se emplea espera activa, consumiendo tiempo de procesador. Puede producirse inanición, porque la selección del proceso a entrar en ejecución es arbitraria. Puede producirse interbloqueo. Ejemplo: sistema basado en prioridades. ● ● ● P0 entra en la sección crítica y pone cerrojo = 1 P1, con mayor prioridad que P0, le interrumpe e intenta entrar en la SC. P1 se mantiene en espera activa debido a que P0 jamás podrá interrumpirle (tiene menos prioridad) y desbloquear la variable cerrojo. 4.1.3 SEMÁFOROS. Semáforos ● ● ● ● ● ● ● Herramienta SW que permite resolver el problema de la sincronización entre procesos evitando la espera activa. Inventados por Dijkstra. Ideas desarrolladas: Dos o más procesos cooperan y se sincronizan por medio de señales. Posibilidad de forzar a un proceso a detenerse en una posición concreta hasta que reciba una determinada señal. Un semáforo S contendrá una variable entera a la que, una vez asignado un valor inicial, sólo podrá accederse a través de operaciones atómicas (primitivas) estándar: wait y signal. wait(s): permite detener un proceso hasta la llegada de una señal. Decrementa el valor del semáforo. Si s < 0 el proceso que invoca wait se bloquea. signal(s): envía una señal al semáforo. Incrementa el valor del semáforo. Si s <= 0 tras ese incremento, significa que habrá algún proceso bloqueado, de modo que se desbloqueará al primer proceso bloqueado. Semáforos Definición formal de las primitivas de los semáforos: • ● Implementación: struct semaforo { int contador; struct cola *buffer_proc; } ● Inicialización: struct semaforo semaf; semaf.contador = 1; // Un wait antes de bloqueo Un semáforo puede inicializarse a un valor no negativo Primitiva wait: void wait(semaf) { semaf.contador--; if (semaf.contador < 0) { semaf.cola.input(proc); // Coloca en la cola de procesos al que invocó wait. bloquear(); // El proceso que invocó wait es bloqueado. } } Semáforos Definición formal de las primitivas de los semáforos (sigue): Primitiva signal: void signal(semaf) { semaf.contador++; if (semaf.contador <= 0) { // Algún proceso bloqueado proc = semaf.cola.primero(); // Se saca al primero desbloquear(proc); } } Más características: ● ● ● ● Los procesos en espera se gestionan mediante una FIFO: equitatividad. Los procesos no pueden permanecer indefinidamente en la cola del semáforo. Semáforo binario (ó mutex) es aquel cuyo contador solo toma los valores 0 y 1. Los semáforos binarios son equipotentes a los generales. Proporcionan una solución al problema de exclusión mutua para n procesos. Semáforos y exclusion mutua void main() { semaforo semaf; Solución para dos procesos // Inicialización semaf.contador = 1; entero = 0; // Segmento de memoria compartida (variable) pid_t pid = fork(); // Creación de proceso hijo switch(pid) { case –1: printf(“Error, no funcionó fork”); break; case 0: P(); break; // Código del hijo. default: P(); break; // Código del padre. } // switch } // main void P() { while(1) { wait(semaf); entero++; printf(“%i”, entero); signal(semaf); } // while } // P //// Zona de exclusión mutua //// //// Zona de exclusión mutua //// Implementación de Semáforos ● ● ● Las primitivas wait y signal deben implementarse como operaciones atómicas. Posibilidades: Soluciones SW: Algoritmo de Dekker, Algoritmo de Peterson Soluciones HW: Inhabilitación de interrupciones (preferida), Instrucciones especiales: Test and Set, Intercambiar Soporte en lenguajes de programación: ● ● ● ● C: librerías sem.h, ipc.h C++: varias implementaciones de clases para sincronizar hebras Dependientes del SO. Independientes del SO: ZThreads http://zthread.sourceforge.net/html/classZThread_1_1Semaphore.html ● JAVA: clase Semaphore (Java 2, SE 5.0) http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Semaphore.html Productor / Consumidor - Semáforos Enunciado: ● Uno o más procesos productores generan datos de un cierto tipo y los sitúan en un buffer. ● Uno o varios consumidores sacan los elementos del buffer de uno en uno. ● Supóngase un buffer ilimitado: sal ent Buffer Ilimitado Situaciones “delicadas”: ● Dos productores tratan de acceder al buffer a la vez. ● Dos consumidores tratan de acceder al buffer a la vez. ● Un consumidor accede a la vez que un productor... Productor / Consumidor - Semáforos Solución 0: sin sincronización // Compartidas int buffer[INF]; int ent = 0; int sal = 0; // Productor int v; while (1) { v = Produce(); buffer[ent] = v; ent = ent + 1; } sal ent // Consumidor int w; while (1) { while (ent <= sal) { /* nada */ }; w = buffer[sal]; sal = sal + 1; consume(w); } Las coincidencias en acceso no están resueltas buffer Espera Activa Productor / Consumidor - Semáforos Solución 1: semáforos binarios ● Se gestiona el total de elementos en una variable n para llevar la cuenta del número de elementos que hay en el buffer: n = ent - sal ● ● ● Se utiliza el semáforo binario exmut para hacer cumplir la exclusión mutua sobre n. Se utiliza el semáforo binario retraso para que el consumidor espere la llegada de elementos al buffer (esperará si el buffer está vacío). Suponemos que al menos un productor se ejecutará antes que todos los consumidores. Sin esta suposición, un consumidor podría extraer elementos de un buffer vacío. Productor / Consumidor - Semáforos Solución 1: semáforos binarios #define numProd 10; #define numCons 10; // 10 productores // 10 consumidores // Variables compartidas int n = 0; semaforo exmut; semaforo retraso; // Elementos del buffer // Ex. mutua // Evita consumir si buffer vacío void productor() { int elemento; while(1) { elemento = producir(); //-- Inicio de Sección Crítica. waitB(exmut); aniadir(elemento); // Añade elemento al buffer. n += 1; if (n == 1) // El único elemento lo acabamos de signalB(retraso); // añadir, despierta 1er. bloqueado signalB(exmut); //----- Fin de Sección Crítica. } } Productor / Consumidor - Semáforos Solución 1: semáforos binarios void consumidor() { int elemento; while(1) { //----- Inicio de Sección Crítica. waitB(exmut); // Saca elemento del buffer. elemento = extraer(); n -= 1; //----- Fin de Sección Crítica. signalB(exmut); consumir(elemento); // Si se consume último elemento if (n == 0) // hay que notificar al semáforo. waitB(retraso); } } void main() { exmut.contador = 1; retraso.contador = 0; for (int i = 1; i <= numProd; i++) crearProductor(); for (int j = 1; j <= numCons; j++) crearConsumidor(); } Productor / Consumidor - Semáforos Solución 1: semáforos binarios Problemas. Supóngase la siguiente secuencia de ejecución: (*) Consumidor1 se queda tras la instrucción “if (n==0)”, sin ejecutar la siguiente. Como no está en sección crítica en ese momento, otro proceso puede ejecutar código de su sección crítica. Productor / Consumidor - Semáforos Solución 2: semáforos generales El semáforo entero n llevará la cuenta de los elementos del buffer. El semáforo binario exmut servirá para acceder en exclusión mutua al buffer. // Variables compartidas: semaforo n; semaforo exmut; n.contador = 0; exmut.contador = 1; void productor() { int elemento; while(1) { elemento = producir(); waitB(exmut); aniadir(elemento); signalB(exmut); signal(n); } } Solución correcta void consumidor() { int elemento; while(1) { wait(n); waitB(exmut); elemento = extraer(); signalB(exmut); consumir(elemento); } } Problema de la Barbería - Semáforos Enunciado (Libro Stallings): La barbería tiene 3 sillas de peluquería, 3 barberos, una zona de espera donde se pueden acomodar 4 clientes en un sofá, y una sala de espera en la que se puede alojar al resto de clientes de pie. Las medidas de seguridad limitan a 20 el número de clientes que puede haber en el establecimiento. En el ejemplo, procesaremos 50 clientes. Restricciones: ● Los clientes no entran a la tienda si ésta está al completo (20 clientes). ● Si el sofá está completo, se espera de pie. ● ● Cuando el barbero está libre, atiende al cliente que más tiempo lleva en el sofá, y el que lleve más tiempo de pie, se sienta en el sofá. Cuando finaliza un corte de pelo, el barbero cobra (sólo se puede cobrar uno a la vez porque sólo hay una caja registradora); los barberos reparten el tiempo entre CORTAR_PELO, COBRAR, DORMIR en su silla a la espera de clientes. Problema de la Barbería - Semáforos Solución NO equitativa: Se soluciona el problema mediante los siguientes semáforos: Problema de la Barbería - Semáforos Solución NO equitativa: // Inicialización: semaforo max_capacidad; semaforo sofa; semaforo silla_barbero; semaforo coord; semaforo cliente_listo; semaforo terminado; semaforo dejar_silla; semaforo pago; semaforo recibo; max_capacidad.contador = 20; sofa.contador = 4; silla_barbero.contador = 3; coord.contador = 3; cliente_listo.contador = 0; terminado.contador = 0; dejar_silla.contador = 0; pago.contador = 0; recibo.contador = 0; // Programa principal: void main() { int i; for (i = 1, i <= MAX_CLIENTES, i++) insertar_cliente(); for (i = 1, i <= NUM_BARBEROS, i++) insertar_barbero(); insertar_cajero(); } Problema de la Barbería - Semáforos Solución NO equitativa: void cliente() { wait(max_capacidad); entrar_en_tienda(); wait(sofa); sentarse_en_sofa(); wait(silla_barbero); levantarse_del_sofa(); signal(sofa); sentarse_en_silla_barbero(); signal(cliente_listo); wait(terminado); levantarse_de_silla(); signal(dejar_silla); pagar(); signal(pago); wait(recibo); salir_tienda(); signal(max_capacidad); } void barbero() { while(1) { wait(cliente_listo); wait(coord); cortar_pelo(); signal(coord); signal(terminado); wait(dejar_silla); signal(silla_barbero); } } void cajero() { while(1) { wait(pago); wait(coord); aceptar_pago(); signal(coord); signal(recibo); } } Problema de la Barbería - Semáforos Solución NO equitativa: Esta solución no es equitativa porque puede ocurrir la siguiente situación: ● ● ● Tres clientes están esperando a que se les corte el pelo => los tres estarán bloqueados en la cola del semáforo terminado en orden de llegada. Cuando a un cliente se le termina de cortar el pelo => el barbero hace signal(terminado). Si suponemos que el último que llegó es el primero al que se termina de cortar el pelo (barbero rápido o alopecia galopante), al ejecutar el barbero signal(terminado), se sacará de la cola al primero que entró, ¡¡ aunque no se le haya terminado de cortar el pelo !!. Mientras que el que terminó deberá esperar a que los otros dos clientes sean sacados de la cola. Problema de la Barbería - Semáforos Solución Equitativa: ● Se asigna un número único a cada cliente en su llegada: ● Variable compartida contador, cuyo acceso está protegido por el semáforo binario exmut1. ● ● ● ● terminado es un vector de semáforos, uno para cada cliente. Cliente ejecuta wait(terminado[numCliente]) cuando se sienta para ser atendido -> espera en su propio semáforo. Barbero ejecuta signal(terminado[numCliente]) para liberar al cliente apropiado cuando termina de atenderle. Para que los barberos conozcan el número del cliente que van a atender, cada cliente inserta su número en la cola cola1 justo antes de avisar al barbero a través del semáforo cliente_listo. Cuando el barbero puede cortar el pelo, saca el número más bajo de la cola (el primero que entró) y lo coloca en su variable local cliente_b. Problema de la Barbería - Semáforos Solución Equitativa: // Inicialización: semaforo max_capacidad; max_capacidad.contador = 20; semaforo sofa; sofa.contador = 4; semaforo silla_barbero; silla_barbero.contador = 3; semaforo coord; coord.contador = 3; exmut1.contador = 1; semaforo exmut1; exmut2.contador = 1; semaforo exmut2; cliente_listo.contador = 0; semaforo cliente_listo; dejar_silla.contador = 0; semaforo dejar_silla; pago.contador = 0; semaforo pago; recibo.contador = 0; semaforo recibo; semaforo terminado[MAX_CLIENTES]; for (int k = 0; k < MAX_CLIENTES; k++) terminado[k].contador = 0; int contador = 0; // Programa principal: void main() { for (int i = 1, i <= MAX_CLIENTES, i++) insertar_cliente(); for (int j = 1, j <= NUM_BARBEROS, j++) insertar_barbero(); insertar_cajero(); } Problema de la Barbería - Semáforos Solución Equitativa: void barbero() { int cliente_b; while(1) { wait(cliente_listo); wait(exmut2); sacar_cola(cliente_b); signal(exmut2); wait(coord); cortar_pelo(); signal(coord); signal(terminado[cliente_b]); wait(dejar_silla); signal(silla_barbero); } } void cajero() { while(1) { wait(pago); wait(coord); aceptar_pago(); signal(coord); signal(recibo); } } void cliente() { int numCliente; wait(max_capacidad); entrar_en_tienda(); wait(exmut1); contador++; numCliente = contador; signal(exmut1); wait(sofa); sentarse_en_sofa(); wait(silla_barbero); levantarse_del_sofa(); signal(sofa); wait(exmut2); poner_cola1(numCliente); signal(exmut2); signal(cliente_listo); sentarse_en_silla_barbero(); wait(terminado[numCliente]); levantarse_de_silla(); signal(dejar_silla); pagar(); signal(pago); wait(recibo); salir_tienda(); signal(max_capacidad); } 4.1.4. REGIONES CRÍTICAS. Regiones Críticas “Problemas” de los semáforos: ● ● ● Alta probabilidad de equivocación por parte del programador. Los compiladores no ayudan al programador en su uso eficiente. Un uso incorrecto de los semáforos puede dar lugar a errores de temporización difíciles de detectar (falta semántica que ayude) El concepto de región crítica (RC) fue introducido por Hansen en 1972: ● Una RC es un “constructor” que resuelve el problema de exclusión mutua estableciendo un mecanismo de acceso a los recursos compartidos. Regiones Críticas Características de las RC: ● ● ● ● ● El compilador implementa automáticamente los mecanismos necesarios para sincronizar el acceso a cada RC. Cada recurso compartido debe ser definido como shared. Existirá una RC para cada recurso compartido. No está permitido el acceso al recurso compartido fuera de la RC. Cada RC tiene asociada una cola para aquellos procesos que esperan a que la RC sea liberada. Declaración de recurso compartido (sintaxis tipo “Pascal Concurrente”) var v: shared T; (* Variable compartida v de tipo T *) Constructor: region v do begin <sección crítica> end; Regiones Críticas Problema de las RC: ● La sincronización entre procesos que aguardan por una condición puede necesitar espera activa. Ejemplo: ... repeat region v do begin ok := (v > 0); if ok then v := v - 1; end; until ok; ... ● (* Hay espera activa en repeat *) (* Solo un proc. ejecuta la RC *) Solución: incluir una condición de “guarda” para cada RC. Son las regiones críticas condicionales (RCC). Regiones Críticas Condicionales Características de las RCC: ● ● ● La idea es similar a las RC, con la diferencia de que se añade una condición de guarda en la región crítica. La evaluación de la condición se considera parte de la región crítica. Un proceso ejecuta el código limitado por la RCC sólo si la condición es cierta. Sintaxis: region v when cond do begin <sección crítica> end; Hansen propuso la siguiente implementación con dos colas Productor / Consumidor - RCCs (* Productor / Consumidor BUFFER LIMITADO *) PROGRAM ProdCons; CONST MAX=50; OJO: el registro protegido TYPE se compone de buffer + TBuffer = RECORD índices sigent, sigsal, cont: INTEGER; elems: ARRAY [1..MAX] OF INTEGER; END; VAR buffer : SHARED TBuffer; PROCESS Productor; VAR pdato: INTEGER; BEGIN ... pdato := producir(); REGION buffer WHEN buffer.cont<MAX DO BEGIN buffer.elems[buffer.sigent] := pdato; buffer.sigent := (buffer.sigent MOD MAX) + 1; buffer.cont := buffer.cont + 1; END; ... END; Productor / Consumidor - RCCs PROCESS Consumidor; VAR cdato: INTEGER; BEGIN ... REGION buffer WHEN buffer.cont<>0 DO BEGIN cdato := buffer.elems[buffer.sigsal]; buffer.sigsal := (buffer.sigsal MOD MAX) + 1; buffer.cont := buffer.cont - 1; END; ... END; BEGIN (* Principal *) (* Inicialización del buffer *) REGION buffer WHEN true DO BEGIN buffer.sigent:=1; buffer.sigsal:=1; buffer.cont := 0; END; COBEGIN Productores; Consumidores; (* Generaría varios de cada uno *) COEND; END. 4.1.5. MONITORES. Monitores Estructuras con funcionalidad equivalente a la de los semáforos: ● Resuelven el acceso en exclusión mutua a recursos compartidos. ● Permiten sincronización entre procesos evitando espera activa. ● Más sencillos de programar que los semáforos. ● Las operaciones que contienen proporcionan semántica. ● Se han usado en diversos lenguajes de programación: PASCAL FC ● Modula-2 ● JAVA (synchronized) http://www.artima.com/insidejvm/ed2/threadsynchP.html ● Dos tipos de monitores: ● Monitores con señales (Hoare). ● Monitores con notificación y difusión (Lampson y Redell). Monitores con Señales Propuestos por primera vez por Hoare en 1974 • • Biografía de Tony Hoare: http://es.wikipedia.org/wiki/C._A._R._Hoare Inventor del algoritmo Quicksort, profesor emérito en Oxford, actualmente vinculado a Microsoft http://research.microsoft.com/users/thoare/ Un monitor con señales es un módulo SW que consta de uno o más procedimientos, una secuencia de inicialización y unos datos locales. Características básicas: ● ● ● Las variables locales sólo pueden ser accedidas por los procedimientos del monitor. Los procesos “entran” en el monitor invocando a uno de los procedimientos contenidos en él. Sólo un proceso puede ejecutar código del monitor en cada instante, otros procesos que hayan invocado al monitor quedarán suspendidos. Monitores con Señales Exclusión Mutua: ● El acceso a una estructura de datos (o recurso) compartida puede protegerse declarándola dentro de un monitor y programando accedentes como procedimientos del monitor. Sincronización: ● Un monitor proporciona sincronización a través de variables de condición que se colocan dentro del monitor. Las operaciones que permiten trabajar con esas variables son: cwait(c): suspende la ejecución del proceso que llama bajo la variable de condición c y lo coloca en una cola de procesos vinculada esa condición. El monitor pasa a estar disponible. csignal(c): reanuda la ejecución de algún proceso suspendido después de un cwait bajo la misma condición. Si hay varios procesos, elige uno de ellos; si no hay ninguno, no hace nada. Monitores con Señales Cola de entrada al monitor Estructura de monitor: Zona de Espera MONITOR Cond c1 Datos Locales cwait(c1) ... Cond cn Variables Condición Procedimiento 1 ... cwait(cn) Salida Procedimiento k Urgentes csignal Código de Inicialización Los procesos van a “Urgentes” si no invocan csignal como última instrucción del procedimiento. Prod. / Cons. - Monitores Señales Productor / Consumidor Buffer Limitado. Monitor buffer_acotado; // Inicio del bloque monitor. int buffer[1..N]; // Vars. del monitor (buffer limitado) int sigent, sigsal; int contador; int tomar() { condition no_lleno, no_vacio; int y; if (contador == 0) void aniadir(int x) { cwait(no_vacio); if (contador == N) y = buffer[sigsal]; cwait(no_lleno); sigsal = (sigsal + 1) % N; buffer[sigent] = x; contador--; sigent = (sigent + 1) % N; csignal(no_lleno); contador++; return y; csignal(no_vacio); } } { sigsal = 0; /* Código de inicialización del monitor. */ sigent = 0; contador = 0; } // Fin del monitor Monitores con Notificación y Difusión Propuestos por Lampson y Redell en 1980 para el lenguaje Mesa. Inconvenientes de la solución de Hoare: ● ● ● Si hay al menos un proceso en una cola de condición, el proceso que ejecuta csignal sobre esa cola debe salir inmediatamente del monitor o suspenderse en él (cola de urgentes): Si el proceso que ejecuta csignal no terminó de ejecutar instrucciones del monitor, se necesitan dos cambios de contexto. La planificación debe ser estricta porque la condición podría cambiar. Solución de Lampson y Redell: ● ● Se sustituye el csignal por cnotify, con la siguiente interpretación: cnotify(c): cuando un proceso ejecuta cnotify(c), se notifica al primer proceso de la cola c que se reanudará en breve, pero como no le asegura la reanudación inmediata, éste habrá de comprobar de nuevo la condición antes de poder seguir ejecutándose. Monitores con Notificación y Difusión Productor / Consumidor con notificación y difusión: void aniadir(int x) { } while (contador == N) cwait(no_lleno); buffer[sigent] = x; sigent = (sigent + 1) % N; contador++; cnotify(no_vacio); int tomar() { int y; while (contador == 0) cwait(no_vacio); y = buffer[sigsal]; sigsal = (sigsal + 1) % N; contador--; cnotify(no_lleno); return y; } ● ● Se sustituyen los if por while para que los procesos vuelvan a comprobar las condiciones (cnotify no garantiza que al retomar la ejecución la condición se cumpla). En la mayoría de los casos, cnotify evita los dos cambios de contexto. Monitores con Notificación y Difusión Mejoras en monitores con notificación y difusión: ● Asociar un temporizador a las colas de condición que limite el tiempo de bloqueo. ● Evita la inanición si un proceso falla antes de enviar la señal. ● Primitiva extra para monitores con notificación y difusión: cbroadcasting(c): ocasiona que todos los procesos en espera de que se cumpla una condición, pasen a estar en la cola de listos. Ventaja fundamental de los monitores con notificación y difusión: ● Es más complicado que los errores de programación afecten al sistema porque, aún mandando una señal equívoca, los procesos deben comprobar la condición al volver a ejecutar. 4.1.6 PASO DE MENSAJES. Paso de Mensajes El mecanismo de paso de mensajes permite: ● Sincronizar procesos (exclusión mutua). ● Intercambiar información entre los procesos que lo necesiten. Método fácilmente implementable en monoprocesador de memoria compartida. sistemas distribuidos, multiprocesador y Hay diversas implementaciones del mecanismo de paso de mensajes, aunque habitualmente se ofrece su soporte a través de dos primitivas: ● ● send(destino, mensaje) ● receive(origen, &mensaje) Éste es el conjunto mínimo de operaciones para que dos procesos puedan dedicarse al paso de mensajes. destino y origen son identificadores de los procesos destinatario y fuente del mensaje. Paso de Mensajes Características de la implementación del paso de mensajes: Sincronización: un proceso receptor no puede obtener un mensaje hasta que no sea enviado por otro proceso. ● ● ● ● ● ● ● ● ● Se debe especificar qué ocurre después de que un proceso ejecute send ó receive. Posibilidades: detenerse (bloquearse) o no. Envío bloqueante, recepción bloqueante (rendezvous). Fuerte sincronización entre procesos. Envío no bloqueante, recepción bloqueante. Útil en programación, evitando emisores “desbocados”. Envío no bloqueante, recepción no bloqueante. Nadie debe esperar. “Peligroso” en programación. Envío bloqueante, recepción no bloqueante. Paso de Mensajes ● ● ● ● ● ● ● ● ● Direccionamiento: especificación de emisor y receptor de los mensajes. Tipos de direccionamiento: Direccionamiento directo: send: incluye la identificación del proceso destino del mensaje. receive: hay dos maneras de gestionarlo. Designación explícita del emisor. Éste no siempre es conocido de antemano Muy recomendable para cooperación entre procesos. Designación implícita: el parámetro origen tomará un valor de retorno cuando ya se haya completado la operación. Direccionamiento indirecto (buzones). Ventajas: ● Se desacopla la relación emisor – receptor. Relaciones diversas: ● Uno a uno: impide errores y da privacidad a la comunicación. ● Uno a muchos: difusión ● Muchos a uno: cliente/servidor, el buzón pasa a ser un puerto. Paso de Mensajes Direccionamiento indirecto (buzones), continúa: La asociación de buzones a procesos puede ser: ● ● ● Estática: los puertos suelen estar asignados estáticamente. Un puerto se crea y se asigna a un proceso definitivamente. Dinámica: cuando hay varios emisores, la asociación de un emisor a un buzón puede realizarse dinámicamente. Necesarias primitivas de conexión y desconexión del buzón. Propietario de un buzón: ● Un puerto normalmente pertenece y es creado por el receptor. ● Un buzón es propiedad del proceso que lo crea (sea emisor o receptor). ● Cuando un proceso se destruye, también se destruyen los buzones que poseyera. Paso de Mensajes Formato de mensajes: el formato de los mensajes depende de los objetivos del sistema de mensajería. Mensajes cortos y de tamaño fijo: Mejor procesamiento y ahorro en coste de almacenamiento. El mensaje puede ser la referencia a un archivo. Formato típico de un mensaje: Cabecera, con información relativa al mensaje. Longitud fija. Cuerpo, contenido real del mensaje. Longitud variable. Paso de Mensajes Disciplina de cola del buzón: Habitualmente FIFO: Insuficiente para mensajes urgentes. Alternativas a FIFO: Asociación de prioridades en el emisor. Permitir al receptor examinar los mensajes de la cola y elegir uno en función de su criterio. Exclusión mutua: recepción bloqueante, token. Antes de acceder a la sección crítica, todo proceso debe recibir un mensaje que le indique la entrada. Tras recibirlo, ejecuta la sección crítica Al terminar la sección crítica envía un mensaje para los próximos procesos. Paso de Mensajes Exclusión mutua: implementación. const int N = 20; void P() { mensaje msg; while(1) { receive(exmut, &msg); <Sección crítica> send(exmut, msg); // Resto del código de P. } } // Numero de procesos. // Recepción BLOQUEANTE // Envío no bloqueante void main() { crear_buzon(exmut); /* Envío de mensaje vacío para que el primer proceso pueda entrar en su sección crítica. */ send(exmut, NULL); // Genera N procesos P(). genera_P(N); } Prod. / Cons. - Paso de Mensajes Productor / Consumidor Buffer Limitado. const int capacidad = N; void productor() { mensaje msg; while(1) { receive(p_producir,&msg); msg = producir(); send(p_consumir,msg); } } void main() { crear_buzon(p_producir); crear_buzon(p_consumir); for (int i = 1; i <= N; i++) send(p_producir,NULL); pid_t pid = fork(); switch(pid) { case –1: printf(“Error, no funcionó fork”); break; case 0: consumidor(); break; // Código del hijo. default: productor(); break; // Código del padre. } void consumidor() { mensaje msg; while(1) { receive(p_consumir,&msg); consumir(msg); send(p_producir,msg) } } 4.1.7. LLAMADA A PROCEDIMIENTOS REMOTOS (RPC). RPC Los procedimientos conforman fronteras naturales para la división de los programas en procesos: ● Interfaces propios, puntos de entrada y puntos de salida. ● RPC hace transparentes al programador los sistemas distribuidos. Aspectos a tener en cuenta: ● Transferencia de control ● Vinculación ó enlace ● Flujo de datos Transferencia de control: ● Suspensión del proceso invocante ● Transferencia de datos al sistema invocado. ● Ejecución del procedimiento remoto ● Devolución de los resultados ● Reanudación del proceso invocante RPC Transferencia de control: (sigue) ● Incorpora el concepto de sustituto (stub) de usuario para representar al procedimiento al que se llama de modo remoto. LOCAL Usuario Sustituto de servidor Llamada local Empaquetar argumentos REMOTO Ejecutable RPC Tx Ejecutable RPC Rx Sustituto de usuario Servidor Desempaquetar argumentos Llamada Esperar Retorno local Desempaquetar argumentos Rx Ejecución Tx Empaquetar argumentos Retorno RPC Vinculación: ● ● ● Proceso consistente en dos pasos: Localización de módulos de componentes Resolución de referencias a direcciones para producir la imagen Flujo de Datos: ● ● Paso de parámetros: El problema es la homogeneidad de los datos. Estándares !! RPC es un protocolo de comunicación implementado en diversos SSOO y lenguajes de programación