Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
,QWURGXFFLyQ
Sabemos que la CPU realiza ciertas actividades. En un sistema de tratamiento por
lotes (EDWFK), se ejecutan trabajos; en un entorno de tiempo compartido hay
programas de usuarios, o tareas; incluso en un ordenador personal, hoy día un
usuario puede ejecutar varios programas simultáneamente, uno interactivo, y otros
en segundo plano (EDFNJURXQG. La cuestión es cómo llamar a todas estas
actividades que realiza la CPU. Pues bien, a estas actividades las denominaremos
SURFHVRV.
&RQFHSWRGH3URFHVR
Se han oído muchas definiciones de proceso, pero, sin duda, la más popular y
acertada es la que dice que “XQSURFHVRHVXQSURJUDPDHQHMHFXFLyQ”.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
,QWURGXFFLyQ &RQFHSWRGH3URFHVR
¢4XpHVXQ3URFHVR"
(VXQ3URJUDPDHQ(MHFXFLyQ
8Q3URJUDPD (VHVWiWLFR1RYDUtDQDGD
1RUHTXLHUH
1RWLHQHYHFWRUGHHVWDGR→
SURFHVDGRU
9DULDEOHVVLQYDORUHV
5XWLQDVVLQGLUHFFLyQ
&RQGLFLRQHVVLQHYDOXDU
(VHODOJRULWPRDHMHFXWDU
8Q3URFHVR (VGLQiPLFR
1HFHVLWD
7LHQHYHFWRUGHHVWDGR→
SURFHVDGRU
/DVYDULDEOHVWLHQHQYDORUHV
/DVUXWLQDVHVWiQHQDOJXQDGLUHFFLyQ
/DVFRQGLFLRQHVVHSXHGHQHYDOXDU
(VODHMHFXFLyQGHODOJRULWPR
352&(62
3URJUDPD
(VWDGR (VWDGR
3URFHVDGRU
6H 8Q&3
SRUSURFHVR
QHFHVLWD 8QiUHDGHWUDEDMR
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Al igual que para la construcción del aeromodelo se necesita un área de trabajo (una
mesa o algo similar), para la ejecución de un programa, también se requiere un área
de trabajo, esto es, ODSLODdel proceso. La pila es la zona de memoria en la que se
guardan los parámetros, variables locales, direcciones de retorno de subprogramas
y, en general, los datos temporales del proceso. Un proceso también se caracteriza
porque en un momento dado de su ejecución dispone de ciertos valores en los
registros del procesador, entre ellos, el &RQWDGRU GH 3URJUDPD que contiene la
dirección de la instrucción que va a ejecutar el proceso a continuación. Así, el
Contador de Programa es el registro que indica el punto de ejecución del programa
en el que se encuentra el proceso.
'HVFULSWRUGH3URFHVR
Como ya sabemos, en un sistema multiprogramado se pueden ejecutar
simultáneamente varios programas, es decir, en un momento dado puede haber
varios procesos. En un sistema con un único procesador no se puede decir que
haya varios programas ejecutándose estrictamente de una forma simultánea. En
realidad, la posesión del procesador se va repartiendo entre los distintos procesos,
dando lugar a una ejecución pseudoparalela. No obstante, por simplicidad, nos
referiremos, en general, a ejecución simultánea o paralela, tanto si es estricta
(sistema multiprocesador) como si no lo es (con un solo procesador).
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Como ya hemos dicho, el BCP es algo así como la ficha de control del proceso, por
esto, en él también se encuentra la información necesaria para poder acceder tanto
al contexto de memoria como al del procesador.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
,QWURGXFFLyQ 'HVFULSWRUGH3URFHVR
¢&yPR9HHO62DORV3URFHVRV"
0HGLDQWHVXYHFWRUGHHVWDGRHQXQ
'HVFULSWRUGH3URFHVR
(O'HVFULSWRUGH3URFHVRFRQWLHQHLQIRUPDFLyQ
GHO3URFHVR
GHVX0HPRULD &RQWH[WR
GHOSURFHVR
GH(VWDGRGHO3URFHVDGRU5HJLVWURV
W\SH DESCRIPTOR_PROCESO LV
UHFRUG
Id_Proceso
Siguiente
Estado
Puntero_Pila
Memoria_Utilizada
Ficheros_Abiertos
Proceso_Padre
Procesos_Hijos
Dormido_Hasta
HQGUHFRUG;
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR3DUDOHOLVPR
En la Introducción ya se vio, por encima, la utilidad de ejecutar varios programas de
forma simultánea para evitar el desaprovechamiento de los tiempos de espera de
CPU a las respuestas de los dispositivos periféricos en las operaciones de
entrada/salida que realiza un proceso.
Otra justificación de la ejecución paralela de programas viene dada por las leyes de
la física, pues según la Teoría de la Relatividad de Albert Einstein es imposible
transmitir señales eléctricas a más velocidad que la de la luz, esto es, unos 30cm
por nanosegundo. Esto quiere decir que el tiempo mínimo que puede tardar en
transmitirse una señal entre dos componentes de un ordenador separados 30cm es
1ns. O sea, que los ordenadores tendrían que empezar a fabricarse cada vez más
pequeños, pero claramente, sabemos que esto tiene ciertas limitaciones. Por otra
parte, algunos programas (cálculo científico, tiempo real, etc.) requieren, a menudo,
ciertas velocidades de ejecución, para que el resultado sea exitoso. Una forma de
conseguir que un programa se ejecute más rápidamente que ejecutando una
instrucción tras otra, consiste en dividir el programa en varias tareas o procesos y
ejecutándolos en paralelo. Un símil de la vida real puede ser el proceso de
fabricación de los automóviles. Las cadenas de montaje de los coches no fabrican
primero las ruedas, luego el motor, a continuación el chasis, después la carrocería,
luego los cristales, ...; sino que cada uno de estos elementos se fabrica por
separado de forma paralela y simultánea, y cuando están todos construidos, se
realiza el proceso de ensamblaje para formar el automóvil completo. De esta forma
se consigue construirlo en bastante menos tiempo.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR3DUDOHOLVPR
3UREOHPDVGHO3URFHVDPLHQWR6HFXHQFLDO
/DVOH\HVGHODItVLFD 1RVHDSURYHFKD
LPSRQHQOLPLWDFLRQHV
OD&38
GHYHORFLGDG
£62/8&,Ð1
352&(6$0,(1723$5$/(/2RVHXGRSDUDOHOR
08/7,352*5$0$&,Ð1
0XOWLSOH[DFLyQGHOD
3URFHVRV &38HQWUHSURFHVRV
&RRSHUDQWHV FRQFXUUHQWHV
FRRSHUDQWHVRQR
0XOWLSURFHVR≠0XOWLXVXDULR
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVDGRU0RQRSURFHVDGRU
0XOWLSOH[DFLyQGHOD&38
Sabemos que para que un programa se ejecute, hay que convertirlo en proceso, y
para que éste evolucione de un estado a otro se requiere un procesador. Si
hablamos de sistemas multiproceso, es decir, que hay varios programas
simultáneamente en memoria, lo más conveniente para la ejecución más rápida es
asignar un procesador a cada uno de los procesos, para que evolucionen todos de
una forma realmente paralela o simultánea. Este es el caso de los ordenadores con
múltiples procesadores, en los que en un momento dado se encuentran realmente
en ejecución varios programas. Si bien esta es la forma más rápida de ejecutar
múltiples programas, también resulta ser, obviamente, la más cara. No solamente
por la cantidad de hardware utilizado (cuando menos, varias CPU’s), sino también
por el hardware y software adicional necesario para poder sincronizar y gestionar
múltiples CPU’s, algo mucho más complejo que cuando solamente se dispone de un
único procesador. (Resultan mucho más sencillos los departamentos de personal,
marketing, fabricación, distribución etc. de una empresa de 2, 3 o 4 empleados, que
los de una multinacional de miles de empleados).
Quizás nos puedan servir como ejemplo las partidas de ajedrez simultáneas que
mantienen los maestros de ajedrez con 20 principiantes. Cuando el maestro realiza
una jugada con un principiante, éste tarda mucho tiempo hasta que decide mover;
mientras tanto, el maestro puede realizar jugadas con el resto de los aprendices, y
seguramente, le dará tiempo a hacer un movimiento con cada uno de los rivales
antes de que el primero de ellos se haya decidido a mover una figura.
En este ejemplo tan optimista, esta partida simultánea se realiza en 1/20 del tiempo
que se tardaría si el maestro primero se dedicase por entero a jugar una partida con
el primer aficionado, hasta finalizarla; luego comenzar otra partida con el segundo y
así sucesivamente hasta haber jugado las 20 partidas. En los casos reales de
nuestros ordenadores, el reparto de la CPU no suele resultar tan provechoso como
en el caso del maestro de ajedrez, pues a menudo, también hay procesos a los que
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR
0iTXLQD0XOWLSURFHVDGRU
8Q3URFHVR 8Q3URFHVDGRU
0iTXLQD0RQRSURFHVDGRU
+D\TXHVLPXODUXQDPiTXLQDPXOWLSURFHVDGRU
6HXGRSDUDOHOLVPR
£ +D\TXHUHSDUWLUHOSURFHVDGRU
HQWUHORVSURFHVRV
3URFHVR
3URFHVR
3URFHVR
0XOWLSURFHVDGRU 0RQRSURFHVDGRUPXOWLSOH[DGR
3URFHVRHQHMHFXFLyQ
3URFHVRHQHVSHUD
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
se les quita la posesión de la CPU antes de que ellos la liberen por una de sus
esperas a un evento externo, por lo que nos encontramos con procesos que están
parados cuando sí podrían ejecutarse de tener una CPU disponible. En el peor de
los casos, es decir cuando se disponga de varios procesos que no tienen esperas
de E/S, la diferencia entre ejecutarlos en un entorno multiprocesador o
monoprocesador es la que se muestra en el gráfico de la Figura 5, en la que se
aprecia que la CPU se reparte en porciones de tiempo entre los distintos procesos,
por lo que mientras uno se ejecuta, los demás deben esperar su turno de CPU. En
este caso decimos que la utilización de la CPU está PXOWLSOH[DGDHQHOWLHPSR.
(VWDGRV\7UDQVLFLRQHVGHORV3URFHVRV
Anteriormente hemos visto que un ejemplo del FLFORGHYLGD de un proceso podría
estar caracterizado por esta secuencia:
También hemos visto con anterioridad que en otras ocasiones, el tiempo de CPU se
reparte en porciones entre todos los procesos que lo solicitan, por lo que un proceso
puede ver cómo pierde la posesión del procesador, de forma involuntaria, cuando se
le acaba la porción de tiempo que tenía asignada.
Este ciclo de vida de un proceso lo podemos ver en la Figura 6. En esta figura, los
círculos son recursos o condiciones deseadas por un proceso, mientras que los
rectángulos representan las colas de procesos que esperan por tales recursos. Así,
vemos que un proceso recién creado inmediatamente quiere ejecutarse, para lo cual
necesita la CPU, por lo que pasa a la cola de los procesos que esperan por el
procesador (cola de procesos SUHSDUDGRV). Una vez que le llega el turno, ejecuta
las instrucciones, hasta que por uno de los motivos mencionados (operación de E/S,
fin de la porción de tiempo, etc.) pierde la posesión de la CPU y pasa a la cola del
recurso solicitado (Disco 1, Unidad de Cinta 3, esperar a las 2:00 de la mañana). Si
la posesión del procesador se ha perdido por finalizar la porción de tiempo asignado
o bien porque un proceso de mayor prioridad requiere el procesador, el recurso que
necesita el proceso expulsado (o expropiado) es la propia CPU, por lo que pasa a la
cola correspondiente (la de los procesos preparados).
Este ciclo se repite una y otra vez hasta que el proceso ejecuta su última instrucción,
o sea, que finaliza el trabajo, con lo que voluntariamente cede el control de la CPU y
da por concluida su existencia como proceso.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR &LFORGH9LGDGHXQSURFHVR
&UHDFLyQ 7HUPLQDFLyQ
35(3$5$'2 &38
load
store ([SXOVLyQ
add 3HULRGR
store &38
read fichero
3HULRGR 'LVFR ',6&2
(VSHUD(6
(6
store
3HULRGR
increment
&38
write fichero
3HULRGR (VOD 'RUPLGRKDVWD
ODV
(VSHUD(6
(6 KRUD
load
store
3HULRGR
add
&38
store &LQWD &,17$
read fichero
3HULRGR
(VSHUD(6
(6
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
Vamos a ver cómo se producen las transiciones entre estos tres estados.
&UHDFLyQ→3UHSDUDGR
Inicialmente, al crear un proceso, no puede pasar directamente al estado de
Espera, pues no se ha ejecutado ninguna instrucción que así se lo indique; por
lo tanto, expresa su necesidad de ejecución entrando en la cola de procesos
Preparados.
3UHSDUDGR→(Q(MHFXFLyQ
Una vez que el proceso está preparado, solamente tiene que esperar a que le
llegue el turno. Los turnos del procesador se establecen en función de la
política de planificación de la CPU. Cuando le llegue el turno tomará posesión
del procesador y empezará a ejecutar instrucciones.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR (VWDGRVGHO3URFHVR
(Q 7HUPLQDFLyQ
(MHFXFLyQ
&UHDFLyQ (Q
3UHSDUDGR (VSHUD
(QB(MHFXFLyQ : ID_PROCESOS;
3UHSDUDGRV : COLA_PROCESOS;
(QB(VSHUD : COLA_PROCESOS;
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
(Q(MHFXFLyQ→3UHSDUDGR
Pasará a Preparado si abandona la CPU involuntariamente, es decir si se le
expulsa (o expropia), bien porque haya terminado su porción de tiempo, o
porque haya pasado a Preparado otro proceso de mayor prioridad.
(Q(MHFXFLyQ→(VSHUD
En cambio, pasa al estado de Espera si cede voluntariamente el procesador,
por tener que esperar a que se produzca un evento externo a la CPU.
(VSHUD→3UHSDUDGR
Desde el estado de Espera no se puede volver directamente a Ejecución, sino
que cuando se haya cumplido el evento externo, para recuperar la posesión del
procesador hay que pasar de nuevo por la cola de los procesos preparados.
Así tenemos que para conseguir la posesión de la CPU siempre hay que pasar
por su cola correspondiente (como un recurso más que es).
(Q(MHFXFLyQ→7HUPLQDFLyQ
Como ya hemos dicho antes, el proceso termina cuando ejecuta su última
instrucción, luego siempre pasará al estado de Terminado desde Ejecución.
Vistos los estados que puede tener un proceso y las transiciones entre ellos, nos
interesa saber FyPR HO VLVWHPD RSHUDWLYR OOHYD FRQWURO GH WRGRV ORV SURFHVRV
FUHDGRV, cómo se realizan estas colas de procesos y cómo se sabe qué proceso
está en ejecución.
En un apartado anterior hemos visto que hay una estructura de datos que contiene
toda la información de control que requiere el sistema operativo para ocuparse de la
gestión o administración del proceso. Nos estamos refiriendo al Descriptor de
Proceso o Bloque de Control de Proceso (BCP). Pues bien, entonces lo que el
sistema operativo necesita es mantener la colección de todos los BCP’s de los
procesos existentes en cada momento. Esta colección de BCP’s se puede organizar
de distintas maneras: mediante una cola estática, con una cola dinámica, o
simplemente utilizando una tabla, es decir, un vector o array de BCP’s. Así vemos
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR (VWDGRVGHO3URFHVR
(1B(-(&8&,Ð1
3ULPHUR
ÓOWLPR
'LVFR
3ULPHUR
ÓOWLPR
3ULPHUR
ÓOWLPR
7HUPLQDO %&3
3ULPHUR
ÓOWLPR
7DEOD 6LJQLO 6LJQLO6LJ 6LJ 6LJQLO6LJQLO 6LJ6LJQLO6LJQLO
GH%&3V
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Habiendo visto cómo se construye la cola de Preparados, resulta fácil imaginar que
las colas de procesos para cada uno de los recursos por los que se puede esperar
(dispositivos de E/S, etc.) se implementan de igual forma.
&DPELRGH3URFHVRHQ(MHFXFLyQ&DPELRGH&RQWH[WR
Cuando un proceso en ejecución pierde la posesión de la CPU, se debe a uno de
los siguientes motivos:
• Llamada al sistema
• Interrupción
• Fin del proceso
Está claro que ante ciertas llamadas al sistema (una petición de E/S, dormir, etc.) el
proceso en cuestión queda bloqueado, sin poder continuar la ejecución de
instrucciones, hasta que se atienda el servicio solicitado; por esto, cede la posesión
del procesador para que pueda ejecutar instrucciones otro proceso que esté
preparado.
También puede ocurrir que una interrupción anuncie el final de la actual posesión
del procesador. Esto será así si la interrupción es la generada por el reloj del
sistema y se detecta que se ha consumido la porción de tiempo asignada (en un
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
&DPELRGH3URFHVR
6LVWHPDV0XOWLSURFHVR HQHMHFXFLyQ
3HWLFLyQGH(6
+//$0$'$$/6,67(0$
'RUPLU
)LQGHODURGDMDGHWLHPSR
0RWLYRV
+,17(5583&,Ð1
GHO&DPELR 6HSUHSDUDXQSURFHVRGH
PD\RUSULRULGDG
+),1'(/352&(62
&DPELRHQ'RV)DVHV
¨6HOHFFLRQDUHO6LJXLHQWH3URFHVR
3/$1,),&$'25
©&DPELDUHO&RQWH[WRGH(MHFXFLyQ
',63$7&+(5
£(O&DPELRGH3URFHVR&RQVXPH7LHPSR
0LQLPL]DUORV&DPELRVGH3URFHVRV
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Una vez conocido el identificador del proceso que va a apropiarse de la CPU, hay
que cederle el control del procesador, pero no antes de realizar el cambio de
contexto. Para esto, se da control al 'LVSDWFKHU, que es la parte del sistema
operativo que se encarga de terminar de salvar el contexto del programa que
abandona la CPU (o perderlo definitivamente si se debe a una terminación del
proceso) y establecer el contexto del proceso seleccionado. De hecho, el último de
los pasos de que consta el cambio completo del contexto, consiste en restaurar el
Contador de Programa del proceso elegido. Una vez que el registro Contador de
Programa es restaurado, la siguiente instrucción que se ejecuta es ya una
instrucción del proceso seleccionado.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
&DPELRGH3URFHVR (O3ODQLILFDGRU
6HOHFFLRQDHO6LJXLHQWH3URFHVRD(MHFXWDU
6HJ~QOD3ROtWLFDGH3ODQLILFDFLyQ
12(;38/625(6 (;38/625(6
3),)2 35RXQG5RELQ
3(OPiVFRUWRHOSULPHUR 33ULRULGDGHV
33ULRULGDGHV
£ ),1'(/$52'$-$
'(7,(032
-- Actualizar el final de la cola Preparados.
Procesos(Preparados.Ultimo).Siguiente := En_Ejecución;
Preparados.Ultimo := En_Ejecución;
-- Seleccionar un proceso.
Proceso_Seleccionado := Preparados.Primero;
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• Se salvan todos los registros del procesador en la Pila del proceso actualmente
en ejecución (el A). A excepción del REGISTRO DE ESTADO (RE), CONTADOR
DE PROGRAMA (CP) y PUNTERO DE PILA (PP).
• Tras decidir que el proceso en ejecución debe abandonar la CPU, el Planificador
elige el proceso que pasará a Ejecución, al que nos referiremos como Proceso
B.
• Se llama al 'LVSDWFKHU y comienza el cambio de contexto. Se producen las
siguientes acciones:
1. El Puntero de Pila del proceso A se guarda en su Descriptor de Proceso.
2. Se carga el Puntero de Pila a partir del PP guardado en el Descriptor del
Proceso B. Ahora la Pila de trabajo es la del proceso B
3. Se cargan todos los registros generales del procesador a partir de los datos
contenidos en la Pila, a excepción del RE, el CP y el PP.
4. El valor que queda en la cima de la Pila es la dirección de vuelta del último
punto en el que se llamó al Dispatcher cuando el proceso B perdió el control de
la CPU.
5. Se actualiza la variable En_Ejecución con Proceso_Seleccionado.
6. El Dispatcher termina. Al ejecutar la instrucción de RETORNO DE SUBRUTINA,
se devuelve el control al punto en el que se había llamado al Dispatcher para
que el proceso B perdiese el control del procesador.
7. El sistema operativo termina de realizar el servicio que el Proceso B le había
solicitado, por lo que ejecuta la instrucción máquina RETORNO DE
INTERRUPCIÓN. Esta instrucción origina que se cargue el REGISTRO DE
ESTADO y el CONTADOR DE PROGRAMA con los dos datos que se sacan de la
cima de la Pila.
8. Con el nuevo CONTADOR DE PROGRAMA, la instrucción que se ejecuta es la
siguiente al punto en el que el proceso B realizó una Llamada al Sistema (lo
que supuso su paso a Espera).
Ya hemos visto que el cambio de CPU de un proceso a otro requiere una serie de
acciones que se encargan de realizarlas el Planificador y el 'LVSDWFKHU. Pues bien,
estas acciones se ejecutan en un tiempo que, desde luego, no es nulo. La elección
del proceso a ejecutar suele ser muy simple y no supone una pérdida de tiempo
considerable; pero el cambio de contexto sí puede acarrear una gran cantidad de
instrucciones, incluidas operaciones de E/S si los contextos de memoria de los
procesos que intervienen hay que salvarlos y traerlos, respectivamente, del disco
duro, cosa que suele realizarse en los actuales sistemas con Memoria Virtual.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
& D P E LR G H 3 U R F H V R ( O' L V S D W F K H U
( V H O( Q F D U J D G R G H & H G H U
H O& R Q W U R OG H OD & 3 8 D O3 U R F H V R
6 H OH F F LR Q D G R S R U H O3 OD Q L I LF D G R U
6 X V $ F F L R Q H V % i V L F D V 6 R Q
7 H U P LQ D U G H V D OY D U H OF R Q W H [ W R G H O
3 U R F H V R $ F W X D OP H Q W H H Q ( M H F X F L y Q
( V W D E OH F H U H O3 X Q W H U R G H 3 LOD G H O 1 X H Y R
3 U R F H V R T X H 3 D V D D ( M H F X F Ly Q
5 H V W D X U D U OR V 5 H J L V W U R V G H OD & 3 8 D
3 D U W L U G H OD 1 X H Y D 3 L OD H [ F H S W R & 3 \ 5 (
5 H V W D X U D 5 ( P R G R X V X D U L R
¡ 57(
5 H V W D X U D & 3
6 LV W H P D V 2 S H U D W LY R V , * H V W Ly Q G H 3 U R F H V R V
solamente se le dedica el 80% del tiempo de CPU, mientras que, claramente, lo más
deseable es que se acercara lo más posible al 100%.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR &DPELRGH3URFHVR
352&(62 6,67(0$ 352&(62
$ 23(5$7,92 %
all
HQHMHFXFLyQ ys_c
int. o
S
SUHSDUDGR
6DOYDU
5HJLVWURV3B$
HQHVSHUD
6HOHFFLRQDU
3URFHVR
&DUJDU
5HJLVWURV3B%
HQHMHFXFLyQ
SUHSDUDGR int. o
S ys_ca
ll
6DOYDU
5HJLVWURV3B%
HQHVSHUDR
SUHSDUDGR
6HOHFFLRQDU
3URFHVR
&DUJDU
5HJLVWURV3B$
HQHMHFXFLyQ
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3URFHVR2FLRVR
Veamos ahora una situación, a primera vista comprometida, que se puede dar en un
sistema multiproceso. Sabemos que cuando un proceso cede voluntariamente el
control de la CPU, el Planificador tiene que elegir otro proceso de usuario que esté
preparado, pero
Si no hay ningún proceso que quiera ejecutar instrucciones ¡qué hace la CPU?
Esta situación no solamente es perfectamente posible, sino que se da con mucha
frecuencia. En un sistema con cinco usuarios ¿qué impide que en un instante
determinado cuatro de los procesos estén esperando una respuesta del disco duro,
la llegada de un carácter por una línea de comunicaciones, o que llegue una hora
determinada? La respuesta es: nada. Pues si en este momento el proceso del
quinto usuario también realiza una petición a un dispositivo de E/S, también pasa a
Espera. En este momento el Planificador tendría que seleccionar un proceso de la
cola de Preparados, para darle el control, pero ¡ya no hay más procesos! ¿qué va a
hacer la CPU mientras todos los procesos están en Espera?
Hemos mencionado solamente los procesos de usuario, pero también hay procesos
del sistema operativo que pueden estar realizando servicios que se les haya
solicitado con anterioridad, por ejemplo, imprimiendo un fichero. De cualquier forma,
tampoco hay nada que impida que en un momento dado no haya ningún proceso
con necesidad de ejecutar instrucciones.
Para estos casos, en todos los sistemas suele haber un proceso del sistema
denominado 3URFHVR2FLRVR. Este proceso consta de un bucle infinito ejecutando
un algoritmo muy sencillo (puede ser incluso la instrucción 1R2SHUDFLyQ) en el que
no figura ninguna instrucción que pueda generar un paso a Espera. El proceso
ocioso puede estar continuamente realizando estudios estadísticos de utilización del
sistema, calculando decimales del numero π, o cualquier trabajo infinito de la menor
prioridad. De esta forma, siempre tendremos un proceso Activo.
Diremos que la CPU está ociosa cuando esté ejecutando el Proceso Ocioso.
3ODQLILFDFLyQGH3URFHVRV
Habiendo visto el ciclo de vida de los procesos, sabemos que un proceso que se
está ejecutando, eventualmente, por diversos motivos que se han comentado,
abandona la posesión del procesador voluntaria o involuntariamente, por lo que hay
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
que cederle la CPU a un proceso que sea lógicamente ejecutable, es decir, que esté
Preparado. Si hay más de un proceso Preparado, el sistema operativo debe decidir
cuál de ellos se ejecutará primero. La parte del sistema operativo que le
corresponde tomar tal decisión es el 3ODQLILFDGRU, que seleccionará un proceso
basado en una política o algoritmo de planificación.
&ULWHULRV
Antes de ver algoritmos concretos de planificación debemos recordar, que la
elección que el Planificador va a realizar debe hacerse persiguiendo “el bien del
sistema”, pues es uno de los cometidos del sistema operativo. No obstante, distintas
políticas de planificación tienen diferentes propiedades, y favorecen más a un tipo
de procesos que a otros. Antes de elegir el algoritmo a utilizar en una situación
concreta, debemos considerar las propiedades de varios algoritmos.
Se han sugerido muchos criterios para comparar algoritmos de planificación de
CPU. Decidir las características que se van a utilizar en la comparación es
fundamental para la elección del algoritmo más apropiado. Veamos los criterios de
comparación más comúnmente utilizados:
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR 3ODQLILFDFLyQGH3URFHVRV
(O3ODQLILFDGRUVH(QFDUJDGH6HOHFFLRQDU
HO3URFHVRTXH3DVDD(MHFXFLyQ
\'HFLGH6HJ~QXQD3ROtWLFD
%DVDGDHQ$OJXQRV&ULWHULRV
-XVWLFLD 7LHPSRGH5HVSXHVWD
(ILFLHQFLD 7LHPSRGH(VSHUD
7LHPSRGH5HWRUQR 5HQGLPLHQWR
3ROtWLFDVGH3ODQLILFDFLyQ
1R([SXOVRUDV ([SXOVRUDV
EDWFK PXOWLXVXDULR\
WLHPSRUHDO
3(O3ULPHURHQ/OHJDU 37LHPSR&RPSDUWLGR
5RXQG5RELQ
3(O0iV&RUWR3ULPHUR
33RU3ULRULGDGHV
33RU3ULRULGDGHV
30~OWLSOHV&RODV
30~OWLSOHV&RODV
5HDOLPHQWDGDV
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3ROtWLFDVGH3ODQLILFDFLyQ
En los diagramas de estados de los procesos, vimos que cuando un proceso en
Ejecución abandona tal estado pasa a Espera o a Preparado, dependiendo si deja el
procesador voluntaria o involuntariamente. Si los procesos de un sistema nunca
dejan la CPU de forma involuntaria, se dice que la política de planificación de CPU
es QRH[SXOVRUD o no expropiativa (QRQSUHHPSWLYHVFKHGXOLQJ). Por el contrario, si
pueden perder la posesión del procesador sin solicitarlo, nos encontramos con una
planificación H[SXOVRUD o expropiativa (SUHHPSWLYHVFKHGXOLQJ).
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• 3ULPHURHQOOHJDU3ULPHURHQVHUYLU
Este algoritmo, cuyo nombre abreviaremos con FCFS ()LUVW&RPH)LUVW6HUYHG),
es, con mucho, el algoritmo más simple. Según este esquema, el primer proceso
que reclama la CPU, es el primero en conseguirla. En cuanto a la
implementación, no merece la pena dar muchas explicaciones, pues basta con
mantener, por ejemplo, una cola FIFO de los descriptores de los procesos que
van solicitando la CPU.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR 3ROtWLFDVGH3ODQLILFDFLyQ
(O3ULPHURHQ/OHJDU3ULPHURHQ6HUYLU
J(VVLPSOH
L7LHPSRGHHVSHUDYDULDEOH5DUDPHQWHHOPtQLPR
L'HVDSURYHFKDORVGLVSRVLWLYRVGH(6
7UDEDMR 7LHPSRQHFHVDULR
(O0iV&RUWRHO3ULPHUR
J2IUHFHVLHPSUHHOPtQLPRWLHPSRPHGLRGHHVSHUD
7UDEDMR 7LHPSRQHFHVDULR
J(VySWLPR
L¢&XiOHVODQHFHVLGDGUHDOGHOWUDEDMR"
0iVXWLOL]DGRHQODSODQLILFDFLyQDODUJRSOD]R
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• (OPiVFRUWRSULPHUR
Este algoritmo, también conocido como SJF (6KRUWHVW-RE)LUVW), concede la CPU
al proceso que durante menos tiempo necesita la CPU de forma ininterrumpida.
Debe quedar claro que se selecciona el que menor porción de tiempo de CPU
necesita en el momento de hacer la elección, no aquel cuyo tiempo total de CPU
es el menor de todos. Si dos procesos necesitan el procesador durante el mismo
tiempo, se elige uno mediante FCFS.
• 5RXQG5RELQ
Este algoritmo está especialmente diseñado para los sistemas multiusuario de
tiempo compartido. Es similar al FCFS, pero se le añade la expropiación de la
CPU cuando la posesión continuada de ésta sobrepasa un tiempo preestablecido
(SRUFLyQGHWLHPSR), que suele ser del orden de 10 a 100 milisegundos.
La implementación de este algoritmo se realiza con una cola FIFO para los
procesos Preparados. Los nuevos procesos se añaden al final de la cola. Cuando
el planificador tiene que seleccionar un proceso, elige el primero de la cola,
establece una temporización correspondiente a la porción de tiempo, y le cede el
control. Ahora pueden ocurrir dos cosas:
1ª) El proceso termina o realiza una operación de E/S antes de que se acabe su
porción de tiempo, en cuyo caso cede la CPU voluntariamente, pasa a espera
y el planificador selecciona el siguiente proceso de la cola Preparados.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LVWHPDV0XOWLSURFHVR 3ROtWLFDVGH3ODQLILFDFLyQ
7LHPSR&RPSDUWLGR5RXQG5RELQ
3URFHVR
3URFHVR
3URFHVR
3URFHVRHQHMHFXFLyQ
3URFHVRHQHVSHUD
7UDEDMR 7LHPSRQHFHVDULR
(O5HQGLPLHQWRGHO6LVWHPD
'HSHQGHGHOD3RUFLyQGH7LHPSR
3HTXHxD *UDQGH
£
6RORKD\
FDPELRVGHFRQWH[WR )&)6
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• 3RU3ULRULGDGHV
Uno de los factores a tener en cuenta en la planificación de los procesos es la
justicia, pero justicia no siempre significa un reparto a partes iguales, sino la
asignación más conveniente que aconsejen las circunstancias. Así, por ejemplo,
tenemos que en un programa de control y supervisión de una central nuclear,
compuesto por diversos procesos, no se debe esperar que todos los procesos
cuenten inexcusablemente con la misma porción de tiempo de CPU, ni según un
turno circular. Evidentemente, no es tan importante el proceso interactivo que se
encarga de mostrar a los visitantes un vídeo de la historia de la central y
responder a sus preguntas, como los procesos encargados de supervisar los
niveles de presión, temperatura, radioactividad, etc., y que en caso de que se
sobrepasen los límites de seguridad activan las válvulas y avisos
correspondientes.
Los criterios para establecer las prioridades pueden ser variados: por razones
físicas, como en el caso de los sistemas de tiempo real, por rangos o categorías
de los usuarios (sistemas multiusuarios), por factores políticos, etc. En sistemas
multiusuario, es muy común tener prioridades por grupos de trabajo o
departamentos, y a los procesos de la misma prioridad aplicarles una política
reparto de tiempo compartido.
Este algoritmo puede ser H[SXOVRU o QR H[SXOVRU. Cuando un proceso llega a la
cola Preparados, se compara su prioridad con la del proceso en ejecución. Con
un algoritmo expulsor por prioridades, si la prioridad del recién llegado es mayor
que la del proceso en ejecución, se le expropia la CPU a este último en favor del
recién llegado. Si la política es no expulsora, simplemente se coloca al nuevo
proceso a la cabeza de la cola. El algoritmo SJF es un caso particular de este
algoritmo con política no expulsora, donde la prioridad es la inversa del tiempo
requerido de CPU.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6 LV W H P D V 0 X OW LS U R F H V R 3 R OtW L F D V G H 3 OD Q L I L F D F Ly Q
3 U L R U LG D G H V H [ S X OV R U D V
+ / R V 3 U R F H V R V 7 L H Q H Q 3 U L R U LG D G H V
$ 3/,&$ &,2 1 (6
* U X S R V G H 3 H U V R Q D V 7 LH P S R 5 H D O
F D W H J R U tD V
& X L G D G R F R Q OD
£ , Q D Q L F Ly Q
6 2 /8 &,2 1 (6 3 5 R X Q G 5 R E LQ S R U S U L R U LG D G H V
3 3 U LR U L G D G H V
G LQ i P L F D V
´ ( Q Y H M H F LP LH Q W R µ
6 LV W H P D V 2 S H U D W LY R V , * H V W Ly Q G H 3 U R F H V R V
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• 0~OWLSOHVFRODV
Existe otro tipo de algoritmos para situaciones en las que los procesos están
claramente clasificados en diferentes grupos. Por ejemplo, una división muy
común es la que se hace entre procesos interactivos de primer plano (IRUHJURXQG)
y los procesos batch que suelen ejecutarse en un segundo plano (EDFNJURXQG).
Estos dos tipos de procesos tiene distintos requisitos en sus tiempos de
respuesta, por lo que podrían tener distintos algoritmos de planificación cada uno.
Además, los procesos interactivos podrían tener mayor prioridad que los se
ejecutan en un segundo plano.
Para esto, la cola Preparados podría estar dividida en varias colas separadas,
una por cada tipo de proceso. Cada proceso siempre se encola en su cola
correspondiente. Así nos encontramos con que para elegir la cola de la que se va
a sacar un proceso se utiliza una política, mientras que para seleccionar qué
proceso se va a sacar de la cola elegida, se utiliza un algoritmo distinto. También
puede ocurrir que en dos colas distintas se utilice la misma política de
planificación, por ejemplo, tiempo compartido, pero que la porción de tiempo sea
distinta en una cola que en otra.
• 0~OWLSOHVFRODVUHDOLPHQWDGDV
Una mezcla de las técnicas de envejecimiento y de las múltiples colas, resulta en
las múltiples colas realimentadas.
Las distintas colas pueden tener políticas de tiempo compartido, pero las más
prioritarias poseen una mayor porción de tiempo. Cuando un proceso lleva mucho
tiempo en una cola de poca prioridad, se le pasa a otra cola de mayor prioridad,
consiguiendo así mayores porciones de tiempo.
3ODQLILFDFLyQHQ6LVWHPDV0XOWLSURFHVDGRU
Hasta ahora hemos tratado con algoritmos de asignación de CPU en sistemas con
un solo procesador. Si se dispone de múltiples procesadores, la planificación se
vuelve bastante más compleja.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3ODQLILFDFLyQ &RQ0~OWLSOHV3URFHVDGRUHV
/RVSURFHVDGRUHVSXHGHQVHU
',)(5(17(6 ,*8$/(6
6LVWHPD+HWHURJpQHR 6LVWHPD+RPRJpQHR
&DGDSURFHVDGRUWLHQHVX ¢9DULDVFRODV"
SURSLDFROD\VXSURSLD
SODQLILFDFLyQ
L£&DUJDGHVHTXLOLEUDGD
&DGDSURFHVRVHDVLJQDDO
WLSRGHSURFHVDGRUTXHOH
FRUUHVSRQGH 'HEHKDEHUXQD~QLFDFRODGH
SURFHVRV
$XWRSODQLILFDFLyQ 8QSURFHVDGRUKDFHGH
3ODQLILFDGRU\UHSDUWHORV
8QSURFHVDGRUOLEUHVDFD
SURFHVRVHQWUHORV
XQSURFHVRGHODFROD
SURFHVDGRUHV
£&8,'$'2
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
En los sistemas homogéneos se podrían tener también varias colas, una por
procesador, pero esto podría dar lugar a una carga desequilibrada, con algunas
colas con muchos procesos, y otras colas vacías con su CPU ociosa. Para evitar
esto, suele ser mejor disponer de una única cola de procesos preparados. Hay dos
métodos para sacar los procesos de la cola.
/D3ODQLILFDFLyQGH$OJXQRV6LVWHPDV2SHUDWLYRV
Aunque los conceptos de sistemas operativos pueden estudiarse o considerarse en
términos puramente teóricos, resulta conveniente observar cómo se han
implementado algunos sistemas operativos comerciales. Así, ahora vamos a
comentar, aunque solo sea superficialmente, algunas de las decisiones de diseño
que se han tomado sobre la planificación de la CPU en Unix, Linux y Windows NT.
8QL[
La primera versión de Unix se desarrolló en 1969 por Ken Thompson en los
Laboratorios Bell. Muchas versiones y emulaciones se han hecho desde entonces.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
También merece especial mención Linux, que desde mediados de los años 90 ha
tenido una espectacular difusión, y al que le trataremos en un apartado particular.
Ahora vamos a comentar aquí la política de planificación del procesador utilizada por
Unix en su versión 4.3BSD.
Las porciones de tiempo son de 100 ms., por lo que cuando un proceso llega al
término de su porción sin haber cedido la CPU, se le quita la CPU para cedérsela al
proceso preparado con mayor prioridad. Las prioridades, no obstante, son
dinámicas, es decir, que la prioridad de un proceso va variando a lo largo de su
vida. Aunque las porciones de tiempo son de 100 ms. la reevaluación de las
prioridades se realiza una vez por segundo, para que no suponga una sobrecarga
considerable. Esto quiere decir que cada segundo se aplica el algoritmo que
establece la prioridad de cada proceso. El algoritmo en cuestión es el siguiente:
&38 (L − 1)
3 (L) = %DVH +
M M
M
+ QLFH M
2
8 (L) &38 (L − 1)
&38 = +
M M
M
2 2
donde
3 L
M Prioridad del proceso M al comienzo del intervalo L. Cuanto menor
sea este número, mayor es la prioridad.
en el intervalo L.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Ya que a todos los procesos de usuario se les asigna la misma prioridad base, para
este tipo de procesos el algoritmo se comporta como si fuera 5RXQG5RELQ (aunque
como ya hemos dicho, favoreciendo a los procesos con poca carga de CPU), no
obstante, se puede favorecer en cierta manera a algunos procesos de usuario
mediante el comando nice.
Debido a este algoritmo con envejecimiento, resulta muy difícil que un proceso
pueda apropiarse de forma exclusiva de la CPU evitando así la “inanición” de los
procesos.
/LQX[
Linux es otro sistema operativo “tipo Unix” en el que aunque la compatibilidad con
Unix era uno de los objetivos de diseño, tiene algunas particularidades que difieren
del Unix estándar, entre ellas la política de planificación de procesos, y dada la
popularidad que ha adquirido en estos últimos años, merece la pena comentarlo.
Alrededor del único NHUQHO GH /LQX[ se han construido multitud de programas que
constituyen el VLVWHPD /LQX[. Alguno de estos programas se ha construido
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
expresamente para Linux, mientras que otros se han tomado prestados de otros
sistemas o proyectos de colaboración.
Cuando no queda ningún proceso preparado con créditos, Linux vuelve a asignar
créditos a todos los procesos del sistema según la regla siguiente:
FUpGLWRV UHVWDQWHV
&UpGLWRV = + SULRULGDG
2
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Para tiempo real, Linux implementa los dos algoritmos expulsores o expropiativos
requeridos por POSIX: ),)2 y 5RXQG5RELQ. Esto quiere decir que la información de
cada proceso debe indicar si se acoge a planificación de tiempo compartido o de
tiempo real, y en caso de ser este último, debe especificar si utiliza el algoritmo ),)2
o 5RXQG5RELQ. Veamos cómo se comporta la planificación con cada uno de estos
dos algoritmos de tiempo real.
:LQGRZV17
Este sistema operativo nació como consecuencia de que Microsoft decidió construir
un nuevo sistema operativo partiendo de cero y con una Nueva Tecnología, que
soportara las aplicaciones tanto para OS/2 como para POSIX, Windows y MS-DOS.
Hay dos versiones de Windows NT: ZRUNVWDWLRQ (puesto de trabajo para un usuario)
y VHUYHU (utilizado como servidor para aplicaciones cliente-servidor), sin embargo
ambas utilizan el mismo núcleo, por lo que las características de planificación que
comentaremos aquí se aplican a las dos versiones.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Se utiliza una cola para cada una de estas prioridades, de tal manera que para
elegir el siguiente proceso que pasa a ejecución, se recorren todas las colas, de
mayor a menor prioridad hasta que se encuentra un proceso preparado. Si no hay
ningún proceso preparado, se le cede el control al WKUHDGRFLRVR.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
consiguen un mayor aumento de prioridad, mientras que los que esperan por la
conclusión de una operación con el disco sólo consiguen un ligero aumento. Esta
estrategia tiende a ofrecer un buen tiempo de respuesta a los procesos interactivos
elevando la prioridad a los procesos que esperan por teclado o ratón, dejando que
los procesos con gran carga de procesador se ejecuten en tiempos muertos en
segundo plano.
3ODQLILFDFLyQHQ6LVWHPDV0XOWLSURFHVDGRUHV
Cuando Windows NT se ejecuta con un único procesador, el proceso preparado de
mayor prioridad siempre está en ejecución, y si hay más de un proceso con la mayor
prioridad, la CPU se reparte por turno rotatorio entre todos los procesos preparados
de esa prioridad.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
&RPXQLFDFLyQ\6LQFURQL]DFLyQHQWUH3URFHVRV
Normalmente, los procesos que cooperan en la realización de un trabajo,
necesitarán durante su ciclo de vida la sincronización o comunicación entre ellos o
con el proceso maestro que les haya creado. Se hace necesario algún sistema de
comunicación cuando se requiere el intercambio de información entre dos o más
procesos. Por ejemplo, un proceso puede estar produciendo una serie de datos que
sirven a su vez de entrada a otro proceso (como ocurre con el SLSH “|” de Unix). En
otros casos, como en los momentos en que se accede a estructuras de datos
comunes a varios procesos, se requiere algún mecanismo de sincronización para
que dos procesos no intenten acceder simultáneamente a dicha estructura para
realizar operaciones de lectura/escritura de forma incontrolada.
Así pues, en los siguientes apartados trataremos los problemas que pueden darse y
algunos mecanismos propuestos para comunicación y sincronización entre procesos
cooperantes que comparten el mismo espacio lógico de direcciones.
&RQGLFLyQGH&DUUHUD
Como ya hemos dicho anteriormente, un sistema puede estar compuesto de
múltiples procesos que se pueden ejecutar en paralelo (simultáneamente) si se
dispone de múltiples procesadores. Cuando solamente se dispone de una CPU, el
efecto del procesamiento paralelo puede simularse si los procesos se ejecutan
turnándose en la posesión del procesador. En otras palabras, el procesador puede
compartirse entre varios procesos. Incluso simulando el procesamiento paralelo,
resulta útil ver cada proceso como si tuviera su propio procesador virtual dedicado.
En este ejemplo se muestra que los resultados son impredecibles, ya que los
procesos se ejecutan con velocidades relativas igualmente impredecibles. Cuando el
resultado de un cálculo depende de las velocidades relativas de los procesos, se
dice que hay una FRQGLFLyQ GH FDUUHUD. Las condiciones de carrera se producen
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LQFURQL]DFLyQGH3URFHVRV
SURJUDP Cuenta_Eventos;
Contador : INTEGER := 0;
SURFHVV Observador;
UHSHDW
Esperar_Evento;
Contador := Contador + 1;
IRUHYHU;
£ 6HSLHUGHQ
HQG Observador;
SURFHVV Reportero;
UHSHDW HYHQWRV
Imprimir (Contador);
Contador := o;
IRUHYHU;
HQG Reportero;
EHJLQ
Observador;
Reportero;
HQG Cuenta_Eventos;
6HSURGXFHXQD&RQGLFLyQGH&DUUHUD 62/8&,Ð1
(ODFFHVRDODYDULDEOHQRHVDWyPLFR
3URSRUFLRQDU
process Observador; ([FOXVLyQ0XWXD
repeat
Esperar_Evento; 5HJLyQ&UtWLFD
(QWUDUB5&;
Contador := Contador + 1;
6DOLUB5&;
forever;
end Observador;
process Reportero;
repeat
(QWUDUB5&;
Imprimir (Contador);
Contador := 0;
6DOLUB5&;
forever;
end Reportero;
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
([FOXVLyQ0XWXD\5HJLyQ&UtWLFD
¿Cómo evitar las condiciones de carrera? La clave para evitar problemas en las
situaciones en que se comparten objetos o recursos es encontrar algún modo de
prohibir que haya más de un proceso leyendo o escribiendo el dato compartido al
mismo tiempo. En otras palabras, lo que se necesita es H[FOXVLyQPXWXD, es decir,
asegurarse de que si un proceso está accediendo a un dato compartido, el otro o los
otros procesos estarán imposibilitados para poder hacerlo también.
En la vida de un proceso, parte del tiempo está ocupado con cálculos internos y otro
tipo de cosas que no conducen a una condición de carrera. Pero en otras ocasiones,
el proceso accede a variables o ficheros compartidos que sí puede conducir a la
condición de carrera. La parte del programa en la que se accede a memoria
compartida se denomina UHJLyQFUtWLFD. Si nos las pudiéramos apañar para que dos
procesos no estuvieran al mismo tiempo en su región crítica, evitaríamos las
condiciones de carrera.
,PSOHPHQWDFLyQGHOD([FOXVLyQ0XWXD
En la parte inferior de la Figura 18 tenemos nuestro ejemplo transformado de
acuerdo a la premisa del acceso a la región crítica. En este programa transformado
se muestra una solución abstracta al problema de la exclusión mutua. Podemos ver
que la región crítica de cada proceso está encerrada entre sendas sentencias de
entrada y salida de la región ((QWUDUB5& y 6DOLUB5&). Estaría bien que estas
primitivas de acceso a la región crítica se comportasen como “porteros”, tal que si un
proceso intentara entrar en la región crítica ocupada por otro proceso, el primero
quedara bloqueado por el portero hasta que el otro proceso saliese de ella.
&RQGLFLRQHVSDUDHO6LQFURQLVPRGH3URFHVRV&RRSHUDQWHV
Aunque con la exclusión mutua se evitan las condiciones de carrera, no es condición
suficiente para que una serie de procesos paralelos cooperen correcta y
eficientemente utilizando datos compartidos. Se requieren las siguientes condiciones
para obtener una buena solución:
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
0HFDQLVPRV
En este apartado examinaremos, tanto a nivel hardware como software, algunos de
los muy diversos métodos de sincronización que existen para resolver el problema
de la exclusión mutua. Estos son:
• Inhibición de interrupciones
• Espera activa
• Semáforos
• Monitores
,QKLELFLyQGH,QWHUUXSFLRQHV
Si se pretende evitar que mientras un proceso está dentro de una región crítica, otro
proceso pueda entrar también, la forma más fácil de conseguirlo es evitando que el
proceso que se encuentra dentro de la región pierda el control del procesador antes
de abandonarla.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6LQFURQL]DFLyQ ([FOXVLyQ0XWXD
5HTXLVLWRVSDUDVX,PSOHPHQWDFLyQ
'RVSURFHVRVQRSXHGHQHVWDUDOPLVPRWLHPSRGHQWUR
+ GHODPLVPDUHJLyQFUtWLFD
1RVHGHEHQKDFHUVXSRVLFLRQHVVREUHHOKDUGZDUH
+ YHORFLGDGRQGHSURFHVDGRUHV
1RVHGHEHQKDFHUVXSRVLFLRQHVVREUHODYHORFLGDGHV
+ UHODWLYDVGHORVSURFHVRV
1LQJ~QSURFHVRIXHUDGHVXUHJLyQFUtWLFDSXHGH
+ EORTXHDUDRWURVSURFHVRV
1LQJ~QSURFHVRGHEHUiHVSHUDUHWHUQDPHQWHDHQWUDU
+ HQVXUHJLyQFUtWLFD
1RVHGHEHSRVSRQHULQGHILQLGDPHQWHODGHFLVLyQGH
+ FXiOHVHOVLJXLHQWHSURFHVRTXHGHEHHQWUDU
9$5,26
6,67(0$6
Ï,QKLELFLyQGH,QWHUUXSFLRQHV
Ï9DULDEOH&HUURMR(VSHUD$FWLYD
Ï6HPiIRURV
Ï0RQLWRUHV
Ï
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Sin embargo, con frecuencia resulta conveniente para el núcleo del sistema
operativo la inhibición de interrupciones durante unas pocas instrucciones mientras
actualiza estructuras de datos del sistema, por ejemplo, para actualizar la lista de
procesos Preparados, pues si se dejase en un estado inconsistente, el sistema se
iría al traste.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
([FOXVLyQ0XWXD ,QKLELFLyQGH,QWHUUXSFLRQHV
,QWHUUXSFLRQHV 3RVHVLyQLQGHILQLGDGHOD&38
,QKLELGDV
352%/(0$6
36HSXHGHQSHUGHULQWHUUXSFLRQHV
36HSULYDD72'26ORVSURFHVRVGHOD&38
33HOLJURVRHQPDQRVGHOXVXDULR
62/8&,Ð1(VSHFLILFDUOD5HJLyQ&UtWLFD
...
Entrar_RC (RC_Eventos);
...
...
Salir_RC (RC_Eventos);
...
8WLOSDUDORVQ~FOHRVGHORVVLVWHPDVRSHUDWLYRV
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
(VSHUD$FWLYD&HUURMRV
Otra posibilidad de impedir el acceso simultáneo de dos procesos a la región crítica
es haciendo que una variable actúe como cerrojo o indicador de si la región crítica
está ocupada o no. Esto se puede hacer con una variable booleana que tome los
valores 0 (libre) y 1 (ocupada). Todos los procesos que deseen acceder a una
región crítica deben cumplir un protocolo de acceso y salida de la región. Cuando un
proceso llegue a la entrada de la región debe consultar el valor de la variable-
cerrojo; si el valor es 0, la pone a 1 y entra en la región crítica; si la variable ya
estaba a 1, el proceso debe esperar hasta que valga 0.
Por desgracia, esta idea contiene el mismo problema que nuestro ejemplo de los
procesos Observador y Reportero. Supongamos que un Proceso A lee el cerrojo y
ve que está a 0. Antes de que pueda ponerlo a 1, pierde el control de la CPU y lo
toma otro Proceso B que también quiere entrar en la región crítica. Este último
consulta también el valor del cerrojo (que sigue a 0), lo pone a 1 y entra en la región.
Antes de salir de la región crítica, finaliza su porción de tiempo y se le devuelve el
control al Proceso A, que continúa lo que estaba haciendo, con lo que pone el
cerrojo a 1 (otra vez) y entra en la región crítica, creyendo que él es el único que
está dentro, porque ha entrado siguiendo el protocolo de acceso.
Para solucionar esto han surgido diversos algoritmos, entre ellos, el de la panadería
(de Lamport); el algoritmo de Decker (para 2 procesos); el de Dijkstra (para n
procesos); el de Knuth, Eisemberg y McGuire; y el de Peterson. La descripción de
estos algoritmos puede encontrarse en cualquiera de los textos indicados en la
bibliografía.
Se consigue una buena solución con un poco de ayuda hardware. Los procesadores
de propósito general suelen ofrecer la siguiente instrucción máquina (por lo tanto,
ininterrumpible en su ejecución):
Esta instrucción (7HVW DQG 6HW) actúa de la siguiente manera. Se lee la variable
&HUURMR, y en función de su valor, se establecen los IODJV correspondientes en el
Registro de Estado del procesador. Por último, a dicha variable se le asigna el
contenido del segundo parámetro, 9DORU. De esta forma se consigue realizar las dos
acciones de comprobación y asignación del valor “ocupado” sin ninguna
interrupción.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
([FOXVLyQ0XWXD 9DULDEOH&HUURMR
(QWUDUB5& TST RC_Eventos
BNZ Entrar_RC
£ (VWDP
MOV 1, RC_Eventos
RV
DOSUL FRPR
RET
6DOLUB5& MOV
RET
0, RC_Eventos QFLSLR
5&B(YHQWRV DB 0
+D\9DULRV$OJRULWPRVTXHOR6ROXFLRQDQ
à 'HNNHUSURFHVRV'LMNVWUDQSURFHVRV
à .QXWK(LVHQEHUJ 0F*XLUH
à $OJRULWPRGHOD3DQDGHUtDGH/DPSRUW
à 3HWHUVRQ
+´3UREOHPDGHOD,QYHUVLyQGH3ULRULGDGHVµ
+£\VLKD\P~OWLSOHVSURFHVDGRUHV"
(O*UDQ3UREOHPDGHHVWDV6ROXFLRQHV
(63(5$
£&RQVXPH5RGDMDVGH7LHPSR
$&7,9$
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Un problema que se puede producir aquí es que un proceso cumpla con el protocolo
de entrada a la región crítica y acceda a ella, pero que a la salida se le olvide
liberarla. El acceso a la región queda bloqueado indefinidamente.
Hasta ahora este método funciona porque las acciones de FRPSUREDU \ SRQHU se
ejecutan como una sola instrucción ininterrumpible, pero veamos con mayor detalle
cómo se ejecuta la instrucción TAS. En primer lugar la CPU toma posesión del bus
(direcciones, datos y control) para leer el contenido del cerrojo de su posición de
memoria. Una vez traído el dato, el procesador suelta la posesión del bus para
analizar el contenido de la variable leída y establecer los IODJV del Registro de
Estado de acuerdo a su valor. Por último, vuelve a adueñarse del bus y realiza la
escritura del cerrojo con el valor que corresponda.
Hemos dicho que “FXDQGR XQ SURFHVR OOHJD D OD HQWUDGD GH OD UHJLyQ FUtWLFD VL OD
YDULDEOHFHUURMR QR WLHQH HO YDORU WRGR OR TXH WLHQH TXH KDFHU HV HMHFXWDUVH HQ
EXFOH KDVWD TXH OD FRQVXOWD GHO UHJLVWUR GH HVWDGR LQGLTXH TXH OD YDULDEOH WHQtD HO
YDORU”. Esto es un problema, o al menos, un gasto inútil de CPU. Si el cerrojo tiene
el valor 1 y el proceso que desea acceder a la región crítica está comprobando
LQLQWHUUXPSLGDPHQWH su valor, está claro que dicho valor no va a cambiar, al menos
mientras tal proceso continúe ejecutando la instrucción TAS. Seguramente habrá
que esperar a que se acabe su porción de tiempo, tome control el proceso que se
encuentra dentro de la región y al finalizar ponga a 0 el cerrojo. Así tenemos que el
proceso que quiere entrar gasta inútilmente sus porciones de tiempo esperando a
que aparezca el valor 0, cosa que nunca va a suceder mientras él tenga la posesión
de la CPU.
Por esto, a este método para conseguir la exclusión mutua se le conoce como
HVSHUDDFWLYD, pues el proceso espera su turno consumiendo, inútilmente, tiempo
de procesador.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6HPiIRURV
En apartados anteriores hemos hablado sobre el ciclo de vida de un proceso,
durante el cual se pasa por periodos de instrucciones de CPU y por periodos de
espera de E/S. Debido a que las operaciones con recursos externos tardan mucho
tiempo en realizarse (incluso puede haber una cola de procesos requiriendo sus
servicios), los procesos que solicitan una operación de E/S pasan a estado de
Espera y ceden la CPU a otro proceso, no desperdiciando así el tiempo de
procesador.
Un semáforo es un tipo abstracto de datos con dos operaciones básicas más una de
inicialización (Figura 22). A las dos operaciones básicas las llamaremos %DMDU y
6XELU, aunque originalmente se llamaran 3 y 9, y posteriormente hayan recibido
otros nombres muy utilizados como (VSHUDU y 6HxDODU :DLW y 6LJQDO. Para cada
región crítica se declara una variable de tipo Semáforo que identifica a la región
como un recurso compartido.
6XELU6 S := S+1;
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
end Semaforos;
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Nos queda hablar de la inicialización del semáforo. Como ya veremos en las notas
sobre su implementación, un semáforo tiene un contador interno asociado, tal que
cada vez que un proceso realiza una operación Bajar sobre él, se decrementa en 1,
hasta llegar a cero. Por esto, el valor inicial de dicho contador indica el número
máximo de procesos que pueden utilizar simultáneamente el recurso asociado. En el
caso de que el recurso sea una región crítica, el valor inicial del semáforo deberá ser
1, pues es el número máximo de procesos que pueden acceder simultáneamente a
la región. Los valores que puede tomar el contador del semáforo son, entonces, 0 y
1; por esto a un semáforo de este tipo se le denomina VHPiIRURELQDULR.
Ahora podemos ver, en la Figura 23, la versión con semáforos de nuestro ejemplo
del Observador y el Reportero. Obsérvese que el programa Cuenta_Eventos
comienza inicializando a 1 el semáforo S, y arrancando a continuación los dos
procesos.
6 HP iIRURV H Q Q X H V W U R H M H P S O R
Program Cuenta_Eventos;
Contador : INTEGER;
S : SEMAFOROS;
process Observador;
repeat
Esperar_Evento;
%DMDU6
Contador := Contador + 1;
6XELU6
forever;
end Observador;
process Reportero;
repeat
%DMDU6
Imprimir (Contador);
Contador := 0;
6XELU6
forever;
end Reportero;
begin
,QLFLDOL]DU6
Observador;
Reportero;
end Cuenta_Eventos;
6 LV W H P D V 2 S H U D W LY R V , * H V W Ly Q G H 3 U R F H V R V
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
0RQLWRUHV
Para evitar el problema de los descuidos del programador a la hora de seguir el
protocolo estipulado para acceder y salir de una región crítica, Hoare propuso en
1974 una primitiva de sincronización de más alto nivel denominada PRQLWRU. Brinch
Hansen propuso otra versión del monitor en 1975, y posteriormente ha habido otras
más, así como también hay diversas políticas de planificación para los procesos que
intervienen en un monitor.
Los monitores tienen una propiedad especial para conseguir la exclusión mutua:
“6RODPHQWHXQSURFHVRSXHGHHVWDUDFWLYRDODYH]GHQWURGHXQPRQLWRU”. Dicho de
otra forma, dado un proceso A que ha llamado a un procedimiento de un monitor, y
mientras se está ejecutando dicho procedimiento, toma el control de la CPU otro
proceso B, si este proceso B llama a cualquier procedimiento del monitor, el proceso
B quedará detenido en la entrada (en estado de Espera) hasta que el proceso A
abandone el monitor.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
6HPiIRURV ,PSOHPHQWDFLyQ
type SEMAFOROS is private;
procedure ,QLFLDOL]DU(S : SEMAFOROS;
Valor : INTEGER);
procedure %DMDU (S : SEMAFOROS);
procedure 6XELU (S : SEMAFOROS);
private -- Inaccesible al usuario
type SEMAFOROS is
record
Contador : INTEGER;
Cola : COLA_PROCESOS;
end;
--
procedure ,QLFLDOL]DU (S : SEMAFOROS;
Valor : INTEGER) is
begin
S.Contador := Valor;
end Inicializar;
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
([FOXVLyQ0XWXD 0RQLWRU
/RVVHPiIRURVVRQXQEXHQPHFDQLVPR
SDUDVLQFURQL]DFLyQGHSURFHVRVSHUR
6LQRVHXVDQDGHFXDGDPHQWH 3$FFHVR&RQFXUUHQWH
RUGHQQ~PHURYDORULQLFLDO 3,QWHUEORTXHRV
8Q0RQLWRUHVXQFRQMXQWRGDWRVFRQVXVSURFHGLPLHQWRVGH
DFFHVRHQFHUUDGRVHQXQPyGXORHVSHFLDO0RQLWRU
6RODPHQWHXQSURFHVRSXHGHHVWDUDFWLYR (;&/86,Ð1
HQXQPRQLWRUHQXQPRPHQWRGDGR 0878$
procedure ,PSULPH is
Imprimir (Num_Eventos);
Num_Eventos := 0;
end Imprime;
process Observador;
repeat
Esperar_Evento;
&RQWUROB(YHQWRV,QFUHPHQWD
forever;
end Observador;
process Reportero;
repeat
&RQWUROB(YHQWRV,PSULPH
Hacer_Otras_Cosas;
forever;
end Reportero;
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Los monitores son una construcción de los lenguajes de programación, de tal forma
que los compiladores saben que las llamadas a los procedimientos de un monitor se
manejan de forma distinta a las llamadas a los procedimientos convencionales.
Normalmente, en la llamada de un proceso a un procedimiento de un monitor, las
primeras instrucciones del procedimiento son para comprobar si algún otro proceso
se encuentra dentro del monitor; si es así, el proceso llamante queda bloqueado
hasta que el otro proceso salga del monitor. Si no hay ningún proceso dentro del
monitor, el proceso llamante puede entrar y continuar la ejecución.
3DVRGH0HQVDMHV
Aunque los semáforos y los monitores son buenos mecanismos para la
sincronización de procesos todavía tienen algunas pegas: los semáforos son de
demasiado bajo nivel, y los monitores solamente están disponibles en unos pocos
lenguajes de programación.
Otro problema con los monitores y los semáforos es que están diseñados para
resolver el problema de la exclusión mutua en sistemas con una o más CPU’s que
comparten una memoria común. Pero cuando se trata de un sistema distribuido,
formado por múltiples procesadores, cada uno con su propia memoria particular y
conectados por una red de área local, estas primitivas se vuelven inservibles, pues
ya no hay variables compartidas, y ninguno de estos mecanismos proporciona
intercambio de información entre máquinas. Se necesita algo más.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
&RPXQLFDFLyQGH3URFHVRV 3DVRGH0HQVDMHV
&RPXQLFDFLyQ
HQWUH3URFHVRV
0HPRULD&RPSDUWLGD 3DVRGH0HQVDMHV
(OSURJUDPDGRUUHVXHOYHORV 1RKD\YDULDEOHV
SUREOHPDVGHFRQFXUHQFLD FRPSDUWLGDV
3URF 3URF
$/*81$6&8(67,21(6
8QLGLUHFFLRQDO Ï0HPRULD&RPSDUWLGD
(O(QODFH
+ 3XHGH6HU
Ï%XV+DUGZDUH
%LGLUHFFLRQDO Ï5HGGH&RPXQLFDFLRQHV
Ï&RPXQLFDFLyQ',5(&7$R,1',5(&7$
+ 0RGHORV
/yJLFRV Ï&RPXQLFDFLyQ6,0e75,&$2$6,0e75,&$
+ &DSDFLGDGGHO%X]yQ
Ï)LMR
+ 7DPDxRGHO0HQVDMH
Ï9DULDEOH
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• ¿Cuál es el tamaño de los mensajes? ¿El tamaño es fijo o puede ser variable?
• ¿Un enlace puede ser unidireccional o bidireccional? Es decir ¿los mensajes
solamente pueden viajar en un sentido, o en ambos?
• Modelos de comunicación: comunicación directa o indirecta, simétrica o
asimétrica.
• La información se puede enviar por copia o por referencia.
En cuanto al tamaño de los mensajes que se envían los procesos, pueden ser de
longitud fija o variable. Si sólo se permiten mensajes de longitud fija, la
implementación del sistema es más fácil, pero tal restricción dificulta la tarea del
programador.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
0RGHORVGH&RPXQLFDFLyQ
Primero debemos decir que los procesos reciben mensajes en EX]RQHV. Es decir,
que cuando un proceso envía mensajes, estos van a parar a buzones, y los
procesos que quieren recibirlos tendrán que sacarlos de esos buzones.
Los procesos que desean comunicarse deben disponer de una manera explícita de
indicar el destino del mensaje que se envía, o el remitente del mensaje que se
quiere recibir, y esto depende de que la comunicación sea 'LUHFWD o ,QGLUHFWD.
&RPXQLFDFLyQ'LUHFWD
En la comunicación directa de envío de mensajes, tanto el emisor como el receptor
deben indicar explícitamente el proceso destino o remitente del mensaje. Así, las
primitivas de envío y recepción tendrán el siguiente aspecto:
(QYLDU3URFHVRB'HVWLQR0HQVDMH
5HFLELU3URFHVRB2ULJHQ0HQVDMH
Como se puede apreciar en el esquema superior de la Figura 27, cada proceso tiene
su propio buzón de recepción de mensajes.
Una variante dentro de esta comunicación directa, es que el modelo sea DVLPpWULFR
(esquema inferior de la Figura 27), es decir, que puede haber múltiples procesos
enviando mensajes a un único receptor, en cuyo caso el proceso receptor no tiene
que indicar de qué proceso quiere recibir mensajes. En la comunicación asimétrica,
la llamada al sistema para enviar mensajes permanece invariable, mientras que la
de recepción, queda así:
5HFLELU,GB3URFHVR0HQVDMH
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3DVRGH0HQVDMHV &RPXQLFDFLyQ'LUHFWD
3&DGDSURFHVRWLHQHVXSURSLREX]yQ
3&DGDSURFHVRLPSOLFDGRGHEHLQGLFDU
H[SOtFLWDPHQWHHOQRPEUHGHOUHFHSWRURHPLVRU
3URF 3URF
(VTXHPD6,0e75,&2
2EVHUYDGRU 5HSRUWHUR
repeat repeat
. . . . . .
Esperar_Evento 5HFLELU2EVHUYDGRU0HQVDMH
. . . . . .
(QYLDU5HSRUWHUR0HQVDMH Imprimir_Evento
forever forever
(QYLDU5HSRUWHUR0HQVDMH
2EV
(VTXHPD$6,0e75,&2
3HJDGHOD
6LFDPELDHOQRPEUHGHXQSURFHVR
&RPXQLFDFLyQ
KD\TXHUHYLVDUWRGDVODVUHIHUHQFLDVDpO
'LUHFWD
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
&RPXQLFDFLyQ,QGLUHFWD
Con la comunicación indirecta, los mensajes se envían a buzones, no a procesos, y,
análogamente, el receptor debe indicar el buzón del que quiere recibir un mensaje,
no de qué proceso. Véase el croquis superior de la Figura 28.
(QYLDU%X]yQ0HQVDMH
5HFLELU%X]yQ0HQVDMH
siendo %X]yQ el identificador del buzón al que se envía o del que se desea recibir un
mensaje.
Observando el citado croquis de la Figura 28, puede verse que, ahora, un enlace de
comunicaciones tiene las siguientes propiedades:
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3DVRGH0HQVDMHV &RPXQLFDFLyQ,QGLUHFWD
2EV /RV%X]RQHV6RQ&RPSDUWLGRV
%X]yQB
Enviar (Buzón_1, Mensaje) Recibir (Buzón_1, Mensaje);
2EV 5HS
%X]yQB
Enviar (Buzón_1, Mensaje) Recibir (Buzón_2, Mensaje);
Enviar (Buzón_2, Mensaje)
2EV 5HS
Enviar (Buzón_2, Mensaje) Recibir (Buzón_2, Mensaje);
/RVPHQVDMHVVHHQYtDQ\UHFLEHQDGHEX]RQHVQRDSURFHVRV
5HSB\5HSBHMHFXWDQRecibir (Buzón_2, Mensaje)
2EVBHQYtDXQPHQVDMHDO%X]yQB
+¢4XpSURFHVRUHFLEHHOPHQVDMHGH2EVB"
(O6LVWHPD2SHUDWLYRRIUHFHVHUYLFLRVSDUD
Procedure &UHDUB%X]RQ (Nombre : in Nombres;
Buzon : out Buzones);
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Obsérvese que, debido a la flexibilidad que ofrece este esquema, se puede tener
cualquier combinación numérica de procesos productores y consumidores de
mensajes:
• Un productor- un consumidor
• Varios productores - un consumidor
• Un productor - varios consumidores
• Varios productores - varios consumidores
• Crear un buzón.
• Conectarse a un buzón.
• Enviar y recibir mensajes de un buzón.
• Destruir un buzón.
Cuando varios procesos vayan a comunicarse mediante un buzón, uno de ellos (el
propietario) lo debe crear y, posteriormente, el resto debe conectarse a él, pues
conocen de antemano el nombre del buzón a compartir. Seguidamente ya pueden
realizar las operaciones de envío y recepción de mensajes utilizando el identificador
de buzón.
&DSDFLGDGGHO%X]yQ
Un buzón tiene una capacidad que determina el número de mensajes que puede
tener almacenados temporalmente. Este almacén se puede ver como una cola de
mensajes asociada al buzón. Básicamente hay tres posibilidades sobre el tamaño
del buzón:
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
• &DSDFLGDG/LPLWDGD
La cola tiene una longitud máxima finita (Q mensajes), lo que quiere decir que,
como mucho, podrá haber Q mensajes en el buzón esperando a ser recibidos por
uno o varios procesos. Así, si la cola no está llena, cuando un proceso envía un
mensaje, éste se encola en el buzón, y el emisor puede continuar la ejecución sin
ninguna espera. El proceso receptor podría estar esperando a recibir un mensaje,
con lo que ahora ya podría recibirlo y continuar también la ejecución; pero
también es posible que no hubiera todavía ningún proceso esperando por el
mensaje, en cuyo caso, el mensaje simplemente queda encolado en el buzón
hasta que un proceso quiera recibirlo. No obstante, ya que el tamaño del buzón
es limitado, si al enviar un mensaje a un buzón, éste está lleno, entonces hay dos
alternativas:
• 6LQ/tPLWHGH&DSDFLGDG
La cola de mensajes tiene una longitud potencialmente infinita, por lo que puede
albergar cualquier número de mensajes, y por lo tanto, el emisor nunca queda
bloqueado.
• &DSDFLGDG1XOD
La longitud máxima de la cola de mensajes es cero, por lo que no puede haber
mensajes en el buzón esperando a ser recibidos. En este caso, el emisor o
remitente que quiera enviar un mensaje debe esperar hasta que el destinatario
reciba el mensaje. Así, los dos procesos deben ponerse de acuerdo en el
momento de realizar el envío/recepción del mensaje para que la transferencia
tenga lugar. En este caso se dice que la comunicación es VtQFURQD. A esta
comunicación síncrona también se le conoce con el nombre de UHQGH]YRXV (cita).
Se debe hacer notar que cuando la capacidad del buzón no es cero, el proceso
emisor no sabe cuándo un mensaje enviado ha llegado a su destino, pues no tiene
que esperar a que el proceso destino lo reciba (comunicación DVtQFURQD), y esto
puede ser crucial para el normal desarrollo del programa. En este caso, el receptor
debería comunicarse explícitamente con el emisor para hacerle saber que ha
recibido el mensaje.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
3DVRGH0HQVDMHV &DSDFLGDGGHO%X]yQ
+&DSDFLGDG/LPLWDGDQPHQVDMHV
6LKD\HVSDFLR⇒(OHPLVRUFRQWLQ~DODHMHFXFLyQ
GHVSXpVGHOHQYtR
6LHVWiOOHQR⇒3(OHPLVRUTXHGDEORTXHDGRKDVWDTXH
KD\DHVSDFLRHQHOEX]yQSDUDGHMDU
XQPHQVDMH
36HGHYXHOYHXQVWDWXV OOHQR
+&DSDFLGDG,OLPLWDGD
(OHPLVRUQXQFDVHEORTXHDHQHOHQYtRGHPHQVDMHV
+&DSDFLGDG1XOD
(OHPLVRUTXHGDEORTXHDGRKDVWDTXHHOUHFHSWRUHVWi
OLVWRSDUDUHFLELUHOPHQVDMH
&RPXQLFDFLyQ 5(1'(=9286
6tQFURQD
(QORVEX]RQHVFRQFDSDFLGDG!
¢&yPRVDEHHOHPLVRUTXHHOPHQVDMHKDOOHJDGRDVXGHVWLQR"
PROCESO P1:
Enviar (P2, Mensaje);
Recibir (P2, Mensaje);
+D\TXHIRU]DUHO
VLQFURQLVPR
PROCESO P2:
Recibir (P1, Mensaje);
Enviar (P1, Mensaje);
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
7KUHDGV
Vamos a comentar ahora un nuevo tipo de procesos que en los últimos años a
surgido con fuerza entre los sistemas operativos y que se adapta especialmente
bien a la estructura de los sistemas con múltiples procesadores: los WKUHDGV o
procesos ligeros.
Los procesos tradicionales (como los de Unix) se crean de tal forma que comparten
el procesador (en un entorno monoprocesador) y a cada uno se le asigna un entorno
de ejecución diferente, es decir, cada uno tiene sus áreas de memoria, sus tablas de
páginas, sus descriptores de los ficheros que maneja, sus EXIIHUV de E/S,
semáforos, etc. Y esto, que parece razonable, se hace para todos los procesos del
sistema, es decir, se trata a todos los procesos del sistema como si fueran
totalmente disjuntos y que lo único que comparten es el procesador.
Ahora bien, hay situaciones en las que un trabajo laborioso, puede descomponerse
en varias subtareas o subprocesos, de tal forma que todos ellos cooperan en la
consecución de un mismo fin. En estos trabajos es normal que haya mucha
comunicación y compartimiento de datos entre los subprocesos componentes. El
mecanismo normal de comunicación en estos casos son los mensajes, que no deja
de ser un mecanismo costoso en tiempo. La comunicación entre procesos por
memoria compartida, aunque rápida, es peligrosa, pues un proceso malintencionado
podría machacar áreas de memoria de otro proceso con el que comparte memoria,
sin embargo esto no es normal en procesos cooperantes.
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
7KUHDGV
3DUDHMHFXWDUXQSURJUDPDVHUHTXLHUH
0& (QWRUQRGH(MHFXFLyQ
(VSDFLRGHGLUHFFLRQHV
9DULDEOHVJOREDOHV
&RQWDGRUGHSURJUDPD )LFKHURVDELHUWRV
3XQWHURGHSLOD 7HPSRUL]DGRUHV
5HJLVWURGHHVWDGR 3URFHVRVKLMRV
5HJLVWURVJHQHUDOHV 6HxDOHV
6HPiIRURV
&RQWDELOLGDG
&DPELRGH 3&DPELRHQHOSURFHVDGRU
FRQWH[WR 3&DPELRGHHQWRUQRGHHMHFXFLyQ
)DOWDVGHSiJLQD
1HFHVDULRFRQ3URFHVRV )DOWDVGHFDFKp
'LVMXQWRV $EULUILFKHURV
/OHQDUEXIIHUVGH(6
3(52
3&UHDFLyQ5iSLGDGH3URFHVRV
3&DPELR5iSLGRGH&RQWH[WR
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
Hemos visto que la creación de un proceso puede ser un tanto costosa, pues crea
un entorno de trabajo totalmente diferente para cada uno. Sin embargo, para
procesos cooperantes parece que no se requieren entornos totalmente distintos,
pues es muy posible que prefieran áreas de memoria comunes para compartir datos
(a su propio riesgo) y comunicarse rápidamente. Es más, seguramente prefieren
compartir las memorias caché, y los EXIIHUV de E/S, pues parte de los datos que
manejan van dirigidos o provienen de las mismas fuentes. Dos o más procesos
gemelos cooperantes podrían compartir incluso el área de código. Según esto, la
creación de procesos cooperantes requeriría un entorno de trabajo muy reducido: la
pila de trabajo y, en caso de procesos no gemelos, un área de memoria para el
código. Esto traería ventajas por dos vertientes:
Por lo visto hasta ahora, parece que sería interesante que los sistemas operativos
ofrecieran dos tipos de procesos (cooperantes y no cooperantes), con sus
correspondientes primitivas de creación, gestión, comunicación y sincronización.
.HUQHOGH62SURFHVRVFRRSHUDQWHV3URFHVRVQRFRRSHUDQWHV
$PRHED 7KUHDG Proceso
&KRUXV 7KUHDG Actor
0DFK 7KUHDG Tarea
96\VWHP Proceso Equipo (7HDP)
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
7KUHDGV
.HUQHOGH62 3URF&RRSHUDQWHV 3URF1R&RRSHUDQWHV
$PRHED 7KUHDG 3URFHVR
&KRUXV 7KUHDG $FWRU
0DFK 7KUHDG 7DUHD
96\VWHP 3URFHVR (TXLSR7HDP
7KUHDG 3URFHVR
R R
3URFHVR/LJHUR 3URFHVR3HVDGR
0D\RU
1~PHURGH 0HMRUDSURYHFKDPLHQWR
3URFHVRV GHORV7KUHDGV
&RRSHUDQWHV
WKUHDG 5$0FRPSDUWLGD
UHSDUWLGRU
/RV6'VHSUHVWDQD WKUHDGV
WHQHUDSOLFDFLRQHV GHVHUYLFLR
IRUPDGDVSRUPXFKRV
SURFHVRVFRRSHUDQWHV
FDFKp
EX]yQ
SHWLFLyQ
6LVWHPDV2SHUDWLYRV, *HVWLyQGH3URFHVRV
$SXQWHVGH62,
*HVWLyQGH3URFHVRV
A los programas con WKUHDGV se les saca más provecho en aplicaciones compuestas
de múltiples procesos cooperantes, y esto es algo que se suele dar mucho en los
sistemas distribuidos, en los que por su filosofía cliente-servidor se prestan mucho a
este tipo de aplicaciones. Debido a la premura de tiempo no vamos a profundizar en
esta justificación, no obstante, se recomienda echar un vistazo a los capítulos
dedicados a WKUHDGV de los textos indicados en la bibliografía, en los cuales pueden
encontrarse numerosos ejemplos de situaciones de programas en las que se
muestran beneficios de los WKUHDGV frente a los procesos convencionales.
Algunos datos sobre los tiempos creación de procesos nos pueden ayudar a
convencernos de las ventajas de los WKUHDGV. La creación de un proceso Unix sobre
un procesador CVAX de DIGITAL requiere 11 milisegundos, mientras que la
creación de un WKUHDG en un kernel llamado Topaz, sobre el mismo procesador
solamente necesita 1 milisegundo. Los tiempos de cambio de contexto entre
procesos Unix oscilan alrededor de 1,8 milisegundos, siendo solamente 0,4 ( y en
algunos casos 0,004) entre WKUHDGV de Topaz. A estos datos habría que añadir los
beneficios que se ganan a largo plazo, es decir, el tiempo que no se pierde en
cargar de nuevo las páginas de memoria virtual, de la caché, creación de
semáforos, apertura y cierre de ficheros, llenado de EXIIHUV de E/S, etc.
$SXQWHVGH62,