11
Programação Concorrente
2
Tópicos de Hoje
Assunto: Semáforos;
● Livro Texto – Capítulo 7;
Rápida revisão sobre Exclusão Mútua; Definição de Semáforo;
Implementação de Semáforos no Kernel;
Implementação de Semáforos fora do Kernel; 5 Problemas clássicos propostos por Dijkstra;
3
Relação de precedência entre processos
● Grafo de Fluxo de processos.
Figura 3.1 – Grafos de fluxo de processos
4
Introdução – Caracterização do Problema
●
Quando processos concorrentes compartilham
dados (variáveis, estruturas de dados, arquivos),
é necessário controlar o acesso a esses dados,
para obter
determinância de execução.
●
Operações de atualização não podem ser feitas
simultaneamente por diferentes processos.
Tampouco operações de leitura podem ocorrer
simultaneamente com atualizações, pois os
dados lidos podem estar temporariamente
inconsistentes.
Forma da Solução de Exclusão Mútua
(5 Tentativas de Solução)
Loop
Região Não Crítica;
Pré-Protocolo;
Região Crítica;
Pós-Protocolo;
End loop;
Regras Gerais
1.
Um processo pode parar em sua RNC (neste
caso, ele não deve interferir nos outros), mas
não pode parar durante a execução dos
protocolos nem da RC
2.
Os processos não devem provocar bloqueio
(deadlock) na tentativa de acessar suas RCs
3.
Não deve haver
inanição (starvation)
de
nenhum dos processos
4.
No caso de não haver disputa pelo acesso à
RC, o processo deve ser bem sucedido e
com overhead mínimo
Inanição ou starvation ocorre quando um processo nunca é executado ("morre de fome"),
pois processos de prioridade maior sempre o impedem de ser executado.
Semáforos
Edsger Wybe Dijkstra foi um cientista da computação Holandês conhecido por suas contribuições nas áreas de desenvolvimento de algoritmos e programas, de linguagens de programação (pelo qual recebeu o Prêmio Turing de 1972), sistemas operacionais e processamento distribuído.
Entre suas contribuições para a ciência da computação está incluído o
algoritmo para o problema do caminho mínimo (também conhecido como algoritmo de Dijkstra), o sistema operacional THE e a construção de semáforos para coordenar múltiplos processadores e programas.
Semáforos: Definição
•
Um semáforo é uma variável inteira, não
negativa, que só pode ser manipulada por
duas instruções atômicas:
Proberen
e
Verhogen
, que significam Testar e
Incrementar, respectivamente.
Proberen = P = Testar
Verhogen = V = Incrementar
• No caso da exclusão mútua, as instruções P e V
funcionam como protocolos de entrada e saída, respectivamente, para que um processo possa entrar e sair de sua região crítica.
Semáforos: Definição
•
Sendo S uma variável semáfora, as operações
P e V têm a seguinte semântica:
– P(S): espera até S ser maior que 0 e então subtrai 1 de S;
– V(S): Incrementa S;
As operações “testar S e subtrair 1 (se S>0)” e
“incrementar S” são executadas de forma
mutuamente exclusiva, no kernel do SO. Se S=1 e
dois processos executam P(S) “simultaneamente”,
um dos processos vai ficar bloqueado.
Semáforos: Definição
Pode-se fazer analogia entre uma variável semáfora e um vaso contendo bolinhas de gude. O Valor numérico do semáforo corresponde ao número de bolinhas dentro do vaso. Uma operação V
corresponde a pôr uma bolinha no vaso. Cada operação P tenta remover uma bolinha, se nenhuma está disponível, então a operação bloqueia o processo e o coloca numa fila de espera. Quando uma bolinha é colocada no vaso (Operação V), ela é removida pelo primeiro processo da fila de espera, o qual prossegue sua execução.
P V
Implementação de Semáforos fora do Kernel do SO
Procedure P (var S : Semaforo)
begin bloquear := false multexbegin; if S.Valor = 0 then bloquear := true Insere_Proc.Fila_Espera else S.Valor := S.Valor – 1; multexend;
if bloquear then block;
end;
Procedure V (var S : Semaforo)
begin multexbegin; if (Tem_Proc_Fila) then p := Retira_Proc.Fila_Espera; wakeup(p); else S.Valor := S.Valor + 1; multexend; end;
Problema Clássico #01
Alocador de Recurso
Desenvolva um alocador de recursos para alocar
pelo menos dois diferentes tipos de recursos de
hardware para usuários dentro de um sistema de
comunicação, em que o sistema suporta até um
primeiro número predeterminado de usuários de um
tipo particular e um segundo número predeterminado
de usuários de um segundo tipo particular. O
alocador de recursos propicia um mapeamento de
recursos, seja de recursos fixos para recursos
compartilhados ou de recursos compartilhados para
recursos fixos, o qual é tanto eficaz em termos de
custo como transparente para software.
Problema Clássico #01
Variáveis globais:R: integer array[5] = [5,4,3,2,1];
T: integer initial 5;
Counter: semaphore initial 5;
Mutex: semaphore initial 1;
Procedure Release (var U : Integer)
begin P(Mutex); T := T + 1; R[T] := U; V(Mutex); V(Counter); end; Procedure Request (var U : Integer)
begin P(Counter); P(Mutex); U := R[T]; T := T – 1; V(Mutex); end;
Problema Clássico #02
Produtor-Consumidor com buffer limitado
Um par de processos compartilha um buffer de N posições. O primeiro processo, denominado produtor, passa a vida a produzir mensagens e colocá-las no
buffer. O Segundo processo, denominado consumidor, passa a vida a retirar mensagens do buffer ( na mesma ordem em que elas foram colocadas) e a consumí-las.
A relação produtor-consumidor ocorre comumente em sistemas concorrentes e o problema se resume em administrar o buffer que tem tamanho limitado. Se o
buffer está cheio, o produtor deve se bloquear, se o
Problema Clássico #02
Problema Clássico #02
Variáveis globais:buffer: integer array[5];
cheio: semaphore initial 0;
vazio: semaphore initial 5;
Consumidor:
msg, out : integer; loop
P(cheio);
out := (out mod 5) + 1; msg := buffer[out]; V(vazio); % Consumo endloop; Produtor: msg, in : integer; loop % Produção P(vazios); in := (in mod 5) + 1; buffer[in] := msg; V(cheios); endloop;
Problema Clássico #03
Problema Clássico #03
Problema Clássico #03
1 1 2 2 3 3 4 4 5 5Problema Clássico #03
Variáveis globais:
garfo: semaphore array[5];
Procedure PegaGarfo(i: integer) { j := i – 1; % Garfo Esquerda if j = 0 then { P(grafo[1]); P(garfo[5]); } else { p(garfo[j]); P(garfo[i]); } }
Procedure DevolveGarfo(i: integer)
{ j := i – 1; % Garfo Esquerda if j = 0 then { V(grafo[1]); V(garfo[5]); } else { V(garfo[j]); V(garfo[i]); } }
Process Filosofo (i:=1 to 5) { k : integer init 10; while k > 0 do { Pegagarfo(i); write(“Filosofo”,i,”Comendo”); DevolveGarfo(i); write(“Filosofo”,i,”Parou”); K := k - 1; } }
Problema Clássico #04
Barbeiro Dorminhoco
Também proposto por Dijktra, este problema ilustra uma organização tipo
cliente-servidor, onde diversos processos clientes utilizam os serviços de um processo servidor. Os clientes podem desistir do serviço em função da “escassez de recursos”.
Problema Clássico #04
Barbeiro Dorminhoco
O problema consiste em simular o funcionamento de uma barbearia com as seguintes características. A barbearia tem uma sala de espera com N cadeiras de barbear. Se não tem clienter à espera, o barbeiro senta numa cadeira e dorme. Quando chega um cliente, ele acorda o barbeiro. Se chega outro cliente enquanto o barbeiro está trabalhando, ele ou ocupa uma cadeira e espera (se tem alguma cadeira disponível) ou vai embora ( se todas as ceidras estão ocupadas.
Problema Clássico #04
Variáveis globais:
fila : semaphore init 0;
clientes: semaphore init 0;
mutex : semaphore init 1;
count : integer init 0;
Cliente:
P(mutex);
if count < 5 then {
count := count + 1;
V(clientes); % Acorda Barbeiro
V(mutex);
P(fila); %Espera Barbeiro
%Cortando Cabelo } else V(mutex); Barbeiro: loop
P(clientes); %Dorme,se for o caso
P(mutex);
count := count – 1;
V(fila); %Prox. Cliente
V(mutex);
%Cortando Cabelo
endloop
Problema Clássico #05
Leitores e Escritores
O problema
dos leitores e escritores (readers and writers) ilustra outra situação comum em sistemas de processos concorrentes. Este problema surge quando processos executam operações de leitura e de atualização sobre um arquivo global (ou sobre uma estrutura de dados global). A sincronização deve ser tal que vários readers (isto é, processos leitores, que não alteram a informação) possam utilizar o arquivo simultaneamente. Entretanto, qualquer processo writerProblema Clássico #05
Variáveis globais:
mutex : semaphore init 1;
w : semaphore init 1; nr : integer init 0; Processo Escritor: P(w); % Escrevendo, Escrevendo... V(w); Processo Leitor: P(mutex); nr := nr + 1; if nr=1 then P(w); V(mutex);
%Lendo, Lendo, Lendo...
P(mutex);
nr := nr – 1;
if nr=0 then V(w); V(mutex);
Problema Clássico #05
Variáveis globais:
mutex, w: semaphore init 1;
nr : integer init 0; nw : integer init 0; mx, r : integer init 1; Processo Escritor: P(mx); nw := nw + 1; if nw=1 then P(r); V(mx); P(w); % Escrevendo, Escrevendo... V(w); P(mx); nw := nw - 1; if nw=0 then V(r); V(mx); Processo Leitor: P(r); P(mutex); nr := nr + 1; if nr=1 then P(w); V(mutex); V(r);
%Lendo, Lendo, Lendo...
P(mutex);
nr := nr – 1;
if nr=0 then V(w); V(mutex);
28
Dúvidas...