11
Programação Concorrente
2
Tópicos de Hoje
●
Livro Texto – Capítulo 4:
Caracterização do Problema;
Exclusão mútua para Dois processos;
Cinco Tentativas de Solução;
Algoritmo de Dekker;
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.
●
Leituras
●
Gravações
●Atualizações
5
Introdução – Condição de Corrida
Suponha que duas threads T1 e T2 desejam incrementar em
um o valor de uma variável compartilhada inteira.
Qual o valor Final da variável compartilhada MEM ?
Situação #1
Thread1 v1=MEM Thread1 v1=v1+1 Thread1 MEM=v1 Thread2 v2=MEM Thread2 v2=v2+1 Thread2 MEM=v2Situação #2
Thread1 v1=MEM Thread2 v2=MEM Thread1 MEM=v1+1 Thread2 MEM=v2+1 Thread1 MEM=v1 Thread2 MEM=v2As operações acima não são atômicas!
6
●
Na história da computação existem diversos exemplos de
desastres ocorridos devido a erros com Exclusividade de
execução de processos. O caso da
máquina de radioterapia
Therac-25
é um exemplo clássico. Uma
condição de corrida
fazia
com que, às vezes, essa máquina administrasse dosagens
milhares de vezes maior que a normal, resultando na morte ou
sérios danos aos pacientes.
O problema da Exclusão Mútua para N processos:
1. Divisão dos processos em RC e RNC;
2. O software deve satisfazer a propriedade de
exclusão mútua;
3. Adição de pré e pós-protocolo.
Uma forma de garantir a
Exclusão Mútua
Loop
Região Não Crítica;
Pré-Protocolo;
Região Crítica;
Pós-Protocolo;
End loop;
DEADLOCK
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
starvation ocorre quando um processo nunca é executado ("morre de fome"),
Exclusão mútua
Apresentou um artigo contendo
5 algoritmos com tentativas
de solução para problemas de
Primeira Tentativa
task body P1 is begin
loop
Regiao_Nao_Critica_1;
loop exit when Turn = 1; end loop; Regiao_Critica_1; Turn := 2; end loop; end P1; task body P2 is begin loop Regiao_Nao_Critica_2;
loop exit when Turn = 2; end loop; Regiao_Critica_2;
Turn := 1; end loop; end P2;
Turn: Integer range 1..2 := 1;
Primeira Tentativa
•
Esta solução satisfaz os requisito de
exclusão mútua
•
A solução não causa deadlock
•
Não há starvation
•
Mas... A solução pode falhar no caso de
ausência de disputa...
Segunda Tentativa
task body P1 is begin
loop
Regiao_Nao_Critica_1;
loop exit when C2 = 1; end loop; C1 := 0; Regiao_Critica_1; C1 := 1; end loop; end P1; task body P2 is begin loop Regiao_Nao_Critica_2;
loop exit when C1 = 1; end loop; C2 := 0; Regiao_Critica_2; C2 := 1; end loop; end P2; C1, C2: Integer range 0..1 := 1;
Exclusão mútua
Segunda Tentativa
•
Considere:
–
P1 verifica C2 e encontra C2 = 1
–
P2 verifica C1 e encontra C1 = 1
–
P1 ajusta C1 para 0
–
P2 ajusta C2 para 0
–
P1 entra na sua região crítica
–
P2 entra na sua região crítica
•
Ou seja, nem mesmo o requisito básico de
exclusão mútua é satisfeito...
Terceira Tentativa
task body P1 is begin loop Regiao_Nao_Critica_1; C1 := 0;loop exit when C2 = 1; end loop;
Regiao_Critica_1; C1 := 1; end loop; end P1; task body P2 is begin loop Regiao_Nao_Critica_2; C2 := 0;
loop exit when C1 = 1; end loop;
Regiao_Critica_2; C2 := 1; end loop; end P2; C1, C2: Integer range 0..1 := 1;
Exclusão mútua
Terceira Tentativa
•
A solução satisfaz a propriedade de
exclusão mútua
•
Mas... Considere:
–
P1 atribui 0 para C1
–
P2 atribui 0 para C2
–
P1 testa C2 e permanece no loop
–
P2 testa C1 e permanece no loop...
–
Ou seja, deadlock...
Quarta Tentativa
task body P1 is begin loop Regiao_Nao_Critica_1; C1 := 0; loop exit when C2 = 1; C1 := 1; C1 := 0; end loop; Regiao_Critica_1; C1 := 1; end loop; end P1; task body P2 is begin loop Regiao_Nao_Critica_2; C2 := 0; loop exit when C1 = 1; C2 := 1; C2 := 0; end loop; Regiao_Critica_2; C2 := 1; end loop; end P2; C1, C2: Integer range 0..1 := 1;Exclusão mútua
Quarta Tentativa
•
A solução satisfaz a propriedade de exclusão mútua
•
Mas...Um processo pode sofrer starvation! Considere:
–
P1 atribui 0 para C1
–
P2 atribui 0 para C2
–
P2 testa C1 e então reseta C2 para 1
–
P1 executa o ciclo completo:
• Verifica C2
• Entra na RC
• Reseta C1
• Executa sua RNC
• Ajusta C1 para 0
–
P2 atribui 0 para C2... Ou seja, voltamos ao início... Starvation
de P2.
Quarta Tentativa
•
A solução pode ainda provocar uma “forma” de
deadlock: o livelock (situação em que até que existe
possibilidade de sucesso, mas pode acontecer dos 2
nunca conseguirem entrar na RC!). Exemplo:
–
P1 ajusta C1 para 0
–
P2 ajusta C2 para 0
–
P1 verifica C2 e permanece em loop
–
P2 verifica C1 e permanece em loop
–
P1 reseta C1 para 1
–
P2 reseta C2 para 1
–
P1 ajusta C1 para 0
–
P2 ajusta C2 para 0
–
P1 verifica C2 e permanece em loop
–
P2 verifica C1 e permanece em loop...
Algoritmo de Dekker
task body P1 is begin loop Regiao_Nao_Critica_1; C1 := 0; loop exit when C2 = 1; if Turn = 2 then C1 := 1; loopexit when Turn = 1; end loop; C1 := 0; end if; end loop; Regiao_Critica_1; C1 := 1; Turn := 2; end loop; end P1; C1, C2: Integer range 0..1 := 1; Turn: Integer range 1..2 := 1;
task body P2 is begin loop Regiao_Nao_Critica_2; C2 := 0; loop exit when C1 = 1; if Turn = 1 then C2 := 1; loop
exit when Turn = 2; end loop; C2 := 0; end if; end loop; Regiao_Critica_2; C2 := 1; Turn := 1; end loop; end P2;
Algoritmo de Dekker
•
Satisfaz a propriedade de exclusão mútua
•
Não provoca deadlock
•
Nenhum processo pode sofrer starvation
•
Na falta de disputa pela RC, um processo
pode entrar em sua região crítica
imediatamente
Exclusão Mútua para N processos
O Algoritmo da Padaria
task body P1 is begin loop Regiao_Nao_Critica_1; N1 := 1; N1 := N2 + 1; loop exit whenN2 = 0 or N1 <= N2; end loop; Regiao_Critica_1; N1 := 0; end loop; end P1; task body P2 is begin loop Regiao_Nao_Critica_2; N2 := 1; N2 := N1 + 1; loop exit when
N1 = 0 or N2 < N1; end loop; Regiao_Critica_2; N2 := 0; end loop; end P2; N1, N2: Integer range 0..1 := 0; Para 2 processos Para 2 processos
Exclusão Mútua para N processos
O Algoritmo da Padaria
task body Pi is
I: constant Integer := ...; /* Task id */ begin loop Regiao_Nao_Critica_I; Escolhendo(I) := 1; Number(I) := 1 + max(Number); Escolhendo(I) := 0; for J in 1..N loop if J != I then
loop exit when Escolhendo(J) = 0; end loop; loop exit when
Number(J) = 0 or
Number(I) < Number(J) or
(Number(I) = Number(J) and I < J); end loop; end if; end loop; Regiao_Critica_I; Number(I) := 0; end loop; end Pi;
Escolhendo: array(1..N) of Integer := (others => 0); Number: array(1..N) of Integer := (others => 0);
Para N processos
24