Modelagem e implementação de programas concorrentes Aula 5 DCC-UFMG 2010
Bibliograa A de sempre + The Mutual Exclusion Problem Part I: A Theory of Interprocess Communication L. Lamport
Interferencia Interferência: instruções executadas por um processo invalidam asserções em outro. Aparece por causa das variáveis compartilhadas A ação a não interfere com a asserção C se {C pre(a)} a {C} é sempre Verdadeiro (C é invariante respeito a execução de a) Exemplo: x = 1; // y = 2; z = x+y; z = x-y; Que podemos fazer ao respeito da interferência?
Interferencia 1. variables disjuntas processos independentes Sobreposição (interação de processos): 1. asserções enfraquecidas armamos menos do que poderiamos na execução isolada 2. invariantes globais predicados que são Verdadeiros em todos os estados visíveis 3. sincronização esconde estados (exclusão mutua <S>) ou demora a execução (sincronização por condição <await B S>)
Seção crítica Precedencia, ver Herlihy Chapter 2
Seção crítica Seção crítica: seqüência de ações envolvida no acesso a variáveis compartilhadas Problema da seção crítica: N processos executam em um loop innito uma sequencia de instruções dividida em 2 subsequencias: a seção critica e a seção nao-critica. <S i > CSEnter S i CSExit. Os processos não podem parar dentro da CS (em algum momento saem) A solução ao problema da seção crítica deve satisfazer 3 regras: Exclusão mutua Progresso (deadlock-freedom) Espera limitada
Seção crítica Exclusão mutua: Se o processo P 1 está executando na sua seção crítica, então nenhum outro processo pode ser executado nessa seção crítica (não pode ter dois processos na seção crítica ao mesmo tempo);
Seção crítica Progresso (deadlock-freedom?): Se um processo está tentando entrar na seção crítica, então algum processo (não necessariamente o mesmo) em algum momento entra a seção crítica. Estado ruim: varios processos esperando por condições que nunca irão ocorrer (deadlock se refere a uma condição especíca em que dois ou mais processos estão esperando porque o outro libere um recurso, ou mais de 2 processos estão esperando por recursos em uma cadeia circular);
Seção crítica Espera limitada (Bounded waiting) (starvation freedom?): Deve existir um limite no número de vezes que outros processos são permitidos de entrar na seção crítica, após a requisição de um processo de entrar na seção critica e antes de que esse pedido é satisfeito (starvation (inanição): a um processo se lhe negam perpetuamente recursos necessários)
Problema da seção crítica Como resolver o problema CS usando instruções de máquina diretamente (sem primitivas de sincronização)? Problema enunciado para N processos, mas começamos por 2! Note: somente existem 2 estados: ninguem na sua CS in1 = false in2 = false alguem na sua CS in1 = true in2 = true
Solução do problema da seção crítica in1 = false; in2 = false; { (in1 in2)} Processo 1 Processo 2 while (true) { while (true) { { (in1 in2)} in1 = true; in2 = true; { (in1 in2)}?? } CS1 in1 = false; NCS1 CS2 in2 = false; NCS2 Exclusão Mutua valendo sempre? Qualquer um entra na seção critica ainda que tenha outro dentro!! Sincronização!
Solução do problema da seção crítica in1 = false; in2 = false; Processo 1 Processo 2 while (true) { while (true) { <await not in2>; <await not in1>; --continua quando not in1 --continua quando not in1 in1 = true; in2 = true; { (in1 in2)}?? } CS1 in1 = false; NCS1 CS2 in2 = false; NCS2 Exclusão Mutua valendo sempre? Não! A leitura e a atribuição precisam ser atômicas!
Solução do problema da seção crítica in1 = false; in2 = false; Processo 1 Processo 2 while (true) { while (true) { <await not in2; <await not in1; in1 = true;> in2 = true;> { (in1 in2)} } CS1 in1 = false; NCS1 CS2 in2 = false; NCS2 Exclusão Mutua valendo sempre? Sim! A invariante (in1 in2) é verdadeira sempre.
Não deadlock Assumir que deadlock é possível, então ambos os processos estão bloqueados no await, ou seja, o processo 1 está no estado: P: { in1 in2} e o processo 2 está no estado: Q: {in1 in2} Mas o predicado P Q não pode ser verdadeiro (Veja teorema de exclusão de congurações no Andrews) porque não pode acontecer ao mesmo tempo de in1 ser verdadeiro e falso e in2 ser verdadeiro e falso Contradição! Portanto, o algoritmo é deadlock-free. Mas, como implementamos o await??
Operações atômicas comuns Test-and-set(TS) Swap Fetch-and-increment Compare-and-swap (CAS) Load-link/Store-conditional Read-modify-write Exemplo: CSenter: while (TS(lock)) skip; CS CSexit: lock = false # exemplo do Andrews
Seção crítica Mas, será possível implementar o await usando somente registros atômicos? Registros atômicos de leitura/escrita (read/write atomic registers): Objetos compartilhados que suportam operações de leitura e escrita atômicas.
Apresentação Herlihy: Algoritmo 1 em Java
Algoritmo 1 Cada processo anuncia que quer entrar na CS: flag1 = false; flag2 = false; Processo 1 Processo 2 while (true) { while (true) { flag1 = true flag2 = true while (flag2); while (flag1); CS1 CS2 flag1 = false; flag2 = false; } }
Algoritmo 1, exclusão mutua Assumindo que os intervalos não se sobrepõem, ou seja, CS j CS k A B e CS k CS j B A então: write A (A = true) read A (B = false) CS A write B (B = true) read B (A = false) CS B Assumindo B o último a ler o ag do outro: write A (A = true) read A (B = false) write B (B = true) read B (A = false) Chegamos a uma contradição: A==true e A==false sem nova atribuição (ela somente acontece na saida da CS e por hipótese o A ainda está na seção crítica).
Algoritmo 1, Deadlock-free? Não. O predicado {ag1 ag2} pode ser verdadeiro.
Algoritmo 2 Cada processo deixa passar ao outro primeiro: int victim; Processo A Processo B while (true) { while (true) { victim = A; --Cede a vez-- victim = B; while (victim==a); while (victim==b); CS1 CS2 } }
Algoritmo 2 Provar Exclusão mutua: pelo absurdo. Assumimos: CS j CS k A B e CS k CS j B A então: write A (victim = A) read A (victim = B) CS A write B (victim = B) read B (victim = A) CS B Assumindo A o último a ler o ag do outro: write B (victim = B) read B (victim = A) read A (victim = B) Chegamos a uma contradição: A não pode ter lido victim=b pois victim=a, não tem outra atribuição de victim=b até o B entrar de novo na CS e os registros são atômicos.
Algoritmo 2 Deadlock: Tem, processo A cede a vez a B, B executa e não volta a tentar entrar na CS.
Algoritmo de Peterson Misturar o melhor de cada um. Anuncio de intenção de entrada na CS e ceder a vez para evitar deadlock. flaga = false; flagb = false; Processo A Processo B while (true) { while (true) { flaga = true; flagb = true; victim = A; victim = B; while(flagb && victim = A); CSA flaga = false; } } while(flaga && victim = B); CSB flagb = false;
Algoritmo de Peterson flaga = false; flagb = false; Processo A Processo B while (true) { while (true) { flaga = true; flagb = true; victim = A; victim = B; while(flagb && victim = A); CSA flaga = false; } } while(flaga && victim = B); CSB flagb = false; Condição do await: agb && victim = A ca enquanto eu seja a vitima B esteja executando. Se o B já tiver tentado entrar (não sou mais a vítima) e B não esta dentro do CS posso entrar. Se o B não entrou ainda posso entrar. A condição agb (victim = A) exclui os casos em que agb victim=b (gera deadlock) e agb victim=a valem (não entra ainda que o B não esteja executando).