Está en la página 1de 20

2.1. Concepto de proceso.

Un proceso no es más que un conjunto de threads(hilos) que ejecutan el mismo código, junto con
las zonas de memoria asociadas a ellos y los ficheros que tienen abiertos.

Un programa consta, al menos, de un proceso, y de un thread. Cuando un programa tiene varios


procesos, lo normal es que cada uno ejecute un código distinto, los cuales se encuentran en
ficheros ejecutables separados. Dos procesos solo pueden compartir una zona de memoria si esta
es definida expresamente como tal. Así mismo, es en este caso cuando los sistemas de
sincronización a la hora de compartir memoria (de los que hablaremos más adelante) se vuelven
especialmente necesarios e importantes.

2.2. Estados y transiciones de los procesos.

Estados.

Durante su vida, un proceso puede pasar por una serie de estados discretos, algunos de ellos son:

En ejecución: El proceso ocupa la CPU actualmente, es decir, se está ejecutando.

Listo o preparado: El proceso dispone de todos los recursos para su ejecución, sólo le falta la CPU.

Bloqueado: Al proceso le falta algún recurso para poder seguir ejecutándose, además de la CPU.
Por recurso se pueden entender un dispositivo, un dato, etc. El proceso necesita que ocurra algún
evento que le permita poder proseguir su ejecución.

Hay otros estados de los procesos, pero en la presente exposición se tratarán estos tres. Por
sencillez, se considera un sistema con una sola CPU, aunque no es difícil la extensión a múltiples
procesadores. Solamente puede haber un proceso en ejecución a la vez, pero pueden existir varios
listos y varios pueden estar bloqueados. Así pues, se forman una lista de procesos listos y otra de
procesos bloqueados. La lista de procesos listos se ordena por prioridad, de manera que el
siguiente proceso que reciba la CPU será el primero de la lista. La lista de procesos bloqueados
normalmente no está ordenada; los procesos no se desbloquean (es decir, no pasan a ser procesos
listos) en orden de prioridad, sino que lo hacen en el orden de ocurrencia de los eventos que están
esperando. Como se verá más adelante, hay situaciones en las cuales varios procesos pueden
bloquearse esperando la ocurrencia del mismo evento; en tales casos es común asignar
prioridades a los procesos que esperan.

 Transiciones de estado de los procesos

A continuación se dan ejemplos de eventos que pueden provocar transiciones de estado en un


proceso en este modelo de tres estados. 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 Procesos ligeros (Hilos o hebras).

El concepto de proceso es más complejo y sutil que el presentado hasta ahora. Engloba dos
conceptos separados y potencialmente independientes: uno relativo a la propiedad de recursos y
otro que hace referencia a la ejecución.

Unidad que posee recursos: A un proceso se le asigna un espacio de memoria y, de tanto en tanto,
se le puede asignar otros recursos como dispositivos de E/S o ficheros.

Unidad a la que se le asigna el procesador: Un proceso es un flujo de ejecución (una traza) a través
de uno o más programas. Esta ejecución se entremezcla con la de otros procesos. De tal forma,
que un proceso tiene un estado (en ejecución, listo, etc) y una prioridad de expedición u origen. La
unidad planificada y expedida por el sistema operativo es el proceso.

En la mayoría de los sistemas operativos, estas dos características son, de hecho, la esencia de un
proceso. Sin embargo, son independientes, y pueden ser tratadas como tales por el sistema
operativo. Esta distinción ha conducido en los sistemas operativos actuales a desarrollar la
construcción conocida como thread, cuyas traducciones más frecuentes son hilo, hebra y proceso
ligero. Si se tiene esta división de características, la unidad de asignación de la CPU se conoce
como hilo, mientras que a la unidad que posee recursos se le llama proceso.

Dentro de un proceso puede haber uno o más hilos de control cada uno con:

Un estado de ejecución (en ejecución, listo, bloqueado).

Un contexto de procesador, que se salva cuando no esté ejecutándose.

Una pila de ejecución.

Algún almacenamiento estático para variables locales.

Acceso a la memoria y a los recursos de ese trabajo que comparte con los otros hilos.
Los beneficios clave de los hilos se derivan de las implicaciones del rendimiento: se tarda menos
tiempo en crear un nuevo hilo de un proceso que ya existe, en terminarlo, y en hacer un cambio
de contexto entre hilos de un mismo proceso. Al someter a un mismo proceso a varios flujos de
ejecución se mantiene una única copia en memoria del código, y no varias.

Un ejemplo de aplicación que podría hacer uso de los hilos es un servidor de ficheros de una red
de área local. Cada vez que llega una solicitud de una operación sobre un fichero, se puede
generar un nuevo hilo para su gestión. El servidor gestiona multitud de solicitudes, por tanto, se
pueden crear y destruir muchos hilos en poco tiempo para dar servicio a estas peticiones. Si el
servidor es un multiprocesador, se pueden ejecutar varios hilos de un mismo proceso
simultáneamente y en diferentes procesadores.

2.4 Concurrencia y secuenciabilidad.

Concepto de Concurrencia.

La concurrencia comprende un gran número de cuestiones de diseño, incluyendo la comunicación


entre procesos, comparición y competencia por los recursos, sincronización de la ejecución de
varios procesos y asignación del tiempo de procesador a los procesos y es fundamental para que
existan diseños como Multiprogramación, Multiproceso y Proceso distribuido.

Los procesos son concurrentes si existen simultáneamente. Cuando dos o más procesos llegan al
mismo tiempo a ejecutarse, se dice que se ha presentado una concurrencia de procesos. Es
importante mencionar que para que dos o más procesos sean concurrentes, es necesario que
tengan alguna relación entre ellos La concurrencia puede presentarse en tres contextos
diferentes:

Varias aplicaciones: La multiprogramación se creó para permitir que el tiempo de procesador de la


máquina fuese compartido dinámicamente entre varios trabajos o aplicaciones activas.

Aplicaciones estructuradas: Como ampliación de los principios del diseño modular y la


programación estructurada, algunas aplicaciones pueden implementarse eficazmente como un
conjunto de procesos concurrentes.

Estructura del sistema operativo: Las mismas ventajas de estructuración son aplicables a los
programadores de sistemas y se ha comprobado que algunos sistemas operativos están
implementados como un conjunto de procesos. Existen tres modelos de computadora en los que
se pueden ejecutar procesos concurrentes:

Multiprogramación con un único procesador. El sistema operativo se encarga de ir repartiendo el


tiempo del procesador entre los distintos procesos, intercalando la ejecución de los mismos para
dar así una apariencia de ejecución simultánea.
Multiprocesador. Es una maquina formada por un conjunto de procesadores que comparten
memoria principal. En este tipo de arquitecturas, los procesos concurrentes no sólo pueden
intercalar su ejecución sino también superponerla.

Multicomputadora. Es una maquina de memoria distribuida, que está formada por una serie de
computadoras. En este tipo de arquitecturas también es posible la ejecución simultánea de los
procesos sobre los diferentes procesadores

En general, la concurrencia será aparente siempre que el número de procesos sea mayor que el de
procesadores disponibles, es decir, cuando haya más de un proceso por procesador. La
concurrencia será real cuando haya un proceso por procesador. Aunque puede parecer que la
intercalación y la superposición de la ejecución de procesos presentan formas de ejecución
distintas, se verá que ambas pueden contemplase como ejemplos de procesos concurrentes.

Existen diversas razones que motivan la ejecución de procesos concurrentes en un sistema:

Facilita la programación de aplicaciones al permitir que éstas se estructuren como un conjunto de


procesos que cooperan entre sí para alcanzar un objetivo común.

Acelera los cálculos. Si se quiere que una tarea se ejecute con mayor rapidez, lo que se puede
hacer es dividirla en procesos, cada uno de los cuales se ejecuta en paralelo con los demás.

Posibilita el uso interactivo a múltiples usuarios que trabajan de forma simultánea.

Permite un mejor aprovechamiento de los recursos, en especial de la CPU, ya que pueden


aprovechar las fases de entrada-salida de unos procesos para realizar las fases de procesamiento
de otros.

Así como existen las razones que motivan la ejecución de procesos concurrentes, también existen
sus contras:

Inanición e interrupción de procesos.

Ocurrencia de bloqueos.

Que dos o mas procesos requieran el mismo recurso (No apropiativo) 

Tipos de procesos concurrentes.

Los procesos que ejecutan de forma concurrente en un sistema se pueden clasificar como:

Proceso independiente: Es aquel que ejecuta sin requerir la ayuda o cooperación de otros
procesos. Un claro ejemplo de procesos independientes son los diferentes shells que se ejecutan
de forma simultánea en un sistema.
Procesos son cooperantes: Son aquellos que están diseñados para trabajar conjuntamente en
alguna actividad, para lo que deben ser capaces de comunicarse e interactuar entre ellos.

En ambos tipos de procesos (independientes y cooperantes), puede producirse una serie de


interacciones entre ellos y pueden ser de dos tipos:

Interacciones motivadas porque los procesos comparten o compiten por el acceso a recursos
físicos o lógicos. Por ejemplo, dos procesos independientes compiten por el acceso a disco o para
modificar una base de datos.

Interacción motivada porque los procesos se comunican y sincronizan entre sí para alcanzar un
objetivo común, Por ejemplo, un compilador que tiene varios procesos que trabajan
conjuntamente para obtener un solo archivo de salida.

Elementos a gestionar y diseñar a causa de la concurrencia.

Se pueden enumerar los siguientes:

El sistema operativo debe ser capaz de seguir la pista de los distintos procesos activos. Esto lo hace
por medio de PBC’s (Bloque de Control de Procesos).

El sistema operativo debe asignar y quitar los distintos recursos a cada proceso activo. Entre estos
recursos se incluyen:

Tiempo de procesador: Es función de la planificación.

Memoria: La mayoría de los sistemas operativos emplean esquemas de memoria virtual.

Archivos.

Dispositivos de E/S.

El sistema operativo debe proteger los datos y los recursos físicos de cada proceso contra
injerencias no intencionadas de otros procesos.

Los resultados de un proceso deben ser independientes de la velocidad relativa a la que se realiza
la ejecución con respecto a otros procesos concurrentes.

Cuando dos o mas procesos llegan al mismo tiempo a ejecutarse, se dice que se ha presentado una
concurrencia de procesos. Es importante mencionar que para que dos o mas procesos sean
concurrentes , es necesario que tengan alguna relaciones entre ellos como puede ser la
cooperaciion para un determinado trabajo o el uso de informacion y recursos compartidos, por
ejemplo: en un sistema de un procesador , la multiprogramaciion es una condicion necesaria pero
no suficiente para que exista concurrencia, ya que los procesos pueden ejecutarse de forma
totalmente independiente.

Por otro lado en un sistema de varios procesos se puede presentar la concurrencia siempre y
cuando las actividades necesiten actuar entre ellos sea para utilizar informacion como para
cualquier otra cosa.

2.4.1 Exclusión mutua de secciones criticas.


Exclusión mutua.

La exlcusión mutua la podríamos definir como una operación de control que permite la
coordinación de procesos concurrentes, y que tiene la capacidad de prohibir a los demás procesos
realizar una acción cuando un proceso haya obtenido el permiso.

El control de la competencia involucra al sistema operativo inevitablemente, porque es el sistema


operativo el que asigna los recursos. Además, los procesos deben ser capaces por sí mismos de
expresar de algún modo los requisitos de exclusión mutua, como puede ser bloqueando los
recursos antes de usarlos.

Hacer que se cumpla la exclusión mutua crea dos problemas de control adicionales.

Interbloqueo. Si se tienen dos procesos P1 y P2 y dos recursos críticos, R1 y R2. Supóngase que
cada proceso necesita acceder a ambos recursos para llevar a cabo una parte de su función. En tal
caso, es posible que se presente la siguiente situación: el sistema operativo asigna R1 a P2 y R2 a
P1. Cada proceso está esperando a uno de los dos recursos. Ninguno liberará el recurso que ya
posee hasta que adquiera el otro y ejecute su sección crítica. Ambos procesos están
ínterbloqueados.

Inanición. Supóngase que tres procesos, P1, P2 y P3, necesitan acceder periódicamente al recurso
R. Considérese la situación en la que P1 está en posesión del recurso y tanto P2 como P3 están
parados, esperando al recurso. Cuando P1 abandona su sección crítica, tanto P2 como P3 deben
poder acceder a R. Supóngase que se le concede el acceso a P3 y que, antes de que termine su
sección crítica, P1 solicita acceso de nuevo. Si se le concede el acceso a P1 después de que P3
termine y si P1 y P3 se conceden el acceso repetidamente el uno al otro, se puede negar
definidamente a P2 el acceso al recurso.

 Requisitos para la exclusión mutua.

El uso adecuado de la concurrencia entre procesos exige la capacidad de definir secciones críticas
y hacer cumplir la exclusión mutua. Esto es fundamental para cualquier esquema de proceso
concurrente. Cualquier servicio o capacidad que dé soporte para la exclusión mutua debe cumplir
los requisitos siguientes:
Debe cumplirse la exclusión mutua: Solo un proceso, de entre todos los que poseen secciones
críticas por el mismo recurso u objeto compartido, debe tener permiso para entrar en ella en un
instante dado.

Un proceso que se interrumpe en una sección no crítica debe hacerlo sin estorbar a los otros
procesos.

Un proceso no debe poder solicitar acceso a una sección crítica para después ser demorado
indefinidamente; no puede permitirse el interbloqueo o la inanición.

Cuando ningún proceso está en su sección crítica, cualquier proceso que solicite entrar en la suya
debe poder hacerlo sin dilación.

No se pueden hacer suposiciones sobre la velocidad relativa de los procesos o su número.

Un proceso permanece en su sección crítica solo por un tiempo finito.

 Soluciones a la exclusión mutua

Hay varias formas de satisfacer los requisitos de exclusión mutua:

Soluciones por Software. Una manera es dejar la responsabilidad a los procesos que deseen
ejecutar concurrentemente, de esta manera los procesos deben coordinarse unos con otros para
cumplir la exclusión mutua sin ayuda alguna, aunque estas soluciones son propensas a errores y a
una fuerte carga de proceso (Algunos ejemplos de estas son: Algoritmo de Dekker y Algoritmo de
Peterson).

Soluciones por Hardware. Propone el uso de instrucciones de la máquina a tal efecto, estas tienen
la ventaja de reducir la sobrecarga. 
El tercer método consiste en dar algún tipo de soporte en el sistema operativo, entre estos
métodos se encuentran los semaforos, monitores, paso de mensajes, etc.

4.2 Sincronización de procesos en S.C.


Uno de los módulos más importantes de un sistema operativo es la de administrar los procesos y
tareas del sistema de cómputo. En esta sección se revisarán dos temas que componen o
conciernen a este módulo: la planificación del procesador y los problemas de concurrencia.

Planificación del procesador

La planificación del procesador se refiere a la manera o técnicas que se usan para decidir cuánto
tiempo de ejecución y cuando se le asignan a cada proceso del sistema. Obviamente, si el sistema
es monousuario y monotarea nohay mucho que decidir, pero en el resto de los sistemas esto es
crucial para el buen funcionamiento del sistema.

Niveles de planificación
En los sistemas de planificación generalmente se identifican tres niveles: el alto, em medio y el
bajo. El nivel alto decide que trabajos (conjunto de procesos) son candidatos a convertirse en
procesos compitiendo por los recursos del sistema; el nivel intermedio decide que procesos se
suspenden o reanudan para lograr ciertas metas de rendimiento mientras que el planificador de
bajo nivel es el que decide que proceso, de los que ya están listos (y que en algún momento paso
por los otros dos planificadores) es al que le toca ahora estar ejecutándose en la unidad central de
procesamiento. En este trabajo se revisaran principalmente los planificadores de bajo nivel porque
son los que finalmente eligen al proceso en ejecución.

Objetivos de la planificación

Una estrategia de planificación debe buscar que los procesos obtengan sus turnos de ejecución
apropiadamente, conjuntamente con un buen rendimiento y minimización de la sobrecarga
(overhead) del planificador mismo. En general, se buscan cinco objetivos principales:

Justicia o Imparcialidad: Todos los procesos son tratados de la misma forma, y en algún momento
obtienen su turno de ejecución o intervalos de tiempo de ejecución hasta su terminación exitosa.

Maximizar la Producción: El sistema debe de finalizar el mayor numero de procesos en por unidad
de tiempo.

Maximizar el Tiempo de Respuesta: Cada usuario o proceso debe observar que el sistema les
responde consistentemente a sus requerimientos.

Evitar el aplazamiento indefinido: Los procesos deben terminar en un plazo finito de tiempo.

El sistema debe ser predecible: Ante cargas de trabajo ligeras el sistema debe responder rápido y
con cargas pesadas debe ir degradándose paulatinamente. Otro punto de vista de esto es que si se
ejecuta el mismo proceso en cargas similares de todo el sistema, la respuesta en todos los casos
debe ser similar.

Características a considerar de los procesos

No todos los equipos de cómputo procesan el mismo tipo de trabajos, y un algoritmo de


planificación que en un sistema funciona excelente puede dar un rendimiento pésimo en otro
cuyos procesos tienen características diferentes. Estas características pueden ser:

Cantidad de Entrada/Salida: Existen procesos que realizan una gran cantidad de operaciones de
entrada y salida (aplicaciones de bases de datos, por ejemplo).

Cantidad de Uso de CPU: Existen procesos que no realizan muchas operaciones de entrada y
salida, sino que usan intensivamente la unidad central de procesamiento. Por ejemplo,
operaciones con matrices.

Procesos de Lote o Interactivos: Un proceso de lote es más eficiente en cuanto a la lectura de


datos, ya que generalmente lo hace de archivos, mientras que un programa interactivo espera
mucho tiempo (no es lo mismo el tiempo de lectura de un archivo que la velocidad en que una
persona teclea datos) por las respuestas de los usuarios.

Procesos en Tiempo Real: Si los procesos deben dar respuesta en tiempo real se requiere que
tengan prioridad para los turnos de ejecución.

Longevidad de los Procesos: Existen procesos que típicamente requerirán varias horas para
finalizar su labor, mientras que existen otros que solo necesitan algunos segundos.

Planificación apropiativa o no apropiativa (preemptive or not preemptive)

La planificación apropiativa es aquella en la cual, una vez que a un proceso le toca su turno de
ejecución ya no puede ser suspendido, ya no se le puede arrebatar la unidad central de
procesamiento. Este esquema puede ser peligroso, ya que si el proceso contiene accidental o
deliberadamente ciclos infinitos, el resto de los procesos pueden quedar aplazados
indefinidamente. Una planificación no apropiativa es aquella en que existe un reloj que lanza
interrupciones periodicas en las cuales el planificador toma el control y se decide si el mismo
proceso seguirá ejecutándose o se le da su turno a otro proceso. Este mismo reloj puede servir
para lanzar procesos manejados por el reloj del sistema. Por ejemplo en los sistemas UNIX existen
los 'cronjobs' y 'atjobs', los cuales se programan en base a la hora, minuto, día del mes, día de la
semana y día del año.

En una planificación no apropiativa, un trabajo muy grande aplaza mucho a uno pequeño, y si
entra un proceso de alta prioridad esté también debe esperar a que termine el proceso actual en
ejecución.

Asignación del turno de ejecución

Los algoritmos de la capa baja para asignar el turno de ejecución se describen a continuación:

Por prioridad: Los procesos de mayor prioridad se ejecutan primero. Si existen varios procesos de
mayor prioridad que otros, pero entre ellos con la misma prioridad, pueden ejecutarse estos de
acuerdo a su orden de llegada o por 'round robin'. La ventaja de este algoritmo es que es flexible
en cuanto a permitir que ciertos procesos se ejecuten primero e, incluso, por más tiempo. Su
desventaja es que puede provocar aplazamiento indefinido en los procesos de baja prioridad. Por
ejemplo, suponga que existen procesos de prioridad 20 y procesos de prioridad 10. Si durante
todo el día terminan procesos de prioridad 20 al mismo ritmo que entran otros con esa prioridad,
el efecto es que los de prioridad 10 estarán esperando por siempre. También provoca que el
sistema sea impredecible para los procesos de baja prioridad.

El trabajo más corto primero: Es dificil de llevar a cabo porque se requiere saber o tener una
estimación de cuánto tiempo necesita el proceso para terminar. Pero si se sabe, se ejecutan
primero aquellos trabajos que necesitan menos tiempo y de esta manera se obtiene el mejor
tiempo de respuesta promedio para todos los procesos. Por ejemplo, si llegan 5 procesos A,B,C,D y
E cuyos tiempos de CPU son 26, 18, 24, 12 y 4 unidades de tiempo, se observa que el orden de
ejecución será E,D,B,C y A (4,12,18, 24 y 26 unidades de tiempo respectivamente). En la tabla
siguiente se muestra en que unidad de tiempo comienza a ejecutarse cada proceso y como todos
comenzaron a esperar desde la unidad cero, se obtiene el tiempo promedio de espera.

Proceso Espera desde Termina Tiempo de Espera

A044

B 0 16 16

C 0 34 34

D 0 58 58

E 0 84 84

Tiempo promedio = (4 + 16 + 34 + 58 + 84 )/5 = 39 unidades.

El primero en llegar, primero en ejecutarse: Es muy simple, los procesos reciben su turno
conforme llegan. La ventaja de este algoritmo es que es justo y no provoca aplazamiento
indefinido. La desventaja es que no aprovecha ninguna característica de los procesos y puede no
servir para unproceso de tiempo real. Por ejemplo, el tiempo promedio de respuesta puede ser
muy malo comparado con el logrado por el del trabajo más corto primero. Retomando el mismo
ejemplo que en el algoritmo anterior, obtenemos un tiempo de respuesta promedio
(26+44+68+80+84)/5 = 60 unidades, el cual es muy superior a las 39 unidades que es el mejor
tiempo posible.

Round Robin: También llamada por turno, consiste en darle a cada proceso un intervalo de tiempo
de ejecución (llamado time slice), y cada vez que se vence ese intervalo se copia el contexto del
proceso a un lugar seguro y se le da su turno a otro proceso. Los procesos están ordenados en una
cola circular. Por ejemplo, si existen tres procesos, el A,B y C, dos repasadas del planificador darían
sus turnos a los procesos en el orden A,B,C,A,B,C. La ventaja de este algoritmo es su simplicidad, es
justo y no provoca aplazamiento indefinido.

El tiempo restante más corto: Es parecido al del trabajo más corto primero, pero aquií se está
calculando en todo momento cuánto tiempo le resta para terminar a todos los procesos,
incluyendo los nuevos, y aquel que le quede menos tiempo para finalizar es escogido para
ejecutarse. La ventaja es que es muy útil para sistemas de tiempo compartido porque se acerca
mucho al mejor tiempo de respuesta, además de responder dinámicamente a la longevidad de los
procesos; su desventaja es que provoca más sobrecarga porque el algoritmo es más complejo.

La tasa de respuesta más alta: Este algoritmo concede el truno de ejecución al proceso que
produzca el valor mayor de la siguiente formula:

tiempo que ha esperado + tiempo total para terminar


valor = ___________________________________________

tiempo total para terminar.

Es decir, que dinámicamente el valor se va modificando y mejora un poco las deficiciencias del
algoritmo del trabajo más corto primero.

Por política: Una forma de asignar el turno de ejecución es por politica, en la cual se establece
algún reglamento específico que el planificador debe obedecer. Por ejemplo, una politica podría
ser que todos los procesos reciban el mismo tiempo de uso de CPU en cualquier momento. Esto
sig- nifica, por ejemplo, que si existen 2 procesos y han recibido 20 unidades de tiempo cada uno
(tiempo acumulado en time slices de 5 unidades) y en este momento entra un tercer proceso, el
planificador le dara inmediatamente el turno de ejecución por 20 unidades de tiempo. Una vez
que todos los procesos están 'parejos' en uso de CPU, se les aplica 'round robin'.

Problemas de Concurrencia

En los sistemas de tiempo compartido (aquellos con varios usuarios, procesos, tareas, trabajos que
reparten el uso de CPU entre estos) se presentan muchos problemas debido a que los procesos
compiten por los recursos del sistema. Imagine que un proceso está escribiendo en la unidad de
cinta y se le termina su turno de ejecución e inmediatamente después el proceso elegido para
ejecutarse comienza a escribir sobre la misma cinta. El resultado es una cinta cuyo contenido es un
desastre de datos mezclados. Así como la cinta, existen una multitud de recursos cuyo acceso
debe der controlado para evitar los problemas de la concurrencia.

El sistema operativo debe ofrecer mecanismos para sincronizar la ejecución de procesos:


semáforos, envío de mensajes, 'pipes', etc. Los semáforos son rutinas de software (que en su nivel
más interno se auxilian del hardware) para lograr exclusión mutua en el uso de recursos. Para
entender este y otros mecanismos es importante entender los problemas generales de
concurrencia, los cuales se describen enseguida.

Condiciones de Carrera o Competencia: La condición de carrera (race condition) ocurre cuando


dos o más procesos accesan un recurso compartido sin control, de manera que el resultado
combinado de este acceso depende del orden de llegada. Suponga, por ejemplo, que dos clientes
de un banco realizan cada uno una operación en cajeros diferentes al mismo tiempo.

El usuario A quiere hacer un depósito. El B un retiro. El usuario A comienza la transacción y lee su


saldo que es 1000. En ese momento pierde su turno de ejecución (y su saldo queda como 1000) y
el usuario B inicia el retiro: lee el saldo que es 1000, retira 200 y almacena el nuevo saldo que es
800 y termina. El turno de ejecución regresa al usuario A el cual hace su depósito de 100,
quedando saldo = saldo + 100 = 1000 + 100 = 1100. Como se ve, el retiro se perdió y eso le encanta
al usuario A y B, pero al banquero no le convino esta transacción. El error pudo ser al revés,
quedando el saldo final en 800.
Postergación o Aplazamiento Indefinido(a): Esto se mencionó en el apartado anterior y consiste en
el hecho de que uno o varios procesos nunca reciban el suficiente tiempo de ejecución para
terminar su tarea. Por ejemplo, que un proceso ocupe un recurso y lo marque como 'ocupado' y
que termine sin marcarlo como 'desocupado'. Si algún otro proceso pide ese recurso, lo verá
'ocupado' y esperará indefinidamente a que se 'desocupe'.

Condición de Espera Circular: Esto ocurre cuando dos o más procesos forman una cadena de
espera que los involucra a todos. Por ejemplo, suponga que el proceso A tiene asignado el recurso
'cinta' y el proceso B tiene asignado el recurso 'disco'. En ese momento al proceso A se le ocurre
pedir el recurso 'disco' y al proceso B el recurso 'cinta'. Ahi se forma una espera circular entre esos
dos procesos que se puede evitar quitándole a la fuerza un recurso a cualquiera de los dos
procesos.

Condición de No Apropiación: Esta condición no resulta precisamente de la concurrencia, pero


juega un papel importante en este ambiente. Esta condición especifica que si un proceso tiene
asignado un recurso, dicho recurso no puede arrebatársele por ningún motivo, y estará disponible
hasta que el proceso lo 'suelte' por su voluntad.

Condición de Espera Ocupada: Esta condición consiste en que un proceso pide un recurso que ya
está asignado a otro proceso y la condición de no apropiación se debe cumplir. Entonces el
proceso estará gastando el resto de su time slice checando si el recurso fue liberado. Es decir,
desperdicia su tiempo de ejecución en esperar. La solución más común a este problema consiste
en que el sistema operativo se dé cuenta de esta situación y mande a una cola de espera al
proceso, otorgándole inmediatamente el turno de ejecución a otro proceso.

Condición de Exclusión Mutua: Cuando un proceso usa un recurso del sistema realiza una serie de
operaciones sobre el recurso y después lo deja de usar. A la sección de código que usa ese recurso
se le llama 'región crítica'. La condición de exclusión mutua establece que solamente se permite a
un proceso estar dentro de la misma región crítica. Esto es, que en cualquier momento solamente
un proceso puede usar un recurso a la vez. Para lograr la exclusión mutua se ideo también el
concepto de 'región crítica'. Para logar la exclusión mutua generalmente se usan algunas técnicas
para lograr entrar a la región crítica: semáforos, monitores, el algoritmo de Dekker y Peterson, los
'candados'. Para ver una descripción de estos algoritmos consulte

Condición de Ocupar y Esperar un Recurso: Consiste en que un proceso pide un recurso y se le


asigna. Antes de soltarlo, pide otro recurso que otro proceso ya tiene asignado.

Los problemas descritos son todos importantes para el sistema operativo, ya que debe ser capaz
de prevenir o corregirlos. Tal vez el problema más serio que se puede presentar en un ambiente
de concurrencia es el 'abrazo mortal', también llamado 'trabazón' y en inglés deadlock. El deadlock
es una condición que ningún sistema o conjunto de procesos quisiera exhibir, ya que consiste en
que se presentan al mismo tiempo cuatro condiciones necesarias: La condición de no apropiación,
la condición de espera circular, la condición de exclusión mutua y la condición de ocupar y esperar
un recurso. Ante esto, si el deadlock involucra a todos los procesos del sistema, el sistema ya no
podrá hacer algo productivo. Si el deadlock involucra algunos procesos, éstos quedarán
congelados para siempre.

En el área de la informática, el problema del deadlock ha provocado y producido una serie de


estudios y técnicas muy útiles, ya que éste puede surgir en una sola máquina o como consecuencia
de compartir recursos en una red.

En el área de las bases de datos y sistemas distribuidos han surgido técnicas como el 'two phase
locking' y el 'two phase commit' que van más allá de este trabajo. Sin embargo, el interés principal
sobre este problema se centra en generar técnicas para detectar, prevenir o corregir el deadlock.

Las técnicas para prevenir el deadlock consisten en proveer mecanismos para evitar que se
presente una o varias de las cuatro condiciones necesarias del deadlock. Algunas de ellas son:

Asignar recursos en orden lineal: Esto significa que todos los recursos están etiquetados con un
valor diferente y los procesos solo pueden hacer peticiones de recursos 'hacia adelante'. Esto es,
que si un proceso tiene el recurso con etiqueta '5' no puede pedir recursos cuya etiqueta sea
menor que '5'. Con esto se evita la condición de ocupar y esperar un recurso.

Asignar todo o nada: Este mecanismo consiste en que el proceso pida todos los recursos que va a
necesitar de una vez y el sistema se los da solamente si puede dárselos todos, si no, no le da nada
y lo bloquea.

Algoritmo del banquero: Este algoritmo usa una tabla de recursos para saber cuántos recursos
tiene de todo tipo. También requiere que los procesos informen del máximo de recursos que va a
usar de cada tipo. Cuando un proceso pide un recurso, el algoritmo verifica si asignándole ese
recurso todavía le quedan otros del mismo tipo para que alguno de los procesos en el sistema
todavía se le pueda dar hasta su máximo. Si la respuesta es afirmativa, el sistema se dice que está
en 'estado seguro' y se otorga el recurso. Si la respuesta es negativa, se dice que el sistema está en
estado inseguro y se hace esperar a ese proceso.

Para detectar un deadlock, se puede usar el mismo algoritmo del banquero, que aunque no dice
que hay un deadlock, sí dice cuándo se está en estado inseguro que es la antesala del deadlock. Sin
embargo, para detectar el deadlock se pueden usar las 'gráficas de recursos'. En ellas se pueden
usar cuadrados para indicar procesos y círculos para los recursos, y flechas para indicar si un
recurso ya está asignado a un proceso o si un proceso está esperando un recurso. El deadlock es
detectado cuando se puede hacer un viaje de ida y vuelta desde un proceso o recurso. Por
ejemplo, suponga los siguientes eventos:

evento 1: Proceso A pide recurso 1 y se le asigna.

evento 2: Proceso A termina su time slice.

evento 3: Proceso B pide recurso 2 y se le asigna.

evento 4: Proceso B termina su time slice.


evento 5: Proceso C pide recurso 3 y se le asigna.

evento 6: Proceso C pide recurso 1 y como lo está ocupando el proceso A, espera.

evento 7: Proceso B pide recurso 3 y se bloquea porque lo ocupa el proceso C.

evento 8: Proceso A pide recurso 2 y se bloquea porque lo ocupa el proceso B.

En la figura 5.1 se observa como el 'resource graph' fue evolucionando hasta que se presentó el
deadlock, el cual significa que se puede viajar por las flechas desde un proceso o recurso hasta
regresar al punto de partida. En el deadlock están involucrados los procesos A,B y C.

Una vez que un deadlock se detecta, es obvio que el sistema está en problemas y lo único que
resta por hacer es una de dos cosas: tener algún mecanismo de suspensión o reanudación
[Deitel93] que permita copiar todo el contexto de un proceso incluyendo valores de memoria y
aspecto de los periféricos que esté usando para reanudarlo otro día, o simplemente eliminar un
proceso o arrebatarle el recurso, causando para ese proceso la pérdida de datos y tiempo.

2.4.2.1 Mecanismo de semáforos.

Sincronización por Semáforos.

En 1965, E.W. Dijkstra sugirió el uso de una variable entera para contar el número de despertares
almacenados para su uso posterior.

En su propuesta se presentó un nuevo tipo de variable, llamada Semáforo. Un semáforo puede


tener el valor 0, lo que indica que no existen despertares almacenados; o bien algún valor positivo
si están pendientes uno o más despertares.

Dijkstra, propuso dos operaciones, DOWN y UP (generalizaciones de SLEEP y WAKEUP,


respectivamente). La operación Down verifica si el valor de un semáforo es mayor que 0. En este
caso, decrementa el valor (es decir, utiliza un despertar almacenado) y continúa. Si el valor es cero,
el proceso se va a dormir. La verificación y modificación del valor, así como la posibilidad de irse a
dormir se realiza en conjunto, como una sola e indivisible acción atómica. Se garantiza que al
iniciar una operación con un semáforo, ningún otro proceso puede tener acceso a semáforo hasta
que la operación termine o se bloquee. Esta atomicidad es absolutamente esencial para resolver
los problemas de sincronización y evitar condiciones de competencia.

La operación UP incrementa el valor del semáforo correspondiente. Si uno o más procesos


dormían en ese semáforo y no podían completar una operación Down anterior, el sistema elige
alguno de ellos (por ejemplo, en forma aleatoria) y se le permite terminar Down. Así, después de
un UP en un semáforo con procesos durmiendo, el semáforo seguirá con valor cero, pero habrá un
menor número de procesos durmiendo. La operación de incremento del semáforo y despertar de
un proceso también es indivisible. Ningún proceso llega a bloquear mediante un UP. 
Un semáforo es una variable protegida, cuyo valor sólo puede ser leído y alterado mediante las
operaciones P y V, y una operación de asignación de valores iniciales y (Inicia semáforo).
 

Tipos de Semáforos.

Semáforos Binarios (Valores de 1,0)

Semáforos Contadores (Valores enteros no negativos)

Operación P (Sobre el semáforo S)

si S>0 
entonces S:=S-1; 
sino (esperar S)

Operación V (Sobre el semáforo S) 


si (Uno o más procesos esperan S) 
entonces (dejar que prosiga uno de esos procesos) 
sino S:=S+1

La exclusión mutua sobre el semáforo S se implanta dentro de P(S) y V(S). Si varios procesos
desean ejecutar una operación P(S) de manera simultánea , sólo se podrá ejecutar uno de ellos,
pero esto no quiere decir que se aplazarán en forma indefinida.

2.4.3 Interbloqueo (DeadLock).

El interbloqueo puede definirse formalmente como sigue: Un conjunto de procesos está en


interbloqueo si cada proceso del conjunto está esperando un evento que sólo otro proceso del
conjunto puede causar. Puesto que todos los procesos están esperando, ninguno de ellos puede
causar ninguno de los eventos que podrían despertar a cualquiera de los demás miembros del
conjunto, y todos los procesos continúan esperando indefinidamente.

Tipos de recursos

Se pueden distinguir dos categorías generales de recursos: reutilizables y consumibles.

Reutilizables

Un recurso reutilizable es aquél que puede ser usado con seguridad por un proceso y no se agota
con el uso. Los procesos obtienen unidades de recursos que liberan posteriormente para que otros
procesos las reutilicen. Como ejemplos de recursos reutilizables se tienen los procesadores,
canales de E/S, memoria principal y secundaria, dispositivos y estructuras de datos tales como
archivos, bases de datos y semáforos.

Consumibles
Un recurso consumible es aquél que puede ser creado (producido) y destruido (consumido).
Normalmente, no hay límite en el número de recursos consumibles de un tipo en particular. Un
proceso productor que no está bloqueado puede liberar cualquier número de recursos
consumibles. Cuando un proceso adquiere un recurso, éste deja de existir. Como ejemplos de
recursos consumibles están las interrupciones, señales, mensajes, e información en buffers de E/S.

Condiciones para el interbloqueo.

Coffman (1971) demostró que deben cumplirse cuatro condiciones para que haya un bloqueo
mutuo:

Condición de exclusión mutua. Cada recurso está asignado únicamente a un solo proceso o está
disponible.

Condición de retener y esperar.Los procesos que actualmente tienen recursos que les fueron
otorgados previamente.

    pueden solicitar nuevos recursos.

3. Condición de no expropiación. No es posible quitarle por la fuerza a un proceso los recursos que
le fueron

    otorgados previamente. El proceso que los tiene debe liberarlos explícitamente.

4. Condición de espera circular. Debe haber una cadena circular de dos o más procesos, cada uno
de los cuales está

    esperando un recurso retenido por el siguiente miembro de la cadena.

Deben estar presentes estas cuatro condiciones para que ocurra un bloqueo mutuo. Si una o más
de estas condiciones está ausente, no puede haber bloqueo mutuo.

Prevención

La estrategia de prevención del interbloqueo consiste, a grandes rasgos, en diseñar un sistema de


manera que esté excluida, a priori, la posibilidad de interbloqueo. Los métodos para prevenir el
interbloqueo son de dos tipos. Los métodos indirectos consisten en impedir la aparición de alguna
de las tres condiciones necesarias, antes mencionadas (condiciones 1 a 3). Los métodos directos
consisten en evitar la aparición del círculo vicioso de espera (condición 4). Se examinarán a
continuación las técnicas relacionadas con cada una de las cuatro condiciones.

Exclusión Mutua
En general, la primera de las cuatro condiciones no puede anularse. Si el acceso a un recurso
necesita exclusión mutua, el sistema operativo debe soportar la exclusión mutua. Algunos
recursos, como los archivos, pueden permitir varios accesos para lectura, pero sólo accesos
exclusivos para escritura. Incluso en este caso, se puede producir interbloqueo si más de un
proceso necesita permiso de escritura.

Retención y Espera

La condición de retención y espera puede prevenirse exigiendo que todos los procesos soliciten
todos los recursos que necesiten a un mismo tiempo y bloqueando el proceso hasta que todos los
recursos puedan concederse simultáneamente. Esta solución resulta ineficiente por dos factores.
En primer lugar, un proceso puede estar suspendido durante mucho tiempo, esperando que se
concedan todas sus solicitudes de recursos, cuando de hecho podría haber avanzado con sólo
algunos de los recursos. Y en segundo lugar, los recursos asignados a un proceso pueden
permanecer sin usarse durante periodos considerables, tiempo durante el cual se priva del acceso
a otros procesos.

No apropiación (no expropiación)

La condición de no apropiación puede prevenirse de varias formas. Primero, si a un proceso que


retiene ciertos recursos se le deniega una nueva solicitud, dicho proceso deberá liberar sus
recursos anteriores y solicitarlos de nuevo, cuando sea necesario, junto con el recurso adicional.
Por otra parte, si un proceso solicita un recurso que actualmente está retenido por otro proceso,
el sistema operativo puede expulsar al segundo proceso y exigirle que libere sus recursos. Este
último esquema evitará el interbloqueo sólo si no hay dos procesos que posean la misma
prioridad. Esta técnica es práctica sólo cuando se aplica a recursos cuyo estado puede salvarse y
restaurarse más tarde de una forma fácil, como es el caso de un 
procesador.

Círculo Vicioso de Espera

La condición del círculo vicioso de espera puede prevenirse definiendo una ordenación lineal de
los tipos de recursos. Si a un proceso se le han asignado recursos de tipo R, entonces sólo podrá
realizar peticiones posteriores sobre los recursos de los tipos siguientes a R en la ordenación. Para
comprobar el funcionamiento de esta estrategia, se asocia un índice a cada tipo de recurso. En tal
caso, el recurso R, antecede a R, en la ordenación si i < j. Entonces, supóngase que dos procesos A
y B se interbloquean, porque A ha adquirido R, y solicitado Ry, mientras que B ha adquirido R; y
solicitado R¿ Esta situación es imposible porque implica que í < j y j < i.Como en la retención y
espera, la prevención del círculo vicioso de espera puede ser ineficiente, retardando procesos y
denegando accesos a recursos
2.4.3.1 Prevención.
Prevencion Interbloqueo Dead Lock

Los bloqueos mutuos pueden ser evitados si se sabe cierta información sobre los procesos antes
de la asignación de recursos. Para cada petición de recursos, el sistema controla si satisfaciendo el
pedido entra en un estado inseguro, donde puede producirse un bloqueo mutuo. De esta forma, el
sistema satisface los pedidos de recursos solamente si se asegura que quedará en un estado
seguro. Para que el sistema sea capaz de decidir si el siguiente estado será seguro o inseguro, debe
saber por adelantado y en cualquier momento el número y tipo de todos los recursos en
existencia, disponibles y requeridos. Existen varios algoritmos para evitar bloqueos mutuos:

Algoritmo del banquero, introducido por Dijkstra.

Algoritmo de grafo de asignación de recursos.

Algoritmo de Seguridad.

Algoritmo de solicitud de recursos.

Prevención

Los bloqueos mutuos pueden prevenirse asegurando que no suceda alguna de las condiciones
necesarias vistas anteriormente.

Eliminando la exclusión mutua: ningún proceso puede tener acceso exclusivo a un recurso. Esto es
imposible para procesos que no pueden ser encolados (puestos en un spool), e incluso con colas
también pueden ocurrir interbloqueos. La condición de retención y espera puede ser eliminada
haciendo que los procesos pidan todos los recursos que van a necesitar antes de empezar. Este
conocimiento por adelantado muchas veces es imposible nuevamente. Otra forma es requerir a
los procesos liberar todos sus recursos antes de pedir todos los recursos que necesitan. Esto
también es impráctico en general.

La condición de no expropiación puede ser también imposible de eliminar dado que un proceso
debe poder tener un recurso por un cierto tiempo o el procesamiento puede quedar
inconsistente.

La condición de espera circular es la más fácil de atacar. Se le permite a un proceso poseer sólo un
recurso en un determinado momento, o una jerarquía puede ser impuesta de modo tal que los
ciclos de espera no sean posibles

2.4.3.2 Detección.

Las estrategias de prevención del interbloqueo son muy conservadoras; solucionan el problema
del interbloqueo limitando el acceso a los recursos e imponiendo restricciones a los procesos. En
el lado opuesto, las estrategias de detección del interbloqueo no limitan el acceso a los recursos ni
restringen las acciones de los procesos. Con detección del interbloqueo, se concederán los
recursos que los procesos necesiten siempre que sea posible. Periódicamente, el sistema
operativo ejecuta un algoritmo que permite detectar la condición de círculo vicioso de espera.
Puede emplearse cualquier algoritmo de detección de ciclos en grafos dirigidos.

El control del interbloqueo puede llevarse a cabo tan frecuentemente como las solicitudes de
recursos o con una frecuencia menor, dependiendo de la probabilidad de que se produzca el
interbloqueo. La comprobación en cada solicitud de recurso tiene dos ventajas: Conduce a una
pronta detección y el algoritmo es relativamente simple, puesto que está basado en cambios
increméntales del estado del sistema. Por otro lado, tal frecuencia de comprobaciones consume
un tiempo de procesador considerable.

Una vez detectado el interbloqueo, hace falta alguna estrategia de recuperación. Las técnicas
siguientes son posibles enfoques, enumeradas en orden creciente de sofisticación:

Abandonar todos los procesos bloqueados. Esta es, se crea o no, una de las soluciones más
comunes, si no la más común, de las adoptadas en un sistema operativo.

Retroceder cada proceso interbloqueado hasta algún punto de control definido previamente y
volver a ejecutar todos los procesos. Es necesario que haya disponibles unos mecanismos de
retroceso y reinicio en el sistema. El riesgo de esta solución radica en que puede repetirse el
interbloqueo original. Sin embargo, el no determinismo del procesamiento concurrente asegura,
en general, que esto no va a pasar.

Abandonar sucesivamente los procesos bloqueados hasta que deje de haber interbloqueo. El
orden en el que se seleccionan los procesos a abandonar seguirá un criterio de mínimo coste.
Después de abandonar cada proceso, se debe ejecutar de nuevo el algoritmo de detección para
ver si todavía existe interbloqueo.

Apropiarse de recursos sucesivamente hasta que deje de haber interbloqueo. Como en el punto 3,
se debe emplear una selección basada en coste y hay que ejecutar de nuevo el algoritmo de
detección después de cada apropiación. Un proceso que pierde un recurso por apropiación debe
retroceder hasta un momento anterior a la adquisición de ese recurso.

Para los puntos 3 y 4, el criterio de selección podría ser uno de los siguientes, consistentes en
escoger el proceso con:

La menor cantidad de tiempo de procesador consumido hasta ahora.


El menor número de líneas de salida producidas hasta ahora.

El mayor tiempo restante estimado.

El menor número total de recursos asignados hasta ahora.

La prioridad más baja.

Algunas de estas cantidades son más fáciles de medir que otras. El tiempo restante estimado deja
lugar a dudas, especialmente. Además, aparte de las medidas de prioridad, no existe otra
indicación del “coste” para el usuario frente al coste para el sistema en conjunto.

2.4.3.3 Recuperación.

También podría gustarte