SISTEMAS OPERATIVO SESION 2
PROCESOS
1. GENERALIDADES
1.1. Programa, proceso y tarea
a) Programa
Conjunto de instrucciones para una computadora. Un programa no hace nada a menos que sus instrucciones sean ejecutadas por el procesador.
b) Proceso
Es un programa en ejecución.
c) Tarea
Una tarea se refiere al proceso que está corriendo en memoria.
1.2. Sistema Operativo
“Un sistema operativo es el encargado de brindar al usuario una forma amigable y sencilla de operar, interpretar, codificar y emitir las órdenes al procesador central, para que éste, realice las tareas necesarias y específicas para completar una orden”
a) CLASIFICACIÓN
a. Por su Estructura
· Monolítico: están constituidos fundamentalmente por un solo programa compuesto de un conjunto de rutinas entrelazadas de tal forma que cada una puede llamar a cualquier otra. Estos sistemas tienen un núcleo grande y complejo, que engloba todos los servicios del sistema.
· Por Capas o Jerárquico: está dividido en pequeñas partes, de tal forma que cada una de ellas es perfectamente definida y con una interfaz clara con el resto de elementos.
· Cliente Servidor: El núcleo tiene como misión establecer la comunicación entre los clientes y los servidores. Cuando un proceso de usuario, llamado proceso cliente, necesita un servicio del S.O lo que hace es enviar un mensaje al proceso servidor correspondiente el cual realiza el trabajo y devuelve la respuesta.
· Maquina Virtual: El objetivo de los sistemas operativos de máquina virtual es el de integrar distintos sistemas operativos dando la sensación de ser varias máquinas diferentes. Estos sistemas operativos separan dos conceptos que suelen estar unidos en el resto de sistemas: la multiprogramación y la máquina extendida.
b. Por Cantidad de Tareas
· Monotarea: Sólo puede ejecutar una tarea o proceso (aparte de los procesos del propio S.O.) en un momento dado. Una vez que empieza a ejecutar un proceso, continuará haciéndolo hasta su finalización o interrupción.
· Multitarea: Permite que varias tareas (procesos) se ejecuten al tiempo. Cada tarea se ejecuta de manera independiente y utilizando los mismos recursos.
c. Por Cantidad de Usuarios
· Monousuario: Solamente permite ejecutar los programas de un usuario al mismo tiempo. Esto a causa de las limitaciones creadas por el hardware, los programas o el tipo de aplicación que se esté ejecutando.
· Multiusuario: administran y permiten que varios usuarios utilicen al tiempo, recursos de hardware y de software. Permite que varios usuarios ejecuten simultáneamente sus programas. Utilizan métodos de protección de datos, de manera que un programa no pueda usar o cambiar los datos de otro usuario.
d. Por la Forma de Administrar Recursos
· Centralizado: Si permite utilizar los recursos de un solo computador.
· Distribuido: Permite utilizar los recursos (memoria, CPU, disco, periféricos...) de más de un computador al mismo tiempo. Integran recursos, en una sola máquina virtual, que el usuario accesa en forma transparente. El usuario no necesita saber la ubicación de los recursos, sino que los conoce por nombre y simplemente los usa como si todos ellos fuesen locales a su lugar de trabajo habitual.
b) INTERFACES
Las interfaces sirven para comunicar el sistema operativo con el usuario y sus programas. Esta comunicación se realiza por medio de instrucciones que el SO proporciona o llamadas al sistema. Las interfaces se usan de dos formas:
· Línea de comandos:
Es un lenguaje de comandos especial, los comandos deben ser memorizados, son programables, otorgándoles flexibilidad.
· Interfaz gráfica.
Tipo de visualización que permite al usuario elegir comandos, iniciar programas, ver listas de archivos, etc. usando representaciones visuales (íconos) y menús. Se activan a través del mouse o teclado.
c) KERNEL
Es el corazón o núcleo del sistema. Esta porción del sistema operativo es la que trabaja de forma más cerrada e independiente del usuario. Se encarga de realizar las funciones de más bajo nivel con respecto al hardware del equipo, permitiendo la no-dependencia del hardware del resto de las partes del sistema operativo.
· Gestiona los recursos físicos, así como las aplicaciones de los usuarios.
· Sirve de interfaz entre los servicios de usuario del S.O. y el propio hardware.
· Reside permanentemente en memoria.
· Maneja los procesos asignando recursos, planificando la multitarea y manejando solicitudes de servicio del hardware.
· Maneja unidades supervisando la transmisión de datos entre los periféricos y las aplicaciones.
El kernel contiene un manejador para las unidades físicas de cada ordenador. Estos manejadores son propios de cada máquina y de cada dispositivo periférico.
d) SHELL
El shell es realmente la única parte del sistema que ve el usuario. Actúa como intérprete permitiendo la comunicación con el sistema.
Cuando un usuario introduce un comando, el shell, que es un programa que está en constante ejecución, lo analiza y llama a ejecución al programa que realiza la función especificada por el comando.
El shell es configurable, es decir, cada usuario puede tener su propio programa shell o “entorno”. Las actividades que normalmente realiza el shell pueden ser:
· Editar programas
· Inicializar soportes
· Comparar, copiar, mostrar e imprimir archivos
· Traducir e interpretar instrucciones
· Gestionar gráficos
· Depurar y encadenar grupos de comandos
Además de las características ya apuntadas hasta este momento cabe destacar otras características no menos importantes:
· Eficacia: es la primera característica que debe cumplir un Sistema Operativo; esto supone una ejecución de sus funciones de forma rápida y utilizando pocos recursos del ordenador.
· Fiabilidad: el sistema operativo debe ser robusto o como ya he dicho con anterioridad, debe ser tolerante a fallos.
· Fácil mantenimiento: debe estar escrito en un lenguaje de programación fácil de mantener y modificar. Esto le da una buena portabilidad.
· Portabilidad: un sistema operativo es portable cuando se puede transportar de un ordenador a otro físicamente distinto. Es una característica muy apreciada y que da origen a los deseados sistemas abiertos.
De manera esquemática, un sistema operativo se compone de:
1. Núcleo (Kernel): responsable de la gestión de memoria, de disco y de procesos.
2. Servicios (API: Aplication Program Interface): mediante estos servicios las aplicaciones pueden realizar peticiones al sistema operativo para acceder a los recursos hardware del sistema.
3. Shell (Intérprete de comandos): es el proceso encargado de traducir los comandos que los usuarios introducen, a instrucciones que el sistema operativo entiende.
a) ¿QUÉ ES UN PROCESO?
Un proceso es un programa en ejecución. Un proceso simple tiene un hilo de ejecución, por el momento dejemos esta última definición como un concepto, luego se verá en más detalle el concepto de hilo. Una vez definido que es un proceso nos podríamos preguntar cuál es la diferencia entre un programa y un proceso, y básicamente la diferencia es que un proceso es una actividad de cierto tipo que contiene un programa, entradas salidas y estados.
Los procesos pueden ser cooperantes o independientes, en el primer caso se entiende que los procesos interactúan entre sí y pertenecen a una misma aplicación. En el caso de procesos independientes en general se debe a que no interactúan y un proceso no requiere información de otros o bien porque son procesos que pertenecen a distintos usuarios.
En la bibliografía los términos job, task y proceso suelen tomarse como sinónimos (dependiendo el autor del texto), pero significan cosas distintas. Un job o trabajo está generalmente asociado a procesamiento en batch y agrupa todas las tareas necesarias para ejecutar ese procesamiento. Un task o tarea es una actividad en particular. En general un job en se compone de varios tasks.
Un proceso se caracteriza por poseer:
· Contador de programa (PC)
· Estado
· Stack
· Sección de datos
· PCB
2. ESTADOS
El principal trabajo del procesador es ejecutar las instrucciones de máquina que se encuentran en memoria principal. Estas instrucciones se encuentran en forma de programas. Para que un programa pueda ser ejecutado, el sistema operativo crea un nuevo proceso, y el procesador ejecuta una tras otra las instrucciones del mismo.
Los procesos en el estado listo son los que pueden pasar a estado de ejecución si el planificador los selecciona. Los procesos en el estado ejecución son los que se están ejecutando en el procesador en ese momento dado. Los procesos que se encuentran en estado bloqueado están esperando la respuesta de algún otro proceso para poder continuar con su ejecución. Por ejemplo operación de E/S.
El concepto central de cualquier Sistema Operativo es el de proceso: una abstracción de un programa en ejecución también llamada tarea.
2.1. Modelo de cinco estados:
En la realidad, los procesos utilizan datos para operar con ellos, y puede suceder que no se encuentren listos, o que se deba esperar algún suceso antes de continuar, como una operación de Entrada/Salida. Es por esto que se necesita un estado donde los procesos permanezcan bloqueados esperando hasta que puedan proseguir. Se divide entonces al estado No ejecución en dos estados: Listo y Bloqueado. Se agregan además un estado Nuevo y otro Terminado.
Los cinco estados de este diagrama son los siguientes:
· Ejecución: el proceso está actualmente en ejecución.
· Listo: el proceso está listo para ser ejecutado, sólo está esperando que el planificador así lo disponga.
· Bloqueado: el proceso no puede ejecutar hasta que no se produzca cierto suceso, como una operación de Entrada/Salida.
· Nuevo: El proceso recién fue creado y todavía no fue admitido por el sistema operativo. En general los procesos que se encuentran en este estado todavía no fueron cargados en la memoria principal.
· Terminado: El proceso fue expulsado del grupo de procesos ejecutables, ya sea porque terminó o por algún fallo, como un error de protección, aritmético, etc.
Los nuevos estados Nuevo y Terminado son útiles para la gestión de procesos. En este modelo los estados Bloqueado y Listo tienen ambos una cola de espera. Cuando un nuevo proceso es admitido por el sistema operativo, se sitúa en la cola de listos. A falta de un esquema de prioridades ésta puede ser una cola FIFO. Los procesos suspendidos son mantenidos en una cola de bloqueados. Cuando se da un suceso se pasan a la cola de listos los procesos que esperaban por ese suceso.
2.2. Transiciones de estado de los procesos:
A continuación se dan ejemplos de eventos que pueden provocar transiciones de estado en un proceso en este modelo de tres estados. La mayoría de estos eventos se discutirán con profundidad a lo largo del curso:
· De ejecución á Bloqueado: al iniciar una operación de E/S, al realizar una operación WAIT sobre un semáforo a cero (en el tema de procesos concurrentes se estudiarán los semáforos).
· De ejecución á Listo: por ejemplo, en un sistema de tiempo compartido, cuando el proceso que ocupa la CPU lleva demasiado tiempo ejecutándose continuamente (agota su cuanto) el sistema operativo decide que otro proceso ocupe la CPU, pasando el proceso que ocupaba la CPU a estado listo.
· De Listo á en ejecución: cuando lo requiere el planificador de la CPU (veremos el planificador de la CPU en el tema de planificación de procesos).
· De Bloqueado á Listo: se dispone del recurso por el que se había bloqueado el proceso. Por ejemplo, termina la operación de E/S, o se produce una operación SIGNAL sobre el semáforo en que se bloqueó el proceso, no habiendo otros procesos bloqueados en el semáforo.
Obsérvese que de las cuatro transiciones de estado posibles, la única iniciada por el proceso de usuario es el bloqueo, las otras tres son iniciadas por entidades externas al proceso.
2.3. Bloque de Control de los Procesos (PCB)
Es una estructura de datos que contiene información asociada a cada proceso. La Tabla General del sistema contiene una lista de todos los procesos, con la PID (process identification) y un puntero a la correspondiente PCB.
En lo que tiene que ver con el control de todos los procesos que se efectúan en nuestro sistema, tenemos que tener claro los estados del proceso (aceptado, listo, en ejecución, bloqueado). Un Program counter, los Registros del CPU, información para la planificación del CPU, información para la Administración de Memoria, información para la Contabilidad y la Información del Estado de la E/S. Pero para administrar estos procesos correctamente necesitamos de una administración o planificación correcta, teniendo:
· Planificador de Trabajos (alto nivel): Se ocupa de elegir los trabajos de una cola de trabajos que llegan y los coloca en la cola de procesos (se basa en los conceptos de: primero en entrar, primero en servirse y en el de prioridad).
· Planificador de procesos (bajo nivel): Se ocupa de asignar el CPU para ejecutar los procesos de los trabajos de la cola de LISTOS.
· Planificador de nivel medio: Se ocupa de retirar trabajos activos de la memoria para reducir el grado de multiprogramación
Cada proceso se representa en el sistema operativo con un bloque de control del proceso (PCB, process control block), también llamado bloque de control de tarea. Este bloque contiene muchos elementos de información asociados a un proceso específico, incluidos los siguientes:
· Estado del proceso: El estado puede ser: nuevo, listo, en ejecución, en espera, detenido, etc.
· Contador de programa: el contador indica la dirección de la siguiente instrucción que se ejecutara para este proceso.
· Registros de CPU: El número y tipo de los registros varía dependiendo de la arquitectura del computador. Los registros incluyen acumuladores, registros índices, punteros de pila y registros de propósito general, así como cualesquier información de códigos de condición que haya. Junto con el contador de programa, esta información de estado se debe guardar cuando ocurre una interrupción, para que el proceso pueda continuar correctamente después.
· Información de planificación de CPU: Esta información incluye una prioridad del proceso, punteros a colas de planificación y cualesquier otros parámetros de planificación que haya.
· Información de gestión de memoria: Esta información puede incluir datos tales como el valor de los registros de base y límite, las tablas de páginas o las tablas de segmentos, dependiendo del sistema de memoria empleado por el sistema operativo (Cap. 8).
· Información contable: Esta información incluye la cantidad de tiempo de CPU y tiempo real consumida, límites de tiempo, números de cuenta, números de trabajo o proceso, y demás.
2.4. PLANIFICACIÓN DE PROCESOS
Existen dos planificadores que se encargan respectivamente de pasar trabajos o procesos a la memoria principal y a la CPU. El más importante es el Planificador de la CPU que se encarga de decidir qué procesos de los que están preparados pasarán a ejecución cuando la CPU se libere de algún otro proceso (cuando este pase a estar en espera). Esta planificación puede ser apropiativa o no apropiativa, siendo la primera aquella en la que unos procesos tienen prioridad sobre otros y cuando acaban de estar en espera y pasan a preparado hacen que el S.O. les dé paso a la CPU que abandona el proceso que tenía en ejecución, lo pone en preparado y pasa a ejecutar el que tiene prioridad. Con el otro sistema la CPU ejecuta un proceso hasta que lo termina o por alguna razón éste pasa a estar en espera. Existen varios criterios por los cuales la CPU es capaz de cambiar de proceso en ejecución:
· Utilización de la CPU: el S.O. pretende que la CPU este el menor tiempo posible inactiva.
· Productividad.
· Tiempo de retorno: el proceso en ejecución tarda mucho en acabar una acción, pudiendo encontrarse en un bucle muy largo.
· Tiempo de espera: se pretende que los procesos no estén demasiado tiempo en espera.
· Tiempo de respuesta.
a) COLAS DE LA PLANIFICACIÓN DE PROCESOS
Entre estas podemos tener:
· Cola de trabajos – conjunto de todos los procesos en el sistema.
· Cola de procesos listos – conjunto de todos los procesos residentes en la memoria-principal, listos y en espera para ejecutarse.
· Cola de dispositivos –conjunto de todos los procesos en espera de un dispositivo de E/S.
· Migración de los Procesos entre las distintas colas.
Conforme el trabajo se mueve a través del sistema, su avance se anota en el PCB.
b) PLANIFICADORES
Un proceso migra de una cola de planificación a otra durante toda su existencia. Para fines de planificación, el sistema operativo debe seleccionar procesos de estas colas de alguna manera. El planificador apropiado se encarga de este proceso de selección. En un sistema por lotes, es común que haya más procesos presentados de los que se pueden ejecutar inmediatamente. Estos procesos se colocan en spool en un dispositivo de almacenamiento masivo (por lo regular un disco), y ahí esperan hasta que pueden ejecutarse. El planificador a largo plazo (o planificador de trabajos) escoge procesos de esta reserva y los carga en la memoria para que se ejecuten. El planificador a corto plazo (o planificador de CPU) escoge entre los procesos que están listos para ejecutarse, y asigna la CPU a uno de ellos.
La distinción primaria entre estos dos planificadores es la frecuencia con que se ejecutan. El planificador a corto plazo debe seleccionar un proceso nuevo para la CPU de forma relativamente frecuente. Un proceso podría ejecutarse durante unos cuantos milisegundos antes de esperar una solicitud de E/S. En muchos casos, el planificador a corto plazo se ejecuta por lo menos una vez cada 100 milisegundos. Dada la brevedad del lapso entre ejecuciones, el planificador a corto plazo debe ser muy rápido. Si se requieren 10 milisegundos para tomar la decisión de ejecutar un proceso durante 100 milisegundos, se estará gastando (desperdiciando) el 10/(100 + 10) = 9% del tiempo de CPU simplemente para planificar el trabajo. El planificador a largo plazo, en cambio, se ejecuta con una frecuencia mucho menor. Podrían pasar minutos entre la creación de procesos nuevos en el sistema. El planificador a largo plazo controla el grado de multiprogramación (el numero de procesos que están en la memoria). Si el grado de multiprogramación es estable, la frecuencia promedio de creación de procesos debe ser igual? a. la frecuencia promedio de salida de procesos del sistema. Así, podría ser que solo sea necesario invocar el planificador a largo plazo cuando un proceso sale del sistema. Como el intervalo entre ejecuciones es más largo, el planificador a largo plazo puede darse el lujo de tardar más en decidir cual proceso escogerá para ejecutarlo.
Entre los planificadores podemos tener:
· Planificador de largo plazo (o planificador de trabajos) selecciona cual proceso deberá ser traído a la cola de procesos listos.
· Planificador de corto plazo (o planificador del CPU).- selecciona cual proceso deberá ser ejecutado enseguida y colocarlo en el CPU.
El planificador de corto plazo es invocado muy frecuentemente: (en milisegundos) ⇒ (deberá de ser rápido).
El planificador de largo plazo es invocado muy infrecuentemente: (en segundos, o minutos) ⇒ (deberá de ser lento). El planificador de largo plazo controla el grado de multiprogramación (el número de procesos en la memoria).
Planificador de mediano plazo (en sistemas de tiempo compartido).- realiza intercambio (swapping), para liberar a la memoria principal y reducir el grado de multiprogramación y también para mejorar la mezcla de procesos.
Los procesos pueden ser descritos como:
· Procesos limitados por E/S.- pasan más tiempo realizando E/S que computaciones, y va muchas veces al CPU, es de carrera corta.
· Procesos limitados por CPU.- pasan más tiempo realizando computaciones; y va muy pocas veces al CPU, es de carrera larga.
El sistema para un mejor rendimiento tiene una buena mezcla de ambos procesos
Es importante que el planificador a largo plazo haga una selección cuidadosa. En general, los procesos pueden describirse como limitados por E / S o limitados por CPU. Un proceso limitado por E/S es uno que dedica la mayor parte de su tiempo a operaciones de E/S, y menos a realizar cálculos. Un proceso limitado por CPU, en cambio, genera solicitudes de E/S con poca frecuencia, y dedica más de su tiempo a realizar cálculos que un proceso limitado por E/S. Es importante que el planificador a largo plazo escoja una buena mezcla de procesos limitados por E / S y limitados por CPU. Si todos los procesos están limitados por E/S, la cola de procesos listos casi siempre estará vacía, y el planificador a corto plazo casi no tendrá que hacer. Si todos los procesos están limitados por CPU, la cola de espera de E / S casi siempre estará vacía, los dispositivos estarán ociosos, y una vez más el sistema estará des balanceado. El sistema con el mejor rendimiento tiene una combinación de procesos limitados por E/S y limitados por CPU.
En algunos sistemas, el planificador a largo plazo podría estar ausente o ser mínimo. Por ejemplo, es común que los sistemas de tiempo compartido no tengan planificador a largo plazo y se limiten a colocar todos los procesos nuevos en la memoria para el planificador a corto plazo. La estabilidad de estos sistemas depende de una limitación física (como el numero de terminales disponibles) o bien de la naturaleza autoajustable de los usuarios humanos. Si el desempeño baja a niveles inaceptables, algunos usuarios simplemente se darán por vencidos y harán alguna otra cosa. Algunos sistemas operativos, como los de tiempo compartido, podrían introducir un nivel adicional, intermedio, de planificación. La idea clave en que se basan los planificadores a mediano plazo es que a veces puede ser provechoso sacar procesos de la memoria (y de la contención activa por la CPU) a fin de reducir el grado de multiprogramación. En algún momento posterior, el proceso se reintroducirá en la memoria y podrá continuar su ejecución donde se quedo. Este esquema se denomina intercambio (swapping). El planificador a mediano plazo intercambia el proceso a disco y luego lo intercambia a la memoria. Esto puede ser necesario para mejorar la mezcla de procesos o cuando un cambio en las necesidades de memoria ha distribuido la memoria disponible entre demasiados procesos, y es preciso liberar algo de memoria.
c) Conmutación de contexto
El cambio de la CPU a otro proceso requiere guardar el estado del proceso anterior y cargar el estado guardado del nuevo proceso. Esta tarea se denomina conmutación de contexto (context switch). El tiempo de conmutación de contexto es exclusivamente gasto extra (overhead), porque el sistema no realiza trabajo útil durante la conmutación. La rapidez de conmutación varia de una maquina a otra, dependiendo de la velocidad de la memoria, el número de registros que hay que copiar y la existencia de instrucciones especiales (como una sola instrucción para cargar y almacenar todos los registros). Por lo regular, el tiempo de conmutación varia entre 1 y 1000 microsegundos. Los tiempos de conmutación de contexto dependen en buena medida del apoyo del hardware.
Por ejemplo, algunos procesadores (como el DECSYSTEM-20) cuentan con varios conjuntos de registros. Una conmutación de contexto simplemente implica cambiar el puntero al conjunto de registros actual. Desde luego, si hay más procesos activos que conjuntos de registros, el sistema tendrá que recurrir a copiar los datos de registros en la memoria, igual que antes. Además, cuanto más complejo es el sistema operativo, mas trabajo hay que efectuar durante una conmutación de contexto. Las técnicas de gestión de memoria avanzadas podrían requerir la conmutación de datos adicionales con cada contexto. Por ejemplo, se hace necesario preservar el espacio de direcciones del proceso actual antes de preparar el espacio para la siguiente tarea. La manera como se preserva el espacio de direcciones, y la cantidad de trabajo que implica, dependen del método de gestión de memoria del sistema operativo. La conmutación de contexto se ha convertido en un cuello de botella tan importante para el desempeño que se están empleando estructuras nuevas (hilos) para evitarla hasta donde sea posible.
3. Operaciones con Procesos
3.1. Creación de procesos
Un proceso puede crear varios procesos nuevos, a través de una llamada al sistema de "crear proceso", durante el curso de su ejecución. El proceso creador se denomina proceso padre, y los nuevos procesos son los hijos de ese proceso. Cada uno de estos procesos nuevos puede a su vez crear otros procesos, formando un árbol de procesos.
En general, un proceso necesita ciertos recursos (tiempo de CPU, memoria, archivos, dispositivos de E/S) para efectuar su tarea. Cuando un proceso crea un subproceso, este tal vez pueda obtener sus recursos directamente del sistema operativo, pero podría estar restringido a un subconjunto de los recursos del proceso padre. El padre quizá tenga que dividir sus recursos entre sus hijos, o tal vez varios de sus hijos puedan compartir algunos recursos (como memoria o archivos). La restricción de un proceso hijo a un subconjunto de los recursos del padre impide que cualquier proceso sobrecargue el sistema creando demasiados subprocesos. Además de los diversos recursos físicos y lógicos que un proceso obtiene cuando se crea, el proceso padre podría pasar a su hijo datos de iniciación (entradas). Por ejemplo, consideremos un proceso cuya función es exhibir la situación de un archivo, digamos Al, en la pantalla de una terminal. En el momento de crearse recibirá, como entradas de su proceso padre, el nombre del archivo Al, y se ejecutara utilizando ese dato para obtener la información deseada. El proceso también podría recibir el nombre del dispositivo de salida. Algunos sistemas operativos pasan recursos a los procesos hijos. En un sistema semejante, el proceso nuevo podría obtener dos archivos abiertos, Al y el dispositivo de terminal, y tal vez solo tendría que transferir el dato entre los dos. Cuando u n proceso crea u n proceso nuevo, hay dos posibilidades en términos de ejecución:
• El padre sigue ejecutándose de forma concurrente con sus hijos.
• El padre espera hasta que algunos de sus hijos, o todos, han terminado.
También hay dos posibilidades en términos del espacio de direcciones del nuevo proceso:
• El proceso hijo es un duplicado del proceso padre.
• Se carga un programa en el proceso hijo.
Para ilustrar estas diferentes implementaciones, consideremos el sistema operativo UNIX. En UNIX, cada proceso se identifica con su identificador de proceso, que es un entero único. Se crea un proceso nuevo con la llamada al sistema fork (bifurcar). El nuevo proceso consiste en una copia del espacio de direcciones del proceso original. Este mecanismo permite al proceso padre comunicarse fácilmente con su proceso hijo. Ambos procesos (el padre y el hijo) continúan su ejecución con la instrucción que sigue al fork con una diferencia: el código de retorno que el proceso nuevo (hijo) recibe del fork es cero, pero al padre se devuelve el identificador de proceso (distinto de cero) del hijo.
Por lo regular, uno de los dos procesos utiliza la llamada al sistema execve después del fork para reemplazar su espacio de memoria con un programa nuevo. La llamada execve carga un archivo binario en la memoria (destruyendo la imagen de memoria del programa que contenía la llamada execve) e inicia su ejecución. De esta forma, los dos procesos pueden comunicarse, y luego cada uno sigue su propio camino. El padre puede crear más hijos o, si no tiene nada más que hacer mientras el hijo se ejecuta, puede emitir una llamada al sistema wait (esperar) para sacarse a sí mismo de la cola de procesos listos hasta que el hijo termine.
El sistema operativo DEC VMS, en contraste, crea un proceso nuevo, carga un programa especificado en ese proceso, e inicia su ejecución. El sistema operativo Microsoft Windows NT maneja ambos modelos: el espacio de direcciones del padre podría duplicarse, o el padre podría especificar el nombre de un programa que el sistema operativo cargara en el espacio de direcciones del nuevo proceso.
3.2. Terminación de procesos
Un proceso acaba cuando termina de ejecutar su ultimo enunciado y le pide al sistema operativo que lo elimine utilizando la llamada al sistema salir (exit). En ese momento, el proceso podría devolver datos (salidas) a su proceso padre (por medio de la llamada al sistema esperar). El sistema operativo liberará todos los recursos del proceso, incluidos memoria física y virtual, archivos abiertos v buffersdeE/S.
Hay otras circunstancias en las que ocurre la terminación. Un proceso puede causar la terminación de otro con una llamada al sistema apropiada (por ejemplo, abortar). Normalmente, solo el padre del proceso que se terminara puede emitir tal llamada. De otro modo, los usuarios podrían matar arbitrariamente los trabajos de otros usuarios. Es evidente que el padre necesita conocer la identidad de sus hijos. Por ello, cuando un proceso crea un proceso nuevo, el sistema operativo le pasa la identidad del proceso recién creado.
Un padre podría terminar la ejecución de uno de sus hijos por diversas razones, como:
• El hijo se ha excedido en la utilización de algunos de los recursos que se le asignaron.
• La tarea que se asigno al hijo ya no es necesaria.
• El padre va a salir, y el sistema operativo no permite que un hijo continúe si su padre termina.
Para determinar el primer caso, el padre debe contar con un mecanismo para inspeccionar el estado de sus hijos.
Muchos sistemas, incluido VMS, no permiten que un hijo exista si su padre ya termino. En tales sistemas, si un proceso termina (sea normal o anormalmente), todos sus hijos tienen que terminar. Este fenómeno se denomina terminación en cascada y por lo regular es el sistema operativo quien lo inicia.
Para ilustrar la ejecución y terminación de procesos, consideremos otra vez el sistema
UNIX. En UNIX, un proceso puede terminar emitiendo la llamada al sistema éxito, y su proceso padre puede esperar ese suceso empleando la llamada al sistema wait. Esta última llamada devuelve el identificador de proceso de un hijo que ha terminado, para que su padre pueda saber cuál de sus posiblemente múltiples hijos termino. Por otro lado, si el padre termina, el sistema operativo hace que todos los hijos terminen. Si no hay un padre, UNIX no sabe a quién informar de las actividades de un hijo.
4. Comunicación entre procesos
Los procesos cooperativos pueden comunicarse en un entorno de memoria compartida. El esquema requiere que estos procesos compartan una reserva de buffers común, y que el programador de la aplicación escriba explícitamente el código para implementar el buffet. Otra forma de lograr el mismo efecto es que el sistema operativo proporcione los medios para que procesos cooperativos se comuniquen unos con otros a través de un mecanismo de comunicación entre procesos (IPC, interprocess communication).
La IPC ofrece un mecanismo que permite a los procesos comunicarse y sincronizar sus acciones. La mejor forma de proveer la comunicación entre procesos es mediante un sistema de mensajes. Hay muchas formas diferentes de definir los sistemas de mensajes. Estos sistemas también tienen otras ventajas.
Cabe señalar que los esquemas de comunicación por memoria compartida y por transferencia de mensajes no son mutuamente exclusivos, y podrían utilizarse simultáneamente dentro de un mismo sistema operativo o incluso dentro de un mismo proceso.
4.1. Estructura Básica
La función de un sistema de mensajes es permitir a los procesos comunicarse entre si sin tener que recurrir a variables compartidas. Un recurso de IPC ofrece por lo menos dos operaciones enviar (mensaje) (send) y recibir (mensaje) (receive). Los mensajes que un proceso envía pueden ser de tamaño fijo o variable. Si solo es posible enviar mensajes de tamaño fijo, la implementación física es sencilla. Sin embargo, esta restriccion dificulta la tarea de programación. Por otro lado, los mensajes de tamaño variable requieren una implementación física más compleja, aunque simplifican la tarea de programación.
Si los procesos P y Q quieren comunicarse, deberán enviarse mensajes; para ello, debe existir un enlace de comunicación entre ellos. Este enlace se puede implementar de diversas maneras. Aquí no nos interesa la implementación física del enlace (que podría ser memoria compartida, un bus de hardware o una red), sino los problemas de su implementación lógica, como sus propiedades lógicas. Las siguientes son algunas preguntas básicas que deben contestarse para la implementación:
• ¿Cómo se establecen los enlaces?
• ¿Un enlace puede estar asociado a mas de dos procesos?
• ¿Cuantos enlaces puede haber entre cada par de procesos?
• ¿Qué capacidad tiene un enlace? Es decir, el enlace tiene espacio de buffer. De ser así, ¿cuánto?
• ¿Qué tamaño tienen los mensajes? ¿El enlace puede dar cabida a mensajes de tamaño variable o solo de tamaño fijo?
• ¿El enlace es unidireccional o bidireccional? Es decir, si existe un enlace entre P y
Q, ¿los mensajes pueden fluir solo en una dirección (digamos, solo de P a Q) o en ambas direcciones?
La definición de unidireccional se debe plantear con más cuidado, ya que un enlace podría estar asociado a más de dos procesos. Así, decimos que un enlace es unidireccional solo si cada proceso conectado al enlace puede enviar o recibir, pero no ambas cosas, y cada enlace tiene por lo menos un proceso receptor conectado a él. Además, hay varios métodos para implementar lógicamente un enlace y las operaciones de enviar/recibir:
• Comunicación directa o indirecta
• Comunicación simétrica o asimétrica
• Uso de buffers automático o explicito
• Envió por copia o envió por referencia
• Mensajes de tamaño fijo o variable
4.2. Asignación de nombres
Los procesos que desean comunicarse deben tener una forma de referirse unos a otros. Se puede usar comunicación directa o comunicación indirecta, como veremos en las dos sub-secciones siguientes.
a) Comunicación directa
En la disciplina de comunicación directa, cada proceso que desea comunicarse debe nombrar explícitamente el destinatario o el remitente de la comunicación. En este esquema, se definen las primitivas enviar y recibir como sigue:
Enviar (P, mensaje). Enviar un mensaje al proceso P.
Recibir (Q, mensaje). Recibir un mensaje del proceso Q.
Un enlace de comunicación en este esquema tiene las propiedades siguientes:
• Se establece automáticamente un enlace entre cada par de procesos que desean comunicarse. Los procesos solo necesitan conocer la identidad del otro para comunicarse.
• Un enlace se asocia a exactamente dos procesos.
• Entre cada par de procesos solo existe un enlace.
• El enlace puede ser unidireccional, pero suele ser bidireccional.
Como ilustración, presentaremos una solución al problema de productores y consumidores. Para que los procesos productores y consumidores puedan ejecutarse de forma concurrente, permitimos al productor producir un elemento mientras el consumidor está consumiendo otro elemento. Cuando el productor termina de generar un elemento, envía ese elemento al consumidor. El consumidor obtiene dicho elemento por medio de la operación recibir. Si un elemento todavía no se ha producido, el proceso consumidor debe esperar hasta que se produce. El proceso productor se define así:
repeat
…
producir un elemento en sigp
…
enviar (consumidor, sigp);
until false;
El proceso consumidor se define así:
repeat
recibir (productor, sigc);
…
consumir el elemento que está en sigc
…
until false;
Este esquema exhibe una simetría de direccionamiento; es decir, los procesos tanto emisor como receptor necesitan nombrar al otro para comunicarse. Una variante de este esquema utiliza asimetría de direccionamiento. Solo el emisor nombra al destinatario; el destinatario no está obligado a nombrar al emisor. En este esquema, las primitivas enviar y recibir se definen como sigue:
· enviar (P, mensaje): Enviar un mensaje al proceso P.
· recibir (id, mensaje): Recibir un mensaje de cualquier proceso; se asigna a la variable id el nombre del proceso con el que hubo comunicación.
La desventaja de ambos esquemas (simétrico y asimétrico) es la limitada modularidad de las definiciones de proceso que se obtienen. Para cambiar el nombre de un proceso podría ser necesario examinar todas las demás definiciones de procesos. Hay que hallar todas las referencias al nombre antiguo a fin de poder cambiarlas al nuevo. Esta situación no es deseable desde el punto de vista de la compilación separada.
b) Comunicación indirecta
Con la comunicación indirecta, los mensajes se envían a, y se reciben de, buzones (también llamados puertos). Un buzón puede considerarse en abstracto como un objeto en el que los procesos pueden colocar mensajes y del cual se pueden sacar mensajes. Cada buzón tiene una identificación única. En este esquema, un proceso se puede comunicar con otro a través de varios buzones distintos. Dos procesos pueden comunicarse solo si comparten un buzón. Las primitivas enviar y recibir se definen como sigue:
· enviar(A, mensaje): Enviar un mensaje al buzón A.
· recibir(A, mensaje): Recibir un mensaje del buzón A.
En este esquema, un enlace de comunicación tiene las propiedades siguientes:
· Se establece un enlace entre un par de procesos solo si tienen un buzón compartido.
· Un enlace puede estar asociado a más de dos procesos.
· Entre cada par de procesos en comunicación puede haber varios enlaces distintos, cada uno de los cuales corresponderá a un buzón.
· Los enlaces pueden ser unidireccionales o bidireccionales.
Supongamos ahora que los procesos P1, P2 y P3 comparten el buzón A. El proceso P1 envía un mensaje a A, y P2 y P3 ejecutan cada uno un recibir de A. ¿Cuál proceso recibirá el mensaje que P1 envió? Esta cuestión puede resolverse de varias maneras:
· No permitir que un enlace este asociado a mas de dos procesos.
· No permitir que más de un proceso ejecute una operación recibir a la vez.
· Permitir al sistema escoger arbitrariamente cual proceso recibirá el mensaje (es decir, P2 o P3, pero no ambos, recibirá el mensaje). El sistema podría identificar el receptor al emisor.
Un buzón puede ser propiedad de un proceso o del sistema. En el primer caso (es decir, si el buzón está unido a, o definido como parte de, el proceso), distinguimos entre el propietario (que solo puede recibir mensajes a través de este buzón) y el usuario del buzón (que solo puede enviar mensajes al buzón). Puesto que cada buzón tiene un propietario único, no puede haber confusión respecto a quien debe recibir un mensaje enviado a este buzón. Cuando un proceso que posee un buzón termina, el buzón desaparece. Cualquier proceso que envié subsecuentemente un mensaje a ese buzón deberá ser notificado de que el buzón ya no existe (por medio de manejo de excepciones).
Hay varias formas de designar el dueño y los usuarios de un buzón dado. Una posibilidad es permitir que un proceso declare variables de tipo buzón. El proceso que declara un buzón es el dueño de ese buzón. Cualquier otro proceso que conozca el nombre de dicho buzón podrá usarlo. Por otro lado, un buzón propiedad del sistema operativo tiene existencia propia; es independiente y no está unido a ningún proceso específico. El sistema operativo establece un mecanismo que permite a un proceso:
· Crear un buzón nuevo
· Enviar y recibir mensajes a través del buzón
· Destruir un buzón
El proceso que crea un buzón nuevo es, por omisión, su dueño. Inicialmente, el dueño es el único proceso que puede recibir mensajes a través de este buzón. Sin embargo, la propiedad y el privilegio de recibir se pueden transferir a otros procesos por medio de llamadas al sistema apropiadas. Desde luego, esta posibilidad podría dar lugar a la existencia de múltiples receptores para cada buzón. Los procesos también podrían compartir un buzón a través del recurso de creación de procesos. Por ejemplo, si el proceso P crea el buzón A, y luego crea un nuevo proceso Q, P y Q podrían compartir el buzón A. Puesto que todos los procesos con derecho de acceso a un buzón podrían terminar en algún momento, podría suceder que después de cierto tiempo un buzón ya no esté accesible a ningún proceso. En este caso, el sistema operativo deberá recuperar el espacio utilizado para el buzón.
Esta tarea podría requerir alguna forma de recolección de basura en la que ocurre una operación independiente para buscar y liberar memoria que ya no se está usando.
4.3. Uso de buffers
Un enlace tiene cierta capacidad que determina el numero de mensajes que pueden residir en el temporalmente. Esta propiedad puede visualizarse como una cola de mensajes unida al enlace. Básicamente, hay tres formas de implementar una cola semejante.
· Capacidad cero: La cola tiene como longitud máxima 0; el enlace no puede tener mensajes esperando en el. En este caso el emisor deberá esperar hasta que el destinatario reciba el mensaje. Los dos procesos deben sincronizarse para que pueda haber una transferencia de mensaje. Esta sincronización se denomina encuentro (rendezvous).
· Capacidad limitada: La cola tiene una longitud finita n; es decir, cuando más n mensajes pueden residir en ella. Si la cola no está llena cuando se envía un mensaje nuevo, este se coloca en la cola (se copia el mensaje o bien se mantiene un puntero a él) y el emisor puede continuar su ejecución sin esperar. Sin embargo, el enlace tiene una capacidad finita; si está lleno, el emisor deberá esperar hasta que haya espacio libre en la cola.
· Capacidad ilimitada: La cola tiene una longitud potencialmente infinita; en ella puede esperar cualquier cantidad de mensajes. El emisor nunca espera.
El caso de capacidad cero recibe también el nombre de sistema de mensajes sin buffers; los otros casos ofrecen almacenamiento automático en buffers.
Cabe señalar que, en los casos de capacidad cero, un proceso no sabe si su mensaje llego o no a su destino después de llevar a cabo la operación enviar. Si esta información es crucial para el cálculo, el emisor deberá comunicarse explícitamente con el receptor para averiguar si este último recibió el mensaje. Por ejemplo, supongamos que el proceso P envía un mensaje al proceso Q y solo puede continuar su ejecución después de haberse recibido el mensaje. El proceso P ejecuta la secuencia
enviar (Q, mensaje);
recibir (Q, mensaje);
El proceso Q ejecuta
enviar (P, mensaje);
recibir (P, "confirmación");
Se dice que tales procesos se comunican asincrónicamente.
Hay casos especiales que no encajan directamente en ninguna de las categorías que hemos descrito:
· El proceso que envía un mensaje nunca espera. Sin embargo, si el receptor no ha recibido el mensaje antes de que el proceso emisor envié otro mensaje, el primero se perderá. La ventaja de este esquema es que no es necesario copiar más de una vez los mensajes grandes. La desventaja principal es que la tarea de programación se vuelve más difícil. Los procesos necesitan sincronizarse explícitamente para asegurar que no se pierdan los mensajes y también que el emisor y el receptor no manipulen el buffer de mensajes simultáneamente.
· El proceso que envía un mensaje espera hasta recibir una respuesta. Este esquema se adopto en el sistema operativo Thoth, en el que los mensajes tienen un tamaño fijo (ocho palabras). Un proceso P que envía un mensaje se bloquea hasta que el proceso receptor ha recibido el mensaje y ha devuelto una respuesta de ocho palabras empleando la primitiva reply (P, mensaje). El mensaje de respuesta se escribe sobre el buffer del mensaje original. La única diferencia entre las primitivas send y reply es que un send hace que el proceso emisor se bloquee, mientras que reply permite que tanto el proceso emisor como el receptor continúen de inmediato su ejecución.
Este método de comunicación sincrónico puede expandirse fácilmente para tener un sistema de llamada a procedimientos remotos (RPC, remote procedure cali) con todas las de la ley. Los sistemas RPC se basan en la percepción de que una llamada a una subrutina o procedimiento en un sistema monoprocesador actúa exactamente como un sistema de mensajes en el que el emisor se bloquea hasta que recibe una respuesta.
El mensaje es entonces como una llamada a una subrutina, y el mensaje de retorno contiene el valor de la subrutina calculada. El siguiente paso lógico es que procesos concurrentes puedan invocarse mutuamente como subrutinas empleando RPC. De hecho, se pueden usar RPC entre procesos que se ejecutan en computadores distintos, con lo cual varios computadores pueden colaborar para beneficio mutuo.
4.4. Condiciones de excepción
Los sistemas de mensajes son útiles sobre todo en los entornos distribuidos, donde los procesos podrían residir en diferentes sitios (maquinas). En un entorno así, la probabilidad de que ocurra un error durante la comunicación (y el procesamiento) es mucho mayor que en un entorno de una sola maquina. En este último caso, los mensajes por lo regular se implementan en memoria compartida. Si ocurre una falla, todo el sistema falla. En un entorno distribuido, en cambio, los mensajes se transfieren por líneas de comunicación, y el fallo de un sitio (o enlace) no causa necesariamente el fallo de todo el sistema.
Cuando ocurre un fallo en un sistema, sea centralizado o distribuido, el sistema debe intentar recuperarse del error (manejar la condición excepcional). Comentaremos brevemente algunas condiciones excepcionales que un sistema debe manejar en el contexto de un esquema de mensajes.
a) El proceso termina
El emisor o el receptor podrían terminar antes de que se procese un mensaje. Esta situación deja mensajes que nunca se recibirán o procesos esperando mensajes que nunca se enviaran. Aquí consideraremos dos casos:
1. Un proceso receptor P podría esperar un mensaje de un proceso Q que ya termino.
Si no se toman medidas, P se bloqueara eternamente. En este caso, el sistema podría terminar P, o bien notificar a P que Q termino.
2. El proceso P podría enviar un mensaje a un proceso Q que ya termino.
Con el esquema de colocación automática en buffers, no hay problema; P simplemente continuara su ejecución. Si P necesita saber que Q proceso su mensaje, deberá programar explícitamente una confirmación. Si no se usan buffers, P se bloquearía eternamente. Como en el caso 1, el sistema podría terminar P o bien avisarle que Q ya termino.
b) Mensajes perdidos
Un mensaje del proceso P al proceso Q podría perderse en la red de comunicación, a causa de un fallo de hardware o de la línea de comunicaciones. Hay tres métodos básicos para enfrentar este suceso:
1. El sistema operativo tiene la obligación de detectar este suceso y retransmitir el mensaje.
2. El proceso emisor tiene la obligación de detectar este suceso y retransmitir el mensaje, si desea hacerlo.
3. El sistema operativo tiene la obligación de detectar este suceso; luego avisa al proceso emisor que el mensaje se perdió. El proceso emisor decide que quiere hacer.
No siempre es necesario detectar los mensajes perdidos. De hecho, algunos protocolos de red especifican que los mensajes no son confiables, mientras que otros garantizan la confiabilidad. El usuario debe especificar (esto es, notificar al sistema, o bien programar este requisito el mismo) que debe realizarse tal detección.
¿Cómo detectamos la pérdida de un mensaje? El método de detección más común es emplear tiempos límite o plazos. Cuando se envía un mensaje, siempre se devuelve un mensaje de respuesta para confirmar la recepción del mensaje. El sistema operativo o un proceso pueden entonces especificar un intervalo de tiempo durante el cual esperara la llegada del mensaje de acuse de recibo. Si se vence este plazo antes de que llegue la confirmación, el sistema operativo (o el proceso) podrá suponer que el mensaje se perdió y volverá a enviarlo. Sin embargo, es posible que no se haya perdido el mensaje, y solo haya tardado un poco más de lo esperado en viajar por la red. En este caso, podríamos tener múltiples copias del mismo mensaje viajando por la red. Debe haber un mecanismo para distinguir entre los diferentes tipos de mensajes.
c) Mensajes alterados
El mensaje podría llegar a su destino, pero sufrir alteraciones en el camino (por ejemplo, a causa de ruido en el canal de comunicación). Este caso es similar al de un mensaje perdido. Por lo regular, el sistema operativo retransmitirá el mensaje original. Es común el uso de códigos de verificación de errores (como las sumas de verificación, paridad y CRC) para detectar este tipo de errores.
5. Resumen
Un proceso es un programa en ejecución. Mientras un proceso se ejecuta, cambia de estado. El estado de u n proceso lo define su actividad actual. Un proceso puede estar en uno de los siguientes estados: nuevo, listo, en ejecución, en espera o terminado. Cada proceso se representa en el sistema operativo con su propio bloque de control de proceso (PCB).
Si un proceso no se está ejecutando, se coloca en alguna cola de espera. Hay dos clases principales de colas en un sistema operativo: colas de solicitud de E/S y la cola de procesos listos. Esta última contiene todos los procesos que están listos para ejecutarse y están esperando la CPU. Cada proceso se representa con un PCB, y los PCB se pueden enlazar para formar una cola de procesos listos. La planificación a largo plazo (de trabajos) es la selección de los procesos a los que se les permitirá competir por la CPU.
Normalmente, la planificación a largo plazo depende en gran medida de las consideraciones de asignación de recursos, sobre todo la gestión de memoria. La planificación a corto plazo (de CPU) es la selección de un proceso de la cola de procesos listos. Los procesos del sistema se pueden ejecutar de forma concurrente. Hay varias razones para permitir la ejecución concurrente: compartir información, aceleración de los cálculos, modularidad y comodidad. La ejecución concurrente requiere un mecanismo para crear y eliminar procesos. Los procesos que se ejecutan en el sistema operativo pueden ser independientes o cooperativos. Los procesos cooperativos deben poder comunicarse entre si. En general, hay dos esquemas de comunicación complementarios: memoria compartida y sistemas de mensajes. El método de memoria compartida requiere que los procesos en comunicación compartan ciertas variables. Se espera que los procesos intercambien información empleando dichas variables. En un sistema de memoria compartida, la obligación de proveer la comunicación corresponde a los programadores de aplicaciones; el sistema operativo solo tiene que proporcionar la memoria compartida. El método de sistema de mensajes permite a los procesos intercambiar mensajes. En este caso la obligación de proveer la comunicación corresponde al sistema operativo. Estos dos esquemas no son mutuamente exclusivos, y podrían utilizarse simultáneamente en un mismo sistema operativo.
Los procesos cooperativos que comparten directamente un espacio de direcciones lógico se pueden implementar como procesos ligeros o hilos. Un hilo es una unidad básica de utilización de la CPU, y comparte con otros hilos pares su sección de código, sección de datos y recursos del sistema operativo, que colectivamente reciben el nombre de tarea. Una tarea no hace nada si no contiene hilos, y un hilo debe estar en una y solo una tarea. El alto grado de compartimiento hace que la conmutación de la CPU entre hilos pares, y la creación de hilos, tengan un costo bajo en comparación con la conmutación de contexto entre procesos pesados.
No hay comentarios:
Publicar un comentario