Sistemas Operacionais
Processos
Processo
processo:
programa em execução
consiste de:
código do programa executável
dados
pilha de execução
contador de programa
valores de registros
informações sobre estado de acesso a arquivos
etc.
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Árvore de Processos
A
B
C
D
E
F
X
Processo
criação dinâmica de processos
processo pai
processos
filhos de A
processos
filhos de B
processo pai
Criação de Processos no Unix
#include <stdlib.h>
#define SHELL “/bin/sh”
int my_system (const char *command) {
int status;
pid_t pid;
pid = fork();
if (pid == 0) {
execl (SHELL, SHELL, “-c”,
command, NULL);
exit (EXIT_FAILURE);
} else if (pid < 0)
status = -1;
else if (waitpid (pid, &status, 0) != pid)
status = -1;
return status;
}
main (int argn, char **argc) {
my_system (“ls -la”);
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
struct task_struct
armazena informações sobre processos
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Alguns Atributos de Processos
uid (user identification)
gid (group identification)
diretório corrente de trabalho
descritores de arquivo padrão:
standard input
standard output
standard error
Estados de um Processo
Executando
Pronto
Bloqueado
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Escalonamento de Processos
Scheduler
Processos
...
0
1
n-1
Implementação de Processos
o sistema operacional mantém uma tabela de
processos
na tabela de processos há uma entrada por
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Exemplo de Tabela de Processos
Gerenciamento
de Processos
Gerenciamento
de Memória
Gerenciamento
de Arquivos
registradores
program counter
apontador da pilha
estado do processo
tempo de início de
execução
tempo de CPU usado
...
apontador para
segmento de código
apontador para
segmento de dados
...
diretório raiz
diretório corrente
descritores de
arquivos
...
Processo
código
dados
pilha
heap
Abstrato
Concreto
Processos
•Comunicação para realização das tarefas
•Processos Independentes,
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Processos em Sistemas Centralizados
Comunicação
Compartilhamento de Memória
Primitivas: Semáforos, filas de mensagens, monitores,
sinais etc
Relógio Único
RAM
Pi
Pj
Pk
Pn
Processos em Sistemas Distribuídos
Comunicação
Troca de Mensagens
Primitivas:
send(destino, mensagem) e receive(origem, mensagem)
RAM
Pi
RAM
Pj
RAM
Pk
RAM
Pn
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Sincronização entre Processos
Race condition:
dois processos compartilham dados e o resultado
depende de quem executa exatamente quando
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Propriedades de um programa distribuído (Lamport, 1977)
Exemplo:
exclusão mútua num sistema controlando semáforos
safety:
dois semáforos numa estarão verde ao mesmo tempo
liveness:
Exemplo de Race Condition
spooler de fila
de impressão
4
5
6
7
Processo A
Processo B
out = 4
in = 6
abc
prog.c
prog.n
Extraído do livro
Tanenbaum pg. 54
1- A atualiza nexta = in + 1
2- A é interrompido pelo escalonador
3 - B atualiza netxb := in + 1
4 - B faz spooler [nextb] := file; in :=
nextb; /* in = 7 *’/
5 - Escalonador coloca A na CPU
6 - A faz spooler [nexta] := file; in :=
nexta; /* in = 7 *’/
in e out são variáveis
compartilhadas
Arquivo de B nunca
será impresso
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Formulação Abstrata do
Requisito de Sincronização
região crítica: parte do programa que acessa o
recurso compartilhado
exclusão mútua: garantia de que, se um processo
está acessando a sua região crítica, nenhum outro
processo estará fazendo o mesmo
Requisitos de uma boa solução
dois processos não podem estar simultaneamente em
suas regiões críticas (safety)
nenhuma consideração deve ser feita sobre velocidades
relativas de execução de processos
nenhum processo executando fora de sua região crítica
pode bloquear outros processos (safety)
processos devem em algum instante poder entrar em
suas regiões críticas (liveness)
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
As soluções em geral implicam :
Ação anterior (testar condição)
.... RC
Métodos para Exclusão Mútua
Desligar (desabilitar) interrupções
Alternação estrita (strict alternation)
Solução de Peterson
Instrução TSL (test and set lock)
Semáforos
Monitores
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Desligar Interrupções
solução simples
não é recomendada no nível das aplicações
pode ser útil para o kernel
somente funciona para sistemas
monoprocessados
Desabilita as interrupções
.... RC
while (lock ==1) // wait
lock = 1
...
R.C.
....
lock =0
Para entrar
Para sair
Problema : 2 processos podem entrar região crítica
caso leia o valor de lock simultaneamente.
Tentando resolver o problema via software com uso
de variáveis tipo “tranca”
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Resolvendo a Exclusão mútua com
Alternação Estrita
while (TRUE) {
while (turn != 0) /* wait */
critical_section();
turn = 1;
noncritical_section();
}
while (TRUE) {
while (turn != 1) /* wait */
critical_section();
turn = 0;
noncritical_section();
}
Problema : a falha ou não execução
de um processo impedirá o acesso
do outro processo
Solução de Peterson
int wait_turn;
int interested[2]; /* valores iniciais = 0 */
void enter_region (int process) {
int other;
other = 1 - process;
interested[process] = TRUE;
wait_turn = process;
while (wait_turn == process && interested[other] == TRUE);
}
void leave_region (int process) {
interested[process] = False);
}
Exercício para casa :
1) mostrar que a solução de peterson
atende aos requisitos de exclusão
mútua
2) fazer a versão generalizada para n
processos
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Solução de Peterson
Exemplo:
P0
P1
Other = 1 – 0 = 1
other = 1 – 1 = 0
Interested[0] = true
interested[1] = true
wait_turn = 0
wiat_turn = 1
While(cond?) White(cond ?) Espera
Entra RC
Solução de exercício
Usar liga e desliga interrupções somente para implementar o teste
do lock.
Obs: lock assume inicialmente valor 1
Testa_RC:
DI (desliga)
LA lock (acumulador := lock)
CMP A,#0
JNZ Entra_Região_Crítica
LI (liga interrupções)
JMP Testa_RC(testa novamente se valor de lock = 1)
Entra_Região_Crítica Sai_RC
Set lock,0 (lock:=0) set lock,#1
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Exercício (trazer na próxima aula)
A primeira solução de software correta para o problema de exclusão
mútua foi feita por Dekker. Mostre que está correta segundo critérios
dados em sala de aula.
Repeat
flag[i] := true; /* para tentar entrar na RC */
while flag[j] do
if turn = j
then begin
flag[i] := false;
while turn = j do no_op;
flag[i] := true;
end;
RC...
Turn := j; /* saida da RC */
Flag[i]:= false;
....
until false;
Resolvendo o Problema no Nível do
Hardware : A Instrução TSL
atomicamente transfere uma posição da memória para
um registrador e armazena um valor diferente de zero na
na posição de memória
leave_region:
mov lock, #0 /* lock := 0*/
ret
enter_region:
tsl reg, lock /* reg:= lock; lock:= 1; */
cmp reg, #0 /* reg 0 o valor de lock era zero? */
jnz enter_region /* loop se o valor de lock era 1 */
ret
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Tentando resolver o problema:
while (lock ==1) // wait
lock = o
...
R.C.
....
lock =1
Para entrar
Para sair
Problema : stavation.
Enter_region
com TST
Leave_region
com TST
Uso de Semáforos para Exclusão Mútua
Wait(mutex) - bloqueia processo se a RC está ocupada
Rergião Crítica
Signal(mutex) – libera a RC para outros processos
Wait = Down = P
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Semáforos de Dijkstra
Abstração conveniente para lidar com o problema de
acesso a região crítica e sincronização entre processos
WAIT ou P (Proberen em holandês)
SIGNAL ou V (Verhogen em holandês)
Um semáforo é uma variável inteira
Semáforos de Dijkstra
Definição Clássica de Semáforos
Inicialmente S := 1;
WAIT(S) : while S 0 no_op
S := S -1;
SIGNAL(S) : S := S + 1;
OBS: Wait e Signal são atômicos pois são regiões críticas
Exercício para Casa : Implementar WAIT e SIGNAL
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Implementando Semáforos de Dijkstra
WAIT(S)
Enter_region:
tsl reg, S /* reg:= S; S:= 1; */
cmp reg, #0 /* reg 0 o valor de lock era zero? */
jnz enter_region /* loop se o valor de lock era 1*/
ret
SIGNAL(S):
mov lock, #0 /* lock := 0*/
ret
Usando Semáforos para resolver o problema de
acesso à região crítica para n processos
Solução : os processos compartilham um
semáforo mutex (
mut
ual
ex
clusion) iniciado com valor 1
Repeat
wait (mutex)
seção crítica
signal (mutex)
resto da seção
until false
OBS: BUSY WAIT irá ocorrer,
mas pode ser interessante para
multiprocessadores ou quando
o lock for rápido
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Usando semáforos para sincronização
entre processos cooperantes
Exemplo: suponhas processos P1 e P2 cuja operação S1 de P1
necessariamente ter que ser executada antes da operação S2 de P2
Processo 1
S1;
Signal (synch);
Processo 2
wait (synch);
S2;
Espera Ocupada (Busy Waiting)
Os métodos:
Alternação estrita (strict alternation)
Solução de Peterson
Instrução TSL (test and set lock)
Semáforos convencionais
são baseados em espera ocupada!
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Como resolver o problema de BUSY WAIT da
especificação clássica dos semáforos ?
Solução : uso de bloqueio de processos e filas de espera associadas
aos semáforos
Processo P
WAIT (S) ---> processo P é bloqueado e colocado na fila de
espera associado a S. O controle passa para o
escalonador que então passo o controle para outro
processo.
Processo P
SIGNAL (S) ---> o escalonador tira um processo associado
a S do estado
waiting
para
ready
Estrutura do semáforo com filas
Type semáforo = Record
value : integer;
L : lista de processos
End;
WAIT (S) : S.value := S.value - 1;
if S.value < 0
then begin
add P to S.L;
end;
SIGNAL (S) : S.value := S.value + 1;
if S.value 0
then begin
remove a P from S.L;
wakeup(P);
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Problemas Clássicos de sincronização que
modelam vários Mecanismos de Sistemas
Operacionais
Produtor/Consumidor
o problema dos filósofos (the dining philosophers
problem)
o problema dos leitores/escrevedores (the readers and
writers problem)
o problema do barbeiro que dorme (the sleeping barber
O Problema Produtor/Consumidor
dois processos compartilham um buffer comum, de
tamanho fixo
um deles, o produtor, coloca informação no buffer
o outro, o consumidor, tira informações do buffer
quando o buffer estiver cheio, o produtor “dorme”
quando o buffer ficar vazio, o consumidor “dorme”
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Produtor/Consumidor
Usando buffer infinito
consumidor
produtor
Produtor
entra_região_crítica
buffer[fim] := item;
fim := fim + 1;
num_itens := num_itens +1 ;
if num_itens = 1
then
tira consumidor da fila FIFO
sai_região_crítica
Consumidor
entra_região_crítica
if num_itens > 0
item := buffer[in]
in := in + 1;
num_itens:= num_itens - 1;
else
coloca consumidor na fila FIFO
sai_região_crítica
If fim = in then ....
If fim > in then ....
Set in = 0; fim = 0;num_itens = 0;
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Solução do problema do
Produtor/Consumidor usando semáforo
consumidor
produtor
0 1 2 3 4 5 6 ...
Produtor
repeat
produz um novo item;
wait (mutex);
buffer[fim] := item;
fim := fim + 1;
signal (mutex);
signal (full)
until false;
Consumidor
reapeat
wait (full)
wait (mutex)
item := buffer[in]
in := in + 1
signal (mutex);
until false;
encapsulamento de procedimentos, variáveis e
estruturas
processos chamam procedimentos do monitor
apenas um processo pode estar ativo dentro do
monitor num dado instante
o compilador constrói a exclusão mútua
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Estrutura de Monitores
monitor example
integer i;
condition c;
procedure producer(x);
...
end
procedure consumer(x);
...
end
end monitor
Monitores: Primitivas wait/signal
Primitivas do Monitor
wait(cond): bloqueia o processo que a chamou e
espera por um signal.
signal(cond): acorda um processo bloqueado
O que fazer depois do signal
Hoare: processo acordado ganha o direito de executar
e bloqueia o processo que acordou
B. Hansen: processo que executou signal() fica
obrigado a deixar o monitor
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Produtor/Consumidor usando Monitor
Monitor ProdCons
condition full, empty;
int cont = 0;
Procedure Enter;
if (cont == N) wait(full);
enter_item;
cont = cont + 1;
if (cont == 1) signal(empty);
end;
Procedure Remove;
if (cont == 0) wait(empty);
remove_item;
cont = cont + 1;
if (cont == N -1) signal(full);
END;
Procedure Prod;
while (TRUE)
Produce_item;
ProdCons.Enter;
endwhile;
end;
Procedure Cons;
while (TRUE)
ProdCons.Remove;
Consome_item;
endwhile;
end;
Características
Exige suporte da linguagem de
programação
Troca de Mensagens
primitivas
send(destino, mensagem)
receive(fonte, mensagem)
se nenhuma mensagem está disponível, o recebedor pode
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Produtor/Consumidor com
Troca de Mensagens
#define N 100
#define MSIZE 4
typedef int message[MSIZE];
void producer(void) {
int item; message m;
while (TRUE) {
produce_item(&item);
receive(consumer,&m);
build_message(&m,item);
send(consumer,&m);
}
}
void consumer(void) {
int item; message m;
for (int i=0; i<N; i++)
send(producer,&m);
while (TRUE) {
receive(producer,&m);
extract_item(&m,item);
send(producer,&m);
consume_item(item)
}
}
O problema dos filósofos
prato
com spaghetti
garfo
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
O problema dos filósofos (cont.)
um conjunto de filósofos está sentado em volta de uma mesa
cada filófoso tem um prato de spaghetti
para comer o spaghetti, um filósofo precisa de dois garfos
entre cada prato tem um garfo
a vida de um filósofo consiste de períodos alternados de comer e
pensar
quando um filósofo tem fome, ele tenta obter os dois garfos ao
lado de seu prato
se o filósofo consegue obter os garfos, ele come por um tempo e
depois repõe os garfos sobre a mesa
O problema dos filósofos
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
O problema dos filósofos
Se o 2o estiver ocupado, larga os dois garfos
Larga e
tenta de
novo
O problema dos filósofos
Se o 2o estiver ocupado, larga os dois garfos
Larga e
tenta de
novo
APÓS um
Tempo
Aleatório
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
O problema dos filósofos
Usando mutex para exclusão mútua
Down(mutex)
pega 1o
pega 2o
come
larga os garfos
up(mutex)
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Uma solução para o
problema dos filósofos
#define N 5
#define LEFT (i-1)%N #define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
typedef int semaphore; int state[N]; semaphore mutex = 1; semaphore s[N]; void philosopher(int i) { while (TRUE) { think(); take_forks(i); eat(); put_forks(i); } } void take_forks(int i) { down(&mutex); state[i] = HUNGRY; test(i); up(&mutex); down(&s[i]); } void put_forks(int i) { down(&mutex); state[i] = THINKING; test(LEFT); test(RIGHT); up(&mutex); } void test(int i) {
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) { state[i] = EATING;
up(&s[i]); }
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
O problema do barbeiro que dorme
um barbearia tem:
um barbeiro
uma cadeira para cortar cabelo
n cadeiras para clientes
se não há clientes, o barbeiro senta-se na cadeira de cortar cabelo
e dorme
quando um cliente chega, ele acorda o barbeiro
se outros clientes chegam, eles sentam-se nas cadeiras (se houver
cadeiras vagas) ou vão embora (se não há cadeiras)
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
Uma solução para o problema
do barbeiro que dorme
#define CHAIRS 5 semaphore customers = 0; sempahore barbers = 0; semaphore mutex = 1; int waiting = 0; void Barber(void) { while (TRUE) { down(customers); down(mutex); waiting = waiting - 1; up(barbers); up(mutex); cut_hair(); } } void Customer(void) { down(mutex); if (waiting < CHAIRS) { waiting = waiting + 1; up(customers); up(mutex); down(barbers); get_haircut(); } else up(mutex); } }
Exercício
Fazer uma solução para o problema do barbeiro
considerando que não há cadeiras de espera
LaSiD - Laboratório de Sistemas Distribuídos http://www.lasid.ufba.br
O problema dos leitores/escrevedores
um conjunto de leitores e escrevedores podem ter
acesso a um conjunto compartilhado de dados
quando um escrevedor quer escrever, ele tem que ter
acesso exclusivo aos dados
vários leitores podem ler os dados ao mesmo tempo
Uma solução para o problema dos
escritores/escrevedores
semaphore mutex = 1; semaphore db = 1; int rc = 0; void reader(void) { while (TRUE) { down(&mutex); rc = rc + 1; if (rc == 1) down(&db); up(&mutex); read_database(); down(&mutex); rc = rc -1; if (rc == 0) up(&db); up(&mutex); use_data_read(); } }void writer (void) { while (TRUE) { think_up_data(); down(&mutex); write_database(); up(&mutex); } }