460 likes | 595 Views
Conceitos fundamentais. Alexandre Mota (acm@cin.ufpe.br). Tipos de Execução. Síncrona Único clock Assíncrona Múltiplos clocks, um para cada processo. Estilos. Multithreaded Computação distribuída Computação paralela. Multithreaded. #Processos > #Processadores (Escal.)
E N D
Conceitos fundamentais Alexandre Mota (acm@cin.ufpe.br)
Tipos de Execução • Síncrona • Único clock • Assíncrona • Múltiplos clocks, um para cada processo Programação Concorrente e Distribuída
Estilos • Multithreaded • Computação distribuída • Computação paralela Programação Concorrente e Distribuída
Multithreaded • #Processos > #Processadores (Escal.) • Comunicação por compartilhamento • Exemplos • PC (Janelas) • SO com tempo compartilhado e multiprocessador • Sistemas tempo real (Controle de espaçonave) Programação Concorrente e Distribuída
Computação Distribuída • Máquinas conectadas por LAN/WAN • Comunicação por mensagens ou operações remotas • Exemplos • Servidores de arquivo • BD de bancos, reserva de vôos, etc. • Servidores Web • Sistemas tolerantes a falhas Programação Concorrente e Distribuída
Computação Paralela • Performance é crucial • Comunicação • Compartilhamento/passagem de mensagens • Dados paralelos – tarefa idêntica • Tarefa paralela – processos diferentes em tarefas diferentes • Exemplos • Computação científica • Processamento gráfico • Problemas de otimização/combinatória Programação Concorrente e Distribuída
Padrões • Paralelismo • Iterativo • Recursivo • Produtores/Consumidores (pipelines) • Clientes/Servidores • Pares de interação Programação Concorrente e Distribuída
Notação • Seqüencial baseada em C, C++ e Java • Concorrente • co • process • Outros construtores descritos depois Programação Concorrente e Distribuída
Construtor co • Duas ou mais alternativasco statement1; // … // statementN; oc • co termina quando também todas as alternativas • Indexação • co [i=0 to n-l], { a[i]=0; b[i]=0; } Programação Concorrente e Distribuída
Construtor process • Qualificador de operação • Processos executam em background • process bar2[i=1 to n] { write (i) } • Ordem dos valores é não-determinística Programação Concorrente e Distribuída
Ações Atômicas • Execução de programa concorrente • Interleaving de ações atômicas de processos individuais • Sincronização previne interleaving indesejável • Exclusão Mútua:Combinando ações atômicas simples em ações compostas • Sincronização Condicional:Retardando execução de processo até um estado que satisfaça um predicado Programação Concorrente e Distribuída
Atomicidade Simples • Ação Atômica de Granularidade Simples:Implementada diretamente em hardware • Atribuição parece ser atômica em programas seqüenciais, mas em concorrentes... • int x, y=0, z=0;co x=y+z; // y=1; z=2; oc; • Quais os possíveis valores de x? Usar o SPIN… Programação Concorrente e Distribuída
Atomicidade Simples • int x, y=0, z=0;co x=y+z; // y=1; z=2; oc; • x pode assumir: • 0, 1, 3 • 2 Programação Concorrente e Distribuída
Atomicidade em programas concorrentes • Para obter atomicidade de expressões em programas concorrentes, devemos estabelecer algumas restrições de execução • A solução mais simples é a adoção do requisito de disjunção na avaliação de expressões Programação Concorrente e Distribuída
Disjunção para Expressões • Sejam P e Q dois processos • Se expressão e em P não contém variável alterada em Q • Então, a avaliação de e parecerá atômica devido a • Avaliação de e em P ser independente da execução de Q, e • Nenhum outro processo pode ver variáveis privadas e/ou temporárias de e Programação Concorrente e Distribuída
Disjunção para Expressões • Infelizmente, este requisito é difícil de satisfazer pois o poder de programas concorrentes é usar variáveis compartilhadas para trocar informações • Felizmente, podemos enfraquecer um pouco este requisito e ainda assim obter resultados interessantes Programação Concorrente e Distribuída
Propriedade at-most-once • Requisito mais fraco (que disjunção) mas avaliação ainda pode ser considerada atômica • Definição de Referência Crítica • É uma referência a uma variável que é alterada por um outro processo Programação Concorrente e Distribuída
Expressões • Uma expressão satisfaz a propriedade at-most-once se ela • Contém no máximo uma referência (at most once) a uma variável simples, a qual é alterada por um outro processo (referência crítica) Programação Concorrente e Distribuída
Atribuição • A atribuição x=e satisfaz a propriedade at-most-once se • e contém no máximo uma referência crítica a uma variável simples, ex não é lida (referenciada) por um outro processo • OU • e não contém referência crítica ex pode ser lida por outros processos Programação Concorrente e Distribuída
Exemplo 1 • Sem referências críticas • int x=0, y=0;co x=x+1; // y=y+1; oc; • Valores finais • x=1 e y=1 Programação Concorrente e Distribuída
Exemplo 2 • Com referência crítica, mas também com propriedade at-most-once satisfeita • int x=0, y=0;co x=y+1; // y=y+1; oc; • Primeiro Processo • Tem referência crítica a y, mas • x não é lida pelo segundo processo • Segundo processo não tem referência crítica • Valores finais? Usar o SPIN… Programação Concorrente e Distribuída
Exemplo 3 • Referências críticas, com propriedade at-most-once não satisfeita • int x=0, y=0;co x=y+1; // y=x+1; oc; • Ambos os processos • Têm referência crítica, e • Atribui a variável lida pelo outro processo • Ou seja, há referência cíclica • Valores Finais? Usar o SPIN… Programação Concorrente e Distribuída
Aumentando a granularidade • Com o requisito at-most-once, já conseguimos obter atomicidade para atribuições (comando simples) • Como escalar este resultado para seqüências de comandos (atomicidade composta)? • Ou seja, obter seqüência de comandos que parecem indivisíveis Programação Concorrente e Distribuída
Sincronização • Usamos sincronização para prevenir interleavings indesejáveis • Através de • Combinação de ações atômicas simples em ações compostas: exclusão mútua • Retardando execução de processo até estado do programa satisfazer um predicado: sincronização condicional Programação Concorrente e Distribuída
Operador de sincronização • Inicialmente vamos assumir que possuímos um operador genérico sobre sincronização • Que tanto nos permita garantir exclusão mútua • Quanto sincronização condicional Programação Concorrente e Distribuída
await • Notação: • Comando await (B) S;, onde • B (Condição de atraso) • S (Seqüência de comandos seqüenciais) • B é garantido ser true quando a execução de S começa • Nenhum estado interno em S é visível para outros processos Programação Concorrente e Distribuída
Exemplos • await (s > 0) s = s – 1; • await (t < Max) t = t + 1; Programação Concorrente e Distribuída
Exclusão Mútua • Exclusão MútuaS; • x=x+1;y=y+1;Ambiente externo só vê os estados de x e y antes ou depois da execução de … • Propriedade de S;. Se S for • Instrução simples de uma máquina, ou • Atribuição simples e satisfizer a At-Most-Once • Então S; S Programação Concorrente e Distribuída
Sincronização Condicional • await (B); • await (count > 0);Processo executante será atrasado até que count > 0 • Se B satisfizer at-most-once então await (B); while (not B); • Esta implementação é chamada de spin loop Programação Concorrente e Distribuída
Usando o await • Agora que definimos o await, vamos usá-lo para escrever programas concorrentes seguros • Inicialmente vamos usá-lo explicitamente nas soluções • E depois mostrar como ele próprio pode ser implementado Programação Concorrente e Distribuída
Problema da Seção Crítica • Problema clássico: N processos executam repetidamente seção crítica/não-crítica • process CS[i=1 to N]{ while (true) {entry protocol; critical section;exit protocol; noncritical section; } • } Mesmasoluçãoparaimplementar o await Programação Concorrente e Distribuída
Problema da Seção Crítica • Hipótese • Cada processo que entra em sua seção crítica eventualmente sairá (termina fora da mesma) • Protocolos devem satisfazer as seguintes propriedades: • Propriedades de segurança • Exclusão Mútua • Ausência de deadlock (livelock) • Ausência de atraso desnecessário • Propriedades de liveness • Entrada eventual Programação Concorrente e Distribuída
Problema da Seção Crítica • Exclusão Mútua • No máximo um processo está em sua seção crítica • Ausência de deadlock (livelock) • Se dois ou mais processos tentarem entrar em suas seções críticas, pelo menos um terá sucesso • Ausência de atraso desnecessário • Se um processo estiver tentando entrar em sua seção crítica e os outros estiverem em seções não-críticas ou tiverem terminado => o 1o processo não é impedido de entrar em sua seção crítica • Entrada eventual • Um processo tentando entrar em sua seção crítica eventualmente conseguirá (terá sucesso) Programação Concorrente e Distribuída
Soluções • Solução Trivial • Comando await incondicional em todo comando dentro da seção crítica • Exclusão mútua é resolvida pela semântica • Ausência de deadlock (livelock), atraso desnecessário, e entrada eventual, desde que escalonamento for incondicionalmente justo • Entretanto, como implementar <> para qualquer comando? Programação Concorrente e Distribuída
Solução Alternativa • Vamos analisar o caso para 2 processos • Das propriedades, exclusão mútua é a mais importante • Assim, basta garantir que ambos os processos não entrarão em suas seções críticas simultaneamente • Usando in1 e in2, temos que garantir MUTEX : (in1 in2) Programação Concorrente e Distribuída
Solução Composta bool in1=false, in2=false; process CS1 { while (true) {await (!in2) in1=true; /* entry*/ critical section; in1=false; /* exit */ noncritical section; }} process CS2 { while (true) {await (!in1) in2=true; /* entry*/ critical section; in2=false; /* exit */ noncritical section; }} Programação Concorrente e Distribuída
Spin locks • Generalização da solução anterior usando N variáveis para N processos • Atualmente, duas situações se destacam • Algum processo em sua seção crítica • Nenhum processo em sua seção crítica • Modique exemplo anterior lock == (in1 in2) lockusado em protocolos de entrada e saída Programação Concorrente e Distribuída
Spin locks • Generalização para N processos bool lock=false; process CS1 { while (true) {await (!lock) lock=true; /* entry*/ critical section;lock=false; /* exit */ noncritical section; }} process CS1 { while (true) {await (!lock) lock=true; /* entry*/ critical section;lock=false; /* exit */ noncritical section; }} Programação Concorrente e Distribuída
Resolvendo o await • Note que nas soluções anteriores ainda constinuávamos usando • await (b) attrib; • Apesar de só usarmos atomicidade composta neste caso • Como isso pode ser implementado? Programação Concorrente e Distribuída
Test/Set (TS) • Felizmente, quase todas as máquinas têm alguma instrução especial correspondente a • await (!lock) lock=true; • Assumimos a instrução: Test-and-Set (TS) bool TS (bool lock) { bool initial=lock lock=true; return initial; } Instrução composta suportada atomicamente por hardware Programação Concorrente e Distribuída
Usando TS em Spin Locks Template Original bool lock=false; process CS [i=1 to n] { while (true) {while (TS(lock)) skip; critical section;lock=false; noncritical section; }} process CS [i=1 to n] { while (true) {entry protocol critical section;exit protocol noncritical section; }} 1. Soluções de spin lock possuem mesmo atributo 2. Usar Spin lock para seção crítica: protocolo de saída deveria simplesmente resetar atributo para seu valor inicial Programação Concorrente e Distribuída
Crítica sobre TS • Experimentos em multiprocessadores mostraram que TS pode resultar em baixa performance • Variável lock é compartilhada e todo processo atrasado a referencia continuamente • Este hot spot causa contenção de memória • Como lock é escrito por TS a cada execução, as caches precisam ser alteradas ou invalidadas Programação Concorrente e Distribuída
Test/Test/Set (TTS) • Como a leitura de variáveis compartilhadas não introduz custo adicional • Então surge a solução estendida TTS, baseada na TS mas sem necessariamente atualizar o lock com tanta freqüência Programação Concorrente e Distribuída
Spin locks: de TS para TTS bool lock=false; process CS [i=1 to n] { while (true) { while (lock) skip; while (TS(lock)) { while (lock) skip; } critical section;lock=false; noncritical section; } } bool lock=false; process CS [i=1 to n] { while (true) {while (TS(lock)) skip; critical section;lock=false; noncritical section; }} Programação Concorrente e Distribuída
Referências • Andrews, G.R. Multithreaded, Parallel, and Distributed Programming. Addison-Wesley, 2000. Programação Concorrente e Distribuída