Capítulo 6: Sincronização de
Processos
Operating System Concepts – 8th Edition
Silberschatz, Galvin and Gagne ©2009
Background

Acesso concorrente a um dado compartilhado pode resultar em inconsistência

Para manter a consistência, é preciso garantir uma execução ordenada dos
processos cooperativos (que estão interagindo por meio de uma estrutura
compartilhada)

Estudo da concorrência entre processos através de modelos

Exemplo: Produtor-consumidor
Operating System Concepts – 8th Edition
6.2
Silberschatz, Galvin and Gagne ©2009
Problema do Produtor-Consumidor


Produtor e consumidor são dois processos distintos

O produtor produz e coloca o produto no buffer

O consumidor consome produtos que estão no buffer
Consequências


O buffer passa a ser uma estrutura compartilhada

O produtor não pode colocar um produto em um buffer cheio

O consumidor não pode consumir um produto se o buffer estiver vazio
A variável compartilhada count pode ser usada para saber o número de
elementos no momento dentro do buffer

Eventualmente, o count pode ser atualizado simultaneamente pelo produtor e
pelo consumidor
–
Atualização não é uma tarefa atômica (indivisível)
Operating System Concepts – 8th Edition
6.3
Silberschatz, Galvin and Gagne ©2009
Produtor
def produtor():
seed()
global count
i=0
while (True):
sleep(random())#Tempo para simular o processo produzindo a
informação
if count<BUFFER_SIZE:
buffer.append(str(i))
count = count +1
i=i+1
else:
while (count>=BUFFER_SIZE):
pass
Operating System Concepts – 8th Edition
6.4
Silberschatz, Galvin and Gagne ©2009
Consumidor
def consumidor():
seed()
global count
while (True):
if count>0:
buffer.pop(0)
count = count -1
sleep(random()) #Tempo para simular o processo
consumindo a informação
else:
while(count<=0):
pass
Operating System Concepts – 8th Edition
6.5
Silberschatz, Galvin and Gagne ©2009
Condição de disputa
 O incremento do contador pode ser implementado da seguinte forma:
register1 = counter
register1 = register1 + 1
counter = register1
 O decremento do contador, por sua vez, seria:
register2 = counter
register2 = register2 - 1
count = register2
 Suponha que, no momento, count=5 e que o produtor e o
consumidor estão sendo executados:
t0: produtor: register1 = counter {register1 = 5}
t1: produtor:
register1 = register1 + 1 {register1 = 6}
t2: consumidor: register2 = counter {register2 = 5}
t3: consumidor: register2 = register2 - 1 {register2 = 4}
t4: produtor:
counter = register1 {count = 6 }
t5: consumidor: counter = register2 {count = 4}
Operating System Concepts – 8th Edition
6.6
Silberschatz, Galvin and Gagne ©2009
Condição de disputa

Definição


Situação em que várias tarefas acessam dados concorrentemente e o resultado
da execução depende da ordem específica em que o acesso ocorre
Solução para a condição de disputa:

Sincronização de processos

Proteção das seções críticas

Uma seção crítica (ou região crítica) é um trecho de código no qual a tarefa
está alterando uma estrutura compartilhada (variáveis compartilhadas,
tabelas, arquivos, etc.)
–
Dessa forma, se um processo entra na sua seção crítica, nenhum outro
processo que compartilhe alguma estrutura pode ser autorizado a entrar
na sua seção crítica
Operating System Concepts – 8th Edition
6.7
Silberschatz, Galvin and Gagne ©2009
Problema da seção crítica

Problema de como controlar o acesso às seções críticas de processos que
compartilham dados

Ideia: Criar um protocolo de acesso

Processo pede autorização para entrar na seção crítica

Quando autorizado, processo executa seção crítica

Processo avisa que terminou sua seção crítica

Processo continua a sua execução
Operating System Concepts – 8th Edition
6.8
Silberschatz, Galvin and Gagne ©2009
Problema da seção crítica
A entra na região crítica
A deixa a região crítica
Processo A
B tenta entrar
na região crítica
Processo B
B entra na
região crítica
B deixa a
região crítica
B bloqueado
T1
Operating System Concepts – 8th Edition
T3
T2
6.9
T4
Silberschatz, Galvin and Gagne ©2009
Soluções para o problema da região
crítica
1. Exclusão mútua

Nunca dois processos podem estar simultaneamente em suas regiões
críticas
2. Progresso

Nenhum processo fora da sua região crítica pode bloquear outros
processos
3. Espera limitada

Nenhum processo deve esperar eternamente para entrar em sua região
crítica
Nada pode ser afirmado sobre a velocidade de processamento ou sobre
o número de CPUs disponíveis
Operating System Concepts – 8th Edition
6.10
Silberschatz, Galvin and Gagne ©2009
Revisão

Problema do produtor-consumidor


Código em Python

Único buffer com 10 posições

P produtores

C consumidores
Problema?

A variável count é modificada por vários threads ao mesmo tempo
–

Condição de disputa:
Vários processos disputando ao
mesmo tempo o acesso às mesmas
variáveis
Inconsistência no valor
Alguma diferença entre o uso de processos ou threads?

Usando processos fica mais pesado

Usando processos tem que usar memória compartilhada
–
Python já tem certo controle sobre essas variáveis
Operating System Concepts – 8th Edition
6.11
Silberschatz, Galvin and Gagne ©2009
Revisão

Qual é/são as seções críticas do código?

Uso da variável count

Uso da variável buffer

Consumidor
def consumidor():
seed()
global count
while (True):
if count>0:
buffer.pop(0)
count = count -1
Seção crítica
sleep(random()) #Tempo
para simular o processo consumindo a
informação
else:
while(count<=0):
pass
Operating System Concepts – 8th Edition
6.12
Silberschatz, Galvin and Gagne ©2009
Revisão

Produtor
def produtor():
seed()
global count
i=0
while (True):
sleep(random())#Tempo para simular o
processo produzindo a informação
if count<BUFFER_SIZE:
Seção crítica
buffer.append(str(i))
count = count +1
i=i+1
else:
while (count>=BUFFER_SIZE):
Seção crítica
pass
Operating System Concepts – 8th Edition
6.13
Silberschatz, Galvin and Gagne ©2009
Revisão

Main:
if __name__ == '__main__': ###Programa principal
print "Esse programa simula o problema do produtor-consumidor, utilizando
uma lista compartilhada por n threads: os produtores e os consumidores"
print "Está se utilizando o método da espera ocupada."
count = 0
prod=20 #Numero de produtores
cons= 20 #Numero de consumidores
t=[1]*(prod+cons) #Inicio o número de threads
for i in range(prod):
t[i] = Thread(target=produtor, args=())
t[i].start()
for i in range(prod,prod+cons):
t[i] = Thread(target=consumidor, args=())
t[i].start()
while (True):
if (len(buffer) != count):
print "ERRO!!!!, pois tamanho do buffer = %d e count = %d"
% (len(buffer),count)
Seção
sleep (0.1)
crítica
if (len(buffer)>10):
print "ERRO!!!!, pois o buffer estourou!!!"
Operating System Concepts – 8th Edition
6.14
Seção
crítica
Silberschatz, Galvin and Gagne ©2009
Revisão

Como proteger a seção crítica?

Enquanto um produtor está na seção crítica, nenhum outro produtor ou
consumidor pode entrar na seção crítica


Seção crítica = seção aonde se atualiza ou se compara as variáveis
compartilhadas
Enquanto um consumidor está na seção crítica, nenhum outro consumidor ou
produtor pode entrar na seção crítica
Operating System Concepts – 8th Edition
6.15
Silberschatz, Galvin and Gagne ©2009
Soluções para o problema da seção crítica

Soluções

Solução de Peterson – Software

Test and set – Solução por hardware

Semáforos e mutexes – Auxílio de hardware
Operating System Concepts – 8th Edition
6.16
Silberschatz, Galvin and Gagne ©2009
Solução de Peterson

Solução por software para controle de 2 processos

Ideia

Se eu quero entrar na região crítica, devo dizer isso ao outro programa

Eu só posso entrar na seção crítica quando for a minha vez
–

Se o outro processo não quer entrar na seção crítica, então passa a ser a
minha vez automaticamente
Eu começo dando a vez para o outro programa, mesmo que eu queira usar
–
Se dois querem, quem der a vez primeiro para o outro vai passar na
frente
P2 ganhou
vez!!!
P1a ganhou
a vez!!!
Operating System Concepts – 8th Edition
P1
P2
Se P1 começa na frente:
Se P2 começa na frente:
VARIÁVEL VEZ
1
2
6.17
Silberschatz, Galvin and Gagne ©2009
Solução de Peterson

Código para Processo 0
Se quero entrar, sinalizo isso
Dou a vez para o outro para
ver se eu ganho a vez...:)
Enquanto(1){
eu_quero_entrar[0]=1
vez = 1
enquanto (eu_quero_entrar[1]==1 e vez==1){
Não faço nada
Quando terminar a seção
crítica, aviso que não quero
mais entrar
}
Executo seção crítica
eu_quero_entrar[0]=0
Quando eu não quiser mais
entrar, eu paro o enquanto
do outro processo e deixo
ele entrar na seção crítica
}
Operating System Concepts – 8th Edition
Se eu quero entrar e a vez é
minha, eu pulo o enquanto
e vou para seção crítica
6.18
Silberschatz, Galvin and Gagne ©2009
Solução de Peterson

Código para Processo 0
Se quero entrar, sinalizo isso
Dou a vez para o outro para
ver se eu ganho a vez...:)
Enquanto(1){
eu_quero_entrar[0]=1
vez = 1
enquanto (eu_quero_entrar[1]==1 e vez==1){
Não faço nada
Quando o outro programa
terminar a seção crítica, ele
não vai mais querer entrar e
eu saio do enquanto.
}
Executo seção crítica
eu_quero_entrar[0]=0
}
Se eu quero entrar e a vez
não é minha, eu espero até
a vez passar a ser minha
Depois que eu executar
minha seção crítica, eu digo
que não quero mais entrar.
A variável vez só serve para distinguir quem vai
entrar se tiver disputa, ou seja, mais de um
processo querendo entrar na seção crítica
Operating System Concepts – 8th Edition
6.19
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Como implementar o lock?

Como permitir que os programas entrem na sua seção crítica segundo uma fila?
do {
acquire lock
Fácil de usar....
critical section
Mas como funciona???
release lock
remainder section
test and set ou swap!!!
} while (TRUE);
- Exemplo: ex_threadv2 e ex-thread-lock.py
Operating System Concepts – 8th Edition
6.20
Instruções atômicas
(vem daquela ideia antiga de
que o átomo era indivisível)
(do grego: a=não,
tomo=divisão)
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Sem me preocupar com a ordem dos processos, usando test and set lock (TSL)
TSL(x):
Se x==0, então x=1 e retorna 0
Se x==1, então x=1 e retorna 1
do {
acquire lock
critical section
release lock
while(TestAndSet(&lock)) ;
remainder section
} while (TRUE);
lock=0
A TSL é uma instrução atômica.
Então, apenas 1 processo pode
executá-la, mesmo que existam
vários processadores. Assim,
apenas 1 processo pode aproveitar
o lock=0.
Então, se lock =0, pode usar. Se
lock =1, não pode usar, pois fica
preso no while
Operating System Concepts – 8th Edition
6.21
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Sem me preocupar com a ordem dos processos, usando swap
swap(x,y):
x recebe o valor de y e y recebe
o valor de x. É literalmente uma
troca.
do {
acquire lock
critical section
key=true;
while(key==true)
swap(lock,key);
release lock
remainder section
} while (TRUE);
lock=0
Então, se lock =0, key vira false,
lock vira 1 e o processo sai do while.
Se lock =1, não pode usar, pois
key=lock=1 e o processo fica preso
no while
Operating System Concepts – 8th Edition
6.22
A swap também é uma instrução
atômica. Então, apenas 1 processo
pode executá-la, mesmo que
existam vários processadores.
Assim, apenas 1 processo pode
aproveitar o lock=0.
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Me preocupando com a ordem dos processos, usando test and set
do {
acquire lock
critical section
release lock
Em todos os exemplos anteriores,
não é possível garantir que algum
processo não vai ficar esperando
eternamente. O mais rápido pega o
lock, e não o processo que está
esperando a mais tempo.
remainder section
} while (TRUE);
Operating System Concepts – 8th Edition
6.23
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Me preocupando com a ordem dos processos, usando test and set
TSL(x):
Se x==0, então x=1 e retorna 0
Se x==1, então x=1 e retorna 1
do {
acquire lock
critical section
release lock
remainder section
} while (TRUE);
waiting[i]=true;
key=true;
while(waiting[i]==true)&(key==true)
key = TestAndSet(&lock)
Waiting[i]=false;
Se lock=0, então lock=1 e key=0. Isso
faz o processo sair do while. Uma vez
que o processo ganhou o acesso, ele não
espera mais para entrar na seção crítica.
Se lock=1, então lock=key=1. O
programa fica preso no while.
Operating System Concepts – 8th Edition
6.24
Silberschatz, Galvin and Gagne ©2009
Solução de hardware

Me preocupando com a ordem dos processos, usando test and set
TSL(x):
Se x==0, então x=1 e retorna 0
Se x==1, então x=1 e retorna 1
do {
acquire lock
critical section
release lock
remainder section
waiting[i]=true;
key=true;
while(waiting[i]==true)&(key==true)
key = TestAndSet(&lock)
Waiting[i]=false;
} while (TRUE);
j = (i + 1) % n;
Escolhe o próximo processo que está
while ((j != i) && !waiting[j])
esperando para entrar
j = (j + 1) % n;
if (j == i)
Se ninguém está esperando, libera o lock
lock = FALSE;
para qualquer um
else
Do contrário, o próximo processo esperando
waiting[j] = FALSE;
pode entrar na região crítica Silberschatz, Galvin and Gagne ©2009
Operating System Concepts – 8th Edition
6.25
Semáforos

Signal e wait

Operações atômicas na modificação do semáforo

Modificam o valor do sinal
int sinal=1;
wait(sinal);
Região crítica;
wait (S) {
while S <= 0
; // no-op
S--;
}
Se S=1, decrementa S e pode entrar.
Caso contrário, fica esperando em espera
ocupada
signal (sinal);
Espera ocupada = espera usando CPU
signal (S) {
S++;
}
Operating System Concepts – 8th Edition
6.26
Silberschatz, Galvin and Gagne ©2009
Semáforos

Signal e wait

Operações atômicas na modificação do semáforo

Modificam o valor do sinal
int sinal=1;
wait (S) {
while S <= 0
; // no-op
S--;
}
wait(sinal);
Região crítica;
signal (sinal);
S pode ser apenas 1 ou 0.
S é um MUTEX, pois permite exclusão
mútua (apenas 1 pode executar).
signal (S) {
S++;
}
Operating System Concepts – 8th Edition
6.27
Silberschatz, Galvin and Gagne ©2009
Semáforos

Signal e wait + block e wakeup
int sinal=1;
wait(sinal);
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
Região crítica;
S pode variar entre –infinito e 1. Se S=1, o
processo acessa a região crítica.
signal (sinal);
Permite fazer a fila de processos esperando.
Operating System Concepts – 8th Edition
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
6.28
Silberschatz, Galvin and Gagne ©2009
Semáforos

Signal e wait + block e wakeup
int sinal=1;
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
wait(sinal);
Não tem espera ocupada!
Região crítica;
signal (sinal);
Operating System Concepts – 8th Edition
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
6.29
Silberschatz, Galvin and Gagne ©2009
Exemplos
 Semáforos em python

Thread-lock-semaphore.py
Operating System Concepts – 8th Edition
6.30
Silberschatz, Galvin and Gagne ©2009
Exercícios

Quando ocorre condição de disputa?


Qual a relação entre seção crítica e condição de disputa?


Uma solução para o problema da seção crítica feita por software para quando
existem no máximo 2 processos disputando o acesso a seção crítica.
Como funcionam as soluções de sincronismo baseadas em hardware?


A seção crítica é a parte do código na qual ocorrem os acessos às variáveis
compartilhadas, onde, eventualmente, podem ocorrer condições de disputa.
O que é a solução de Peterson?


Quando dois ou mais processos tentam utilizar a mesma variável compartilhada
ao mesmo tempo, de tal forma que o valor final da variável dependa da ordem
específica com a qual os acessos ocorrem.
Através do uso de instruções atômicas que auxiliam a exclusão mútua, tais como
a test & set e a swap.
Qual a principal diferença funcional entre locks e semáforos?

Os locks permitem criar apenas a exclusão mútua, enquanto que os semáforos
podem ser usados para fazer a exclusão mútua ou para selecionar um número
de eventos que podem ocorrer em paralelo.
Operating System Concepts – 8th Edition
6.31
Silberschatz, Galvin and Gagne ©2009
Deadlock e Inanição
Deadlock – Acontece quando dois ou mais processos estão esperando por
um evento que só poderia ser executado por um dos processos em espera
 Exemplo


Imagine que S e Q são dois semáforos inicializados em 1
P0
P1
wait (S);
wait (Q);
wait (Q);
wait (S);
.
.
.
.
.
.
signal (S);
signal (Q);
Operating System Concepts – 8th Edition
signal (Q);
signal (S);
6.32
Silberschatz, Galvin and Gagne ©2009
Exercício

Crie um programa que crie 2 processos cuja a interação leve a um deadlock.
Operating System Concepts – 8th Edition
6.33
Silberschatz, Galvin and Gagne ©2009
Deadlock e Inanição

Inanição – Bloqueio indefinido
 Um processo nunca é retirado da fila de espera por um semáforo
 Exemplo: Política de escolha de quem recebe o semáforo do tipo LIFO
(Last In, First Out)

Inversão de prioridades – Problema de escalonamento que ocorre quando
um processo de baixa prioridade tem posse de um semáforo compartilhado
com processos de alta prioridade

Solução: Protocolo de herança de prioridade
 Todos os processos que compartilham dados com um processo de
alta prioridade recebem a mesma prioridade que esse processo
Operating System Concepts – 8th Edition
6.34
Silberschatz, Galvin and Gagne ©2009
Problemas clássicos de sincronização

Problemas clássicos usados para testar novos esquemas de sincronização propostos

Problema do buffer limitado

Problema dos leitores-escritores

Problema do jantar dos filósofos
Operating System Concepts – 8th Edition
6.35
Silberschatz, Galvin and Gagne ©2009
Problema do buffer limitado


N buffers, cada um podendo armazenar um item
Semáforo mutex inicializado no valor 1

Semáforo full inicializado no valor 0

Semáforo empty inicializado no valor N
Operating System Concepts – 8th Edition
6.36
Controla o acesso ao
buffer
Controla o número de
espaços ocupados no buffer
Controla o número de
espaços vazios no buffer
Silberschatz, Galvin and Gagne ©2009
Problema do buffer limitado

Estrutura do processo produtor
do {
// produce an item in nextp
Espera ter um vazio
para usar e usa
Pede acesso ao buffer
wait (empty);
wait (mutex);
// add the item to the buffer
Libera o acesso ao buffer
signal (mutex);
Aumenta o número de
espaços ocupados
signal (full);
} while (TRUE);
Operating System Concepts – 8th Edition
Não pode trocar
a ordem!
6.37
Silberschatz, Galvin and Gagne ©2009
Problema do buffer limitado

Espera ter um cheio
para usar e usa
Estrutura do processo consumidor
Pede acesso ao buffer
do {
wait (full);
wait (mutex);
// remove an item from buffer to nextc
Libera o acesso ao buffer
signal (mutex);
Aumenta o número de
espaços vazios
signal (empty);
// consume the item in nextc
} while (TRUE);
Operating System Concepts – 8th Edition
6.38
Silberschatz, Galvin and Gagne ©2009
Exercícios

Com base nos códigos do produtor e do consumidor,qual o estado das variáveis
compartilhadas ao longo do tempo, se cada processo executa uma linha de código e
perde a vez? Dê sua resposta no formato da tabela abaixo. Preencha pelo menos 16
linhas e assuma que o processo produtor foi iniciado antes do processo consumidor.
Além disso, suponha que o buffer possui apenas 3 posições.
Linha de
código
Mutex
Operating System Concepts – 8th Edition
Full
Empty
6.39
Buffer[0]
Buffer[1]
Buffer[2]
Silberschatz, Galvin and Gagne ©2009
Exercício

Repita o exercício anterior, supondo que o consumidor foi o primeiro processo a ser
executado.

Repita o exercício anterior, supondo que a operação de produção de item seja 16x
mais rápida que a operação de consumo de item. Suponha que o buffer comece com
2 elementos e execute até que o produtor seja bloqueado pela primeira vez.

Suponha que as linhas 2 e 3 (wait empty e wait mutex) do código do produtor fossem
trocadas e que o buffer seja iniciado cheio. Isso causará algum problema?

Suponha que o buffer está cheio.
Operating System Concepts – 8th Edition
6.40
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores



Um conjunto de dados é compartilhado entre um número de processos
concorrentes

Leitores – apenas leem o conjunto de dados; não realizam atualizações

Escritores – podem ler e escrever
Problema

Permitir que múltiplos leitores leiam ao mesmo tempo

Apenas um escritor pode acessar os dados compartilhados ao mesmo
tempo
Existem diversas variações sobre como tratar os leitores e os escritores

Todas envolvem prioridades
Operating System Concepts – 8th Edition
•Solução proposta: nenhum leitor
deve esperar que outros leitores
terminem só porque existe um
escritor esperando  prioridade
para leitores
6.41
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores

Dados compartilhados
Trata do acesso ao readcount

Conjunto de dados

Semáforo mutex inicializado em 1

Semáforo wrt inicializado em 1

Inteiro readcount inicializado em 0
Exclusão mútua para escritores
Número de leitores
Operating System Concepts – 8th Edition
6.42
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores


Estrutura do processo escritor
Estrutura do processo leitor
do {
do {
wait (wrt) ;
//
Seção crítica
Seção crítica
writing is performed
wait (mutex) ;
readcount ++ ;
if (readcount == 1)
wait (wrt) ;
signal (mutex)
signal (wrt) ;
// reading is performed
} while (TRUE);
Seção crítica
Operating System Concepts – 8th Edition
6.43
wait (mutex) ;
readcount - - ;
if (readcount == 0)
signal (wrt) ;
signal (mutex) ;
} while (TRUE);
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores


Estrutura do processo escritor
Estrutura do processo leitor
do {
do {
wait (wrt) ;
//
Espera ter acesso ao
buffer sozinho
writing is performed
signal (wrt) ;
} while (TRUE);
Libera para leitores e
escritores
wait (mutex) ;
readcount ++ ;
if (readcount == 1)
wait (wrt) ;
signal (mutex)
// reading is performed
wait (mutex) ;
readcount - - ;
if (readcount == 0)
signal (wrt) ;
signal (mutex) ;
} while (TRUE);
Operating System Concepts – 8th Edition
6.44
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores


Estrutura do processo escritor
Estrutura do processo leitor
do {
do {
wait (wrt) ;
Se ninguém está
usando o readcount,
posso usar
//
writing is performed
Depois de atualizar,
libero o readcount
signal (wrt) ;
// reading is performed
} while (TRUE);
Começando pelo
mutex readcount
Operating System Concepts – 8th Edition
wait (mutex) ;
readcount ++ ;
if (readcount == 1)
wait (wrt) ;
signal (mutex)
Acabei de ler. Se
ninguém estiver
usando, atualizo o
readcount
wait (mutex) ;
readcount - - ;
if (readcount == 0)
signal (wrt) ;
Libero o readcount
signal (mutex) ;
} while (TRUE);
6.45
Silberschatz, Galvin and Gagne ©2009
Problema dos leitores-escritores


Estrutura do processo escritor
Estrutura do processo leitor
do {
do {
Se já não tem alguém
wait (wrt) ;
lendo, pode ter alguém
escrevendo
// writing is performed
wait (mutex) ;
readcount ++ ;
if (readcount == 1)
wait (wrt) ;
signal (mutex)
signal (wrt) ;
// reading is performed
} while (TRUE);
Agora o mutex wrt
Operating System Concepts – 8th Edition
wait (mutex) ;
readcount - - ;
Se não tem mais
if (readcount == 0)
leitores, então libera o
signal (wrt) ;
acesso para escritores
signal (mutex) ;
e leitores
} while (TRUE);
6.46
Silberschatz, Galvin and Gagne ©2009
Variações do problema dos leitoresescritores

Primeira variação – nenhum leitor é deixado esperando a menos que o escritor tenha
permissão para usar o objeto compartilhado.

Segunda variação – uma vez que o escritor está pronto, ele escreve o mais rápido
possível

Ambos podem levar à inanição, criando ainda mais variações

Problema é solucionado em alguns sistemas pelo Kernel, que provê locks para leitorescritor.
Operating System Concepts – 8th Edition
6.47
Silberschatz, Galvin and Gagne ©2009
Problema do jantar dos filósofos

Filósofos passam suas vidas pensando e comendo

Eles não interagem com seus vizinhos

Ocasionalmente, eles tentam pegar dois palitos, um de cada vez, para
comer da vasilha central.


Eles precisam dos dois palitos para comer, mas liberam os dois
quando terminam
No caso de 5 filósofos

Dados compartilhados

Vasilha de arroz (conjunto de dados)

Semáforos chopstick [5] inicializado em 1
Operating System Concepts – 8th Edition
6.48
Silberschatz, Galvin and Gagne ©2009
Algoritmo do problema do jantar dos
filósofos

Estrutura do i-ésimo filósofo:
do {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );
// eat
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
Possibilidade de deadlock
e de inanição
// think
} while (TRUE);

Qual o problema com esse algoritmo?
Operating System Concepts – 8th Edition
6.49
Silberschatz, Galvin and Gagne ©2009
Problemas com semáforos


Uso incorreto de operações de semáforos:

signal (mutex) …. wait (mutex)

wait (mutex) … wait (mutex)

Omissão do wait (mutex) ou do signal (mutex) (ou de ambos)
Deadlock e inanição
Operating System Concepts – 8th Edition
6.50
Silberschatz, Galvin and Gagne ©2009
Monitores

Uma abstração de alto nível que provê um mecanismo conveniente e eficiente
para sincronizar processos
 Apenas 1 processo pode estar ativo no monitor por vez
 Contudo, não é poderoso o suficiente para modelar alguns esquemas de
sincronização
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }
procedure Pn (…) {……}
Initialization code (…) { … }
}
}
Operating System Concepts – 8th Edition
6.51
Silberschatz, Galvin and Gagne ©2009
Variáveis condicionais

condição x, y;

Duas operações em uma variável condicional:

x.wait () – o processo que invoca a operação é suspenso até que x.signal
() seja chamado

x.signal () – resume um dos processos, se houver algum, que invocou o
x.wait ()

Se não existe nenhum x.wait () na variável, então isso não tem nenhum
efeito na variável
Operating System Concepts – 8th Edition
6.52
Silberschatz, Galvin and Gagne ©2009
Escolha de variáveis condicionais

Se o processo P chama x.signal (), com o processo Q no estado x.wait (), o
que deve acontecer em seguida?


Se Q é resumido, então P deve esperar
Opções incluem:

Signal and wait – P espera até que Q deixe o monitor ou espere por
alguma outra condição

Signal and continue – Q espera até que P deixe o monitor ou espera por
alguma outra condição

Ambos tem prós e contras – Escolha depende da implementação

Monitores implementados em Pascal concorrente


P executando o signal deixa o monitor imediatamente e Q é resumido
Implementado em outras linguagens, incluindo Mesa, C#, Java
Operating System Concepts –
Implementado no Python com a classe Condition
8th
Edition
6.53
Silberschatz, Galvin and Gagne ©2009
Solução para o jantar dos filósofos
monitor DiningPhilosophers
{
enum { THINKING; HUNGRY, EATING)
state [5] ;
condition self [5];
void test (int i) {
if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self [i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
Operating System Concepts – 8th Edition
6.54
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Silberschatz, Galvin and Gagne ©2009
Solução para o jantar dos filósofos

Cada filósofo I chama as operações pickup() e putdown() na seguinte sequência:
DiningPhilosophers.pickup (i);
EAT
DiningPhilosophers.putdown (i);

Não tem deadlock, mas a inanição é possível
Operating System Concepts – 8th Edition
6.55
Silberschatz, Galvin and Gagne ©2009
End of Chapter 6
Operating System Concepts – 8th Edition
Silberschatz, Galvin and Gagne ©2009
Download

8 th Edition