Documente Academic
Documente Profesional
Documente Cultură
2 - Procesos e hilos
Lectura a disco
P0
file descriptor
variables de entorno
seales
Cant. de instrucciones
P1
Peticin
a disco
[P0]
Tiempo
Excede quantum
P0
P1
Peticin
a disco
[P0]
Tiempo
Fin de
tiempo
[P1]
Envo de mensaje
Cant. de instrucciones
P0
Cant. de instrucciones
P1
Peticin
a disco
[P0]
Fin de
tiempo
[P1]
Uso
de red
[P0]
P0
Cant. de instrucciones
P0
P1
Peticin
a disco
[P0]
Fin de
tiempo
[P1]
Uso
de red
[P0]
P1
Tiempo
Lo que uno ve
Tiempo
Por consiguiente:
secuencial/determinista
Por consiguiente:
Procesos: Creacin
Sistemas simples -> Todos los procesos se crean al principio
Observar:
La velocidad con que el proceso realiza su ejecucin no es
uniforme
Por consiguiente:
Los procesos no deben programarse con presuposiciones
temporales
Procesos:Foreground
Creacin
-> procesos que interactan
Procesos: Creacin
Background:
Sistemas simples -> Todos los procesos
se crean al principio
ps -ax
Sistemas de propsitos
generales
-
- Ej:
determinan
la creacin de un proceso:
Procesos: Creacin
Procesos: Creacin
Sistemas interactivos:
- doble click o
-d
Procesos: Creacin
Procesos: Creacin
incluyendo
variables de entorno,
archivos abiertos, espacio de
direccionamiento, etc.
! fork -> crea una copia exacta del proceso que llama
UNIX " execve -> llamada por el proceso hijo para ejecutar un
nuevo programa
#
! fork -> crea una copia exacta del proceso que llama
UNIX " execve -> llamada por el proceso hijo para ejecutar un
nuevo programa
#
Procesos: Creacin
Procesos: Terminacin
voluntaria
!
"
#
fork
Terminacin
En UNIX, el espacio de
UNIX direccionamiento
execve -> llamada
procesodireccionamiento
hijo para ejecutar
se copia.un
del padre por
y delel
hijo
son distintos.
nuevo programa (En algunos UNIX: copy on write)
Windows -> Slo una llamada: CreatProcess + 10 parmetros
En ambos casos los espacios de direcciones de padre e hijo son
disjuntos
involuntaria
Normal:
Ej: exit(0), Quit del men
Errnea:
Ej: gcc test.c, pero test.c
no existe -> exit(4)
Error causado por el proceso:
Ej: divisin por 0, referencia a
una dir. de mem. inexistente
Matado por otro proceso: kill
Ej: killall mozilla.bin.
Procesos: Jerarqua
UNIX:
Jerrquico: se mantiene la estructura padre-hijo segn
creacin
Ver con pstree
Tiene cierta utilidad para manejar grupo de procesos
Windows:
No hay jerarqua
Slo existe un token especial (handle) que se retorna al padre
en la creacin, pero este puede cederlo a otro proceso
dargenio@russell:~$ pstree
init!"!acpid
#!apache2!!!10*[apache2]
#!3*[automount]
#!cron
#!dnsmasq
#!fail2ban-server!!!8*[{fail2ban-serve}]
UNIX:
#!6*[getty]
#!klogd
Jerrquico: se mantiene la estructura
padre-hijo segn
#!mailmanctl!!!8*[python]
#!master!"!pickup
creacin
$
#!qmgr
$
%!tlsmgr
Ver con pstree
#!mysqld_safe!"!logger
$
%!mysqld!!!17*[{mysqld}]
Tiene cierta utilidad para manejar
grupo de procesos
#!portmap
#!rpc.idmapd
#!rpc.mountd
#!rpc.statd
#!rpc.yppasswdd
Windows:
#!rpc.ypxfrd
#!sensord
No hay jerarqua
#!sshd!"!sshd!!!sshd!!!bash!!!ssh
$
%!sshd!!!sshd!!!bash!!!pstree
Slo existe un token especial#!syslogd
(handle) que se retorna al padre
#!udevd!!!2*[udevd]
en la creacin, pero este puede
cederlo a otro proceso
#!ypbind!!!2*[{ypbind}]
%!ypserv
Procesos: Jerarqua
Ejecutando
bloqueado ! listo
Suspensin inherente
al problema
Bloqueado
Listo
El proceso en ejecucin
algn
evento
requiere
algn
eventoparticular
para
continuar (ej: el arribo de un
dato de entrada)
Ejecutando
Bloqueado
Ejecutando
Listo
Bloqueado
Listo
se libera yde
un
Bloqueado: imposibilitado de ejecutar hastaLalaCPU
ocurrencia
proceso en la cola de listos
algn evento particular
Ejecutando
Bloqueado
Listo
evento esperado. El
proceso est ahora listo para
ejecutar (ej: ya se
produjo la entrada)
Bloqueado
Ejecutando
Listo
Lgicamente,
los estados ejecutando y listo
son similares: en ambos casos el
proceso est dispuesto a
ejecutar
La forma en de
la
Bloqueado: imposibilitado de ejecutar hasta la ocurrencia
que se administran estas
algn evento particular
dos transiciones es tarea del
Ejecutando
Bloqueado
En cambio, si el
proceso est bloqueado,
ste no puede ejecutar an
si la CPU est ociosa.
Listo
Procesos: ejecutan
Procesos: Estado deprogramas
los procesos
de usuarios, o son parte
Modelo en capas
planificador de procesos o
scheduler
Ejecutando
Bloqueado
Listo
Procesos: Implementacin
Se implementa a travs de tablas de procesos
Tabla de procesos -> arreglos o listas:
una entrada por proceso
Procesos
Scheduler
Scheduler (o Planificador):
da la ilusin de mltiples CPU
Procesos: Implementacin
Depende
del procesador y del sistema
operativo
Hilos (Threads)
Sistemas operativos tradicionales
->cada proceso tiene un espacio de dir. y un slo hilo de control
Hay situaciones en las que es conveniente tener varios hilos de
ejecucin en el mismo espacio de direccionamiento.
Como si fueran procesos (casi) separados excepto que
comparten el espacio de direccionamiento.
Hilos: Uso
Por qu queremos hilos?
Hilos: Uso
Por qu queremos hilos?
Y no tenemos a los
procesos para esto?
Hilos: Uso
simultneamente:
1. prepaginado
2. impresin
Adems:
4. backup automtico
1. prepaginado
2. impresin
Para manejar muchas actividades al mismo
tiempo
3. spell checking
Adems:
4. backup automtico
Hilos: Uso
1. prepaginado
2. impresin
Para manejar muchas actividades al mismo
tiempo
Adems:
3. spell checking
4. backup automtico
agrupacin de recursos
ejecucin
funcionar
funcionar
agrupacin de recursos
agrupacin de recursos
ejecucin
ejecucin
registra cual es la
instruccin que se ejecutar a
continuacin
contiene las variables
de trabajo actuales
contiene el historial de
llamadas a procedimientos pendientes a
lo largo de la ejecucin
es comparable a
n procesos en 1 CPU
los procesos
comparten mem. fsica, disco,
y otros recursos.
n procesos en 1 CPU
Bloqueado
Listo
Bloqueado
Listo
Espacio de direccionamiento
Contador de programa
Espacio de direccionamiento
Contador de programa
Variables globales
Registros
Variables globales
Registros
Archivos abiertos
Pila
Archivos abiertos
Pila
Procesos hijos
Estado
Procesos hijos
Estado
Alarmas pendientes
Alarmas pendientes
Informacin administrativa
Informacin administrativa
P 1:
x := 2;
{ x = ? }
P 1:
x := 2;
{ x = ? }
P 1:
x := 2;
{ x = 2 }
{ x = 2 }
P 1:
x := 2;
{ x = 2 }
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 }
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 0 }
P 0:
x := x+1;
P 1:
x := x+1;
{ x = ? }
Esto se denomina
condicin de carrera
P 1:
x := 2;
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = ? }
{ x = 0 }
P 0:
x := 1;
{ x = 1 x = 2}
{ x = 0 }
P 1:
x := 2;
{ x = 1 x = 2}
Estas instrucciones
pueden no realizarse de
manera atmica (indivisible)
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = ? }
AX = ?
x = 0
Esto se denomina
condicin de carrera
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 0
x = 0
{ x = ? }
MOV AX, x
ADD AX, 1
MOV x, AX
P 0:
x := 1;
MOV AX, x
ADD AX, 1
MOV x, AX
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 0 }
P 0:
x := 1;
{ x = 0 }
{ x = 0 }
{ x = ? }
AX = 1
x = 1
MOV AX, x
ADD AX, 1
MOV x, AX
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
x = 0
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 1
{ x = ? }
Esto se denomina
condicin de carrera
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = ? }
El scheduler
cambia de proceso
AX = ?
x = 1
Esto se denomina
condicin de carrera
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 1
x = 1
{ x = ? }
MOV AX, x
ADD AX, 1
MOV x, AX
P 0:
x := 1;
MOV AX, x
ADD AX, 1
MOV x, AX
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 0 }
P 0:
x := 1;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = ? }
x = 1
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 2
{ x = ? }
Esto se denomina
condicin de carrera
AX = 2
x = 2
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = 2 }
Esto se denomina
condicin de carrera
Esto se denomina
condicin de carrera
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
AX = ?
x = 0
{ x = 2 }
MOV AX, x
ADD AX, 1
MOV x, AX
P 0:
x := 1;
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 0
x = 0
{ x = 2 }
Esto se denomina
condicin de carrera
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
EL SCHEDULER DECIDE
CAMBIAR DE PROCESO
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = 2 }
{ x = 0 }
AX = 1
x = 0
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = 2 }
AX = ?
x = 0
Esto se denomina
condicin de carrera
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 0
x = 0
{ x = 2 }
MOV AX, x
ADD AX, 1
MOV x, AX
P 0:
x := 1;
MOV AX, x
ADD AX, 1
MOV x, AX
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 0 }
P 0:
x := 1;
{ x = 0 }
{ x = 0 }
{ x = 2 }
AX = 1
x = 1
MOV AX, x
ADD AX, 1
MOV x, AX
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
x = 0
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
AX = 1
{ x = 2 }
Esto se denomina
condicin de carrera
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = 2 }
AX = 1
x = 1
Esto se denomina
condicin de carrera
P 1:
x := 2;
P 1:
x := 2;
{ x = 1 x = 2}
{ x = 1 x = 2}
{ x = 0 }
{ x = 0 }
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
MOV AX, x
ADD AX, 1
MOV x, AX
P 0:
x := 1;
Esto se denomina
condicin de carrera
P 1:
x := 2;
{ x = 1 x = 2}
Conclusin:
el
scheduler es MANDINGA
{ x = 0 }
en persona!!
AX, x
MOV AX, x
MOV
ADD AX, 1
MOV x, AX
ADD AX, 1
MOV x, AX
{ x = 1 x = 2}
MOV AX, x
ADD AX, 1
MOV x, AX
{ x = 1 x = 2}
{ x = 1 }
{ x = 0 }
Esto se denomina
condicin de carrera
P 1:
x := 1;
x := x+1;
{ x = ? }
Cul es la postcondicin si
las instrucciones son atmicas?
Y si no lo son?
Queda como
ejercicio
Porque:
1. es imposible, y
2. no debera ser necesario!
Mientras que los procesos son hostiles entre ellos, compitiendo
por recursos,
P 0:
call Foo(x);
P 1:
call Faa(y);
los hilos cooperan entre s para llevar a cabo una tarea comn.
Para lograr una cooperacin adecuada los hilos necesitan
sincronizarse apropiadamente
Pila
Lo posponemos para la
prxima clase
P 0:
call Foo(x);
P 0:
call Foo(x);
P 1:
call Faa(y);
x
dir ret Foo
Pila
* CS = Context Switch
1. P0 llama al
2. CS durante
3. P1 llama al
4. CS durante
P 1:
call Faa(y);
procedimiento Foo(x)
la ejecucin de Foo
procedimiento Faa(y)
la ejecucin de Faa
* CS = Context Switch
y
dir ret Faa
x
dir ret Foo
Pila
P 0:
call Foo(x);
P 0:
call Foo(x);
P 1:
call Faa(y);
y
dir ret Faa
P 1:
call Faa(y);
La historia de la ejecucin
es local a cada hilo
Pila
Pila P0
Pila P1
* CS = Context Switch
Crea un
nuevo hilo (usualmente con un parmetro)
Habitualmente no hay relacin padre-hijo
Retorna un identificador del nuevo hilo.
Se entrega
voluntariamente al scheduler dando la
posibilidad a otros hilos de ejecutar
Ventajas:
semejante si ocurre un
fallo de pgina
Creacin/terminacin de hilos a
travs de syst. calls al kernel
Creacin/terminacin de hilos a
travs de syst. calls al kernel
Para qu?
Para qu?
compartir y
compartir y
sincronizar
sincronizar
Menos obvio
Fcil
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
8
9
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
out = 4
Qu hace esto?
Anda bien?
in = 7
8
9
out = 4
B1
B2
A2
Cmo termina
la ejecucin?
in = 7
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
J4
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
8
9
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
J5
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
8
9
out = 4
B1
B2
in = 7
A2
out = 4
B1
B2
Cmo termina
la ejecucin?
Cmo termina
la ejecucin?
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
J5
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
8
9
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
J5
Basura
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
out = 4
B1
B2
A2
in = 8
9
out = 4
Cmo termina
la ejecucin?
in = 7
A2
B1
B2
A2
Cmo termina
la ejecucin?
in = 9
Buffer
circular
J1
J2
J3
Proc_A:
...
A1: spl->buf[in] = J4;
A2: spl->in ++;
...
J5
Basura
Proc_B:
...
B1: spl->buf[in] = J5;
B2: spl->in ++;
...
B1
B2
A2
Hola.
out = 4
Soy yo, MANDINGA.
Otra in
vez= 9
Buffer
circular
J1
J2
de carrera es una
6
situacin donde dos o ms proceso (o hilos)
Proc_A:
Proc_B:
7
en un rea compartida y el
... deben leer o escribir
...
8
A1: spl->buf[in]
= J4; final
B1: spl->buf[in]
= J5;
resultado
depende de qu
proceso
9
A2: spl->in ++;
B2: spl->in ++;
ejecuta ...
y cundo lo hace
...
Hola.
J3
J5
Basura
out = 4
in = 9
P 0:
do true ->
RNC0
Inicio RC0
RC0
Fin RC0
od
P 1:
do true ->
RNC1
Inicio RC1
RC1
Fin RC1
od
La idea es tratar de
construir el cdigo que
implemente Inicio RC y
Fin RC para asegurar
exclusin mutua de las RCi
Tpicamente analizaremos
programas con esta pinta.
P 0:
do true ->
RNC0
Inicio RC0
RC0
Fin RC0
od
P 1:
do true ->
RNC1
Inicio RC1
RC1
Fin RC1
od
Ya lo vimos
Requerimiento de progreso
Requerimiento de equidad
(fairness)
Ya lo vimos
Requerimiento de progreso
Requerimiento de equidad
(fairness)
Requerimientos de vitalidad
(liveness - algo bueno va a pasar)
esto?
Requerimiento de progreso
Requerimiento de equidad
(fairness)
No funciona
Funciona?
P 1:
do true ->
RNC1
CLI
RC1
STI
od
Requerimientos de vitalidad
(liveness - algo bueno va a pasar)
Fin RC
P 0:
do true ->
RNC0
CLI
RC0
STI
od
kernel, Regiones
por ej: durante lacrticas
actualizacin de la
Comunicacin e/proc.:
Deshabilitar interrupciones:
Ya lo vimos
Deshabilitar interrupciones:
Fin RC
P 0:
do true ->
RNC0
CLI
RC0
STI
od
P 1:
do true ->
RNC1
CLI
RC1
STI
od
Variable candado:
Init:
lock = 0
Inicio RC:
Fin RC:
lock = 0
{ lock == 0 }
Variable candado:
Variable candado:
Init:
lock = 0
Inicio RC:
Fin RC:
lock = 0
Funciona?
Init:
lock = 0
Inicio RC:
Fin RC:
lock = 0
{ lock == 0 }
P0: do true ->
A1
RNC0
A2
do (lock==1) -> skip od
A3
lock = 1
A4
RC0
A5
lock = 0
od
No funciona
Viola seguridad
(condicin 1)
{ lock == 0 }
Contraejemplo: A1 B1 A2 B2 A3 B3 A4 B4
procesos
acceden
a la RC
Exclusin mutua con espera ocupada
(busy
waiting)
Alternancia estricta:
procesos
acceden
a la RC
Exclusin mutua con espera ocupada
(busy
waiting)
Alternancia estricta:
Funciona?
Init:
turn = 0
Inicio RC:
Fin RC:
turn = (turn+1)%CANT_PROC
{ turn == 0 }
Funciona?
Init:
turn = 0
Inicio RC:
Fin RC:
turn = (turn+1)%CANT_PROC
{ turn == 0 }
Consideremos la secuencia:
Alternancia estricta:
Init:
turn = 0
Inicio RC:
Fin RC:
turn = (turn+1)%CANT_PROC
{ turn == 0 }
Busy waiting
Algoritmo de Peterson:
En 1959, Edsger W. Dijkstra plante el problema de exclusin mutua en
el Departamento de Computacin del Matematisch Centrum (Amsterdam).
Bsicamente solicitaba las mismas condiciones que planteamos antes.
Consideremos la secuencia:
Hasta que Dijkstra se pudri y cambi las reglas: quien trajera una
solucin deba tambin traer la demostracin de su correccin
Theodorus J. Dekker propuso entonces una solucin para 2 procesos
con demostracin y todo
Mezclaba la idea de locks y turno de los algoritmos anteriores
Inicio RC:
want[i] = true
turn = 1-i
do (want[1-i] && turn==1-i) -> skip od
Fin RC:
want[i] = false
{ turn == 0
&&
Funciona
P0:
do true ->
RNC0
want[0] = true
turn = 1
do (want[1] && turn==1) -> skip od
RC0
want[0] = false
od
P1:
do true ->
RNC1
want[1] = true
turn = 0
do (want[0] && turn==0) -> skip od
RC1
want[1] = false
od
Fin RC:
want[i] = false
{ turn == 0
&&
P0:
do true ->
RNC0
want[0] = true
turn = 1
do (want[1] && turn==1) -> skip od
RC0
want[0] = false
od
P1:
do true ->
RNC1
want[1] = true
turn = 0
do (want[0] && turn==0) -> skip od
RC1
want[1] = false
od
Algoritmo de Peterson:
Ejercicios:
Observar que no sufre de retraso innecesario como el de
alternancia estricta. Mostrar que P0 puede entrar varias veces
aunque P1 no progrese.
El algoritmo es muy delicado: intercambiar las asignaciones en
Inicio RCarruina el algoritmo => dar una ejecucion que lo
muestre
Dar una demostracin de que este algoritmo funciona [Difcil!!]
Generalizar a N procesos
rx;
Exclusin mutua con espera ocupadaregister
(busy int
waiting)
Init:
Fin RC:
lock = 0
=> S funcionara
Esto requiere de una ayuda del hardware (y van...):
TSL RX, lock
registro
RX ! lock
lock ! 1
memoria
La CPU garantiza que el
scheduler no interrumpe entre medio
de la ejecucin de ambas
instrucciones
Con N procesos
se resuelve de la misma
manera
{ lock == 0 }
P 0:
do true ->
RNC0
do test_set(&lock) -> skip od
RC0
lock = 0
od
P 1:
do true ->
RNC1
do test_set(&lock) -> skip od
RC1
lock = 0
od
{ lock == 0 }
{ lock == 0 }
Qu observan?
P 0:
do true ->
...
do test_set(&lock) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock = 0
...
do test_set(&lock) -> skip od
fd = tb_get(fd_tb,fid)
lock = 0
...
od
P 1:
do true ->
...
do test_set(&lock) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock = 0
...
do test_set(&lock) -> skip od
fd = tb_get(fd_tb,fid)
lock = 0
...
od
Bloqueo al cuete!
P 0:
do true ->
...
do test_set(&lock) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock = 0
...
do test_set(&lock) -> skip od
fd = tb_get(fd_tb,fid)
lock = 0
...
od
P 1:
do true ->
...
do test_set(&lock) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock = 0
...
do test_set(&lock) -> skip od
fd = tb_get(fd_tb,fid)
lock = 0
...
od
Sincronizacin bloqueante
Tanto Peterson como TSL funcionan correctamente
P 0:
do true ->
...
do test_set(&lock1) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock1 = 0
...
do test_set(&lock2) -> skip od
fd = tb_get(fd_tb,fid)
lock2 = 0
...
od
P 1:
do true ->
...
do test_set(&lock1) -> skip od
p.id = tb_alloc(proc_tb,pcb)
lock1 = 0
...
do test_set(&lock2) -> skip od
fd = tb_get(fd_tb,fid)
lock2 = 0
...
od
{ lock == 0 }
P 0:
do true ->
A1 RNC0
A2 do test_set(&lock) -> skip od
A3 RC0
A4 lock = 0
od
P 1:
do true ->
B1 RNC1
B2 do test_set(&lock) -> skip od
B3 RC1
B4 lock = 0
od
!
"
#
!
"
#
!
"
#
Sincronizacin bloqueante
Sincronizacin bloqueante
Ocurre lo mismo en
schedulers no apropiativos y
{ lock == 0 }
suponiendo que P0 realiza E/S en
la ejecucin de la RC
P 1:
P 0:
do true ->
A1 RNC0
A2 do test_set(&lock) -> skip od
A3 RC0
A4 lock = 0
od
do true ->
B1 RNC1
B2 do test_set(&lock) -> skip od
Problema
B3 RC1
de inversin de
B4 lock = 0
prioridades
od
!!!!!
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
sleep(queue)
A1 A2 A3 B1 B2 B2 B2 B2 B2 B2 B2 B2 B2 B2 B2 B2 B2 .....
Sincronizacin bloqueante
(buf_remove) datos
Funciona?
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 0
qp = []
qc = []
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 0
qp = []
qc = []
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 0
qp = []
qc = []
Sincronizacin bloqueante
(buf_remove) datos
Sincronizacin bloqueante
(buf_remove) datos
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Sincronizacin bloqueante
(buf_remove) datos
Funciona?
count = 0
qp = []
qc = []
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 0
qp = []
qc = []
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 1
qp = []
qc = []
Sincronizacin bloqueante
(buf_remove) datos
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 1
qp = []
qc = []
El consumidor an
El consumidor excede su tiempo
no est encolado!
Sincronizacin bloqueante
(buf_remove) datos
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Sincronizacin bloqueante
(buf_remove) datos
Funciona?
count = 1
qp = []
qc = []
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 1
qp = []
qc = []
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 1
qp = []
qc = [Cons]
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = 2
qp = []
qc = [Cons]
El consumidor se bloquea
Contina ejecutando el productor
Sincronizacin bloqueante
(buf_remove) datos
El consumidor se bloquea
Contina ejecutando el productor
Sincronizacin bloqueante
(buf_remove) datos
El consumidor se bloquea
Contina ejecutando el productor
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Sincronizacin bloqueante
(buf_remove) datos
Funciona?
count = ...
qp = []
qc = [Cons]
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
El consumidor se bloquea
Contina ejecutando el productor
Funciona?
count = N
qp = []
qc = [Cons]
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = N
qp = []
qc = [Cons]
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
Funciona?
count = N
qp = []
qc = [Cons]
El consumidor se bloquea
Contina ejecutando el productor
Sincronizacin bloqueante
(buf_remove) datos
El consumidor se bloquea
Contina ejecutando el productor
Sincronizacin bloqueante
(buf_remove) datos
El consumidor se bloquea
Contina ejecutando el productor
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Sincronizacin bloqueante
(buf_remove) datos
Funciona?
count = N
qp = []
qc = [Cons]
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
El productor se bloquea
=> Deadlock!
No funciona
count = N
qp = [Prod]
qc = [Cons]
Sincronizacin bloqueante
(buf_remove) datos
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
No funciona
count = N
qp = [Prod]
qc = [Cons]
V(sem) :
Productor:
do true ->
d = produce_item()
if (count == N)
-> sleep(qp) fi
buf_insert(b,d)
count = count + 1
if (count == 1)
-> wakeup(qc) fi
od
Tratemos de enternder
por qu surge el problema
Consumidor:
do true ->
if (count == 0)
-> sleep(qc) fi
d = buf_remove(b)
if (count = N-1)
-> wakeup(qp) fi
count = count - 1
consume_item(d)
od
No funciona
count = N
qp = [Prod]
qc = [Cons]
{
{
consumidores, respect.
[Dijkstra 1965]
P(sem) :
Semforos
Sincronizacin bloqueante
(buf_remove) datos
Nunca se
bloquea
P es por probeer te verlagen (intentar decrementar)
y V es por verhogen (incrementar)
Consumidor:
do true ->
P(full)
P(mutex)
d = buf_remove(b)
V(mutex)
V(empty)
consume_item(d)
od
Semforos
Semforos
En particular, mutex es
un semforo que slo manipula dos
estados:
o desbloqueado. Este
Solucin de Productores/Consumidores
conbloqueado
3 semforos:
tipo de semforos se denomina
full -> cuenta la cantidad de lugares
ocupados en el buffer
semforo binario o mutex.
Consumidor:
do true ->
P(full)
P(mutex)
d = buf_remove(b)
V(mutex)
V(empty)
consume_item(d)
od
Comunicacin e/proc.:ParaRegiones
crticas
mltiples core usar TSL o XCHG.
Solo funciona
en mquinas de una
sola CPU
Semforos
No queda otra que busy waiting, pero notar
que es muy localizado.
Opiniones?
void V(Semaphore s) {
Deshab. interrup.
if (isEmpty(s->q)) {
s->count ++;
} else {
thread = RemoveFirst(s->q);
wakeup(thread);
}
Hab. interrup.
}
void V(Semaphore s) {
Deshab. interrup.
if (isEmpty(s->q)) {
s->count ++;
} else {
thread = RemoveFirst(s->q);
wakeup(thread);
}
Hab. interrup.
}
Semforos
Implementacin de mutexes en espacio de usuario.
Mucho ms eficiente
mutex_lock:
TSL RX, mutex
CMP RX, #0
JZE ok
CALL thread_yield
JMP mutex_lock
ok: RET
|
|
|
|
|
|
mutex_unlock:
MOVE mutex, #0
RET
| guardar 0 en mutex
| retornar
Monitores
Monitores
Consumidor:
do true ->
P(mutex)
P(full)
d = buf_remove(b)
V(mutex)
V(empty)
consume_item(d)
od
Funciona?
Productor:
do true ->
d = produce_item()
P(empty)
P(mutex)
buf_insert(b,d)
V(mutex)
V(full)
od
Consumidor:
do true ->
P(mutex)
P(full)
d = buf_remove(b)
V(mutex)
V(empty)
consume_item(d)
od
No funciona
Deadlock!
Monitores
Monitores
Muy importante
Productores/Consumidores:
monitor syncBuff
int count = 0
buffer b = []
condvar full, empty
procedure insert(d:Data){
if count == N -> wait(full) fi
buf_insert(b,d)
count = count + 1
if count == 1 -> signal(empty) fi
}
function remove() data {
if count == 0 -> wait(empty) fi
result = buf_remove(b)
count = count - 1
if count == N-1 -> signal(full) fi
return(result)
}
end monitor
Productor:
do true ->
d = produce_item()
syncBuff.insert(d)
od
Consumidor:
do true ->
d = syncBuff.remove(b)
consume_item(d)
od
Variables
Productores/Consumidores: de condicin:
definen una cola de
monitor syncBuff
procesos
int count = 0
buffer b = []
condvar full, empty
procedure insert(d:Data){
if count == N -> wait(full) fi
buf_insert(b,d)
count = count + 1
if count == 1 -> signal(empty) fi
}
function remove() data {
if count == 0 -> wait(empty) fi
result = buf_remove(b)
count = count - 1
if count == N-1 -> signal(full) fi
return(result)
}
end monitor
Todos los
procedimientos y funciones se
ejecutan en exclusin mutua
Levanta la exclusin
mutua y duetme al proceso
encolndolo en full
Despierta a un
proceso encolado en full
(si es que hay)
int count = 0
buffer b = []
condvar full, empty
procedure insert(d:Data){
if count == N -> wait(full) fi
buf_insert(b,d)
count = count + 1
Las implementaciones
if count == 1 -> signal(empty) fi
existentes (como en Java), no
}
function remove() data {
aqu explicadas
if count == 0 -> wait(empty) fi
result = buf_remove(b)
count = count - 1
if count == N-1 -> signal(full) fi
return(result)
}
end monitor
Todos los
procedimientos y funciones se
ejecutan en exclusin mutua
Levanta la exclusin
mutua y duetme al proceso
encolndolo en full
Despierta a un
proceso encolado en full
(si es que hay)
Atencin!
La correccin depende
de esta poltica
Varias polticas para signal:
despierta y continua ejecutando
despierta y espera [Hoare]
despierta y termina [Brinch Hansen]
Barreras
Monitores
Variables
Productores/Consumidores: de condicin:
definen una cola de
monitor syncBuff
procesos
Fili:
do true ->
pensar
tomar_tenedor(i)
tomar_tenedor((i+1)%5)
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
tomar_tenedor(i)
tomar_tenedor((i+1)%5)
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Funciona?
No funciona
Deadlock!
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
Funciona?
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
Fili:
do true ->
pensar
done = false
do !done ->
tomar_tenedor(i)
if tenedor_disponible (i)
then
tomar_tenedor((i+1)%5)
done = true
else
dejar_tenedor(i)
fi
od
No funciona
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
od
etc.
Inanicin!
Funciona
Cmo se implementa?
Cuando termina de
comer, libera la silla y
vuelve a pensar
{ sillas == 4 }
Fili:
do true ->
pensar
P(sillas)
tomar_tenedor(i)
tomar_tenedor((i+1)%5)
comer
dejar_tenedor(i)
dejar_tenedor((i+1)%5)
V(sillas)
od
Es decir, a la RC
Supongamos que
r cuenta la cant. de lectores accediendo a la BD a la vez, y
w cuenta la cant. de escritores accediendo a la BD a la vez
Qu es lo que necesitamos que funcione?
(w " 1) ((w = 1)
Nunca puede
acceder ms de un escritor
a la vez
Invariante de
seguridad
(r = 0))
Si un escritor est
accediendo, ningn lector puede estar
leyendo
!
"
#
Problema de equidad
(fairness) si hay un flujo
continuo de lectores
((w = 1) (r = 0)) (w = 0)
(w " 1) ((w = 0) (r = 0))
Lector:
do true ->
P(mutex)
cant_r ++
if (cant_r == 1) -> P(sem_w)
V(mutex)
// Leer
P(mutex)
cant_r -if (cant_r == 0) -> V(sem_w)
V(mutex)
od
Investiguen
Investiguen