Programação Concorrente Unidade 1 Definições e Conceitos
Motivação Por que estudar programação concorrente? O mundo a nossa volta funciona concorrentemente Exemplo: ao mesmo tempo estamos... Respirando Lendo Escrevendo Assistindo a essa apresentação, etc. Os computadores atuais também trabalham de forma concorrente Ao mesmo tempo eles... Imprimem um documento Exibem na tela um texto Salvam informações no disco, etc.
Motivação Por que estudar programação concorrente? Determinados problemas demoram muito para serem resolvidos de forma seqüencial, seja devido ao tempo de execução muito longo ou à necessidade de muita memória Física Astronômica: Movimentação de corpos celestes Meteorologia: Previsão do tempo Genética: Genoma humano Farmacologia: Produção de novos medicamentos Processamento de Imagens Processadores disponíveis hoje Bastante rápidos e relativamente baratos (custo/benefício) Podem ser utilizados em paralelo Evitar “ociosidade” de hardware
Motivação Por que estudar programação concorrente? Redução do tempo total de processamento de um programa O desempenho de um programa pode ser melhor se o mesmo for executado em mais de um processador Disponibilidade de Serviços e Tolerância a Falhas Processamento executando em vários processadores
Limitações Limitações Introduz não-determinismos na execução do programa Introduz sobrecarga devido à criação, escalonamento e sincronização na execução das tarefas Determinação de concorrência/paralelismo fica a cargo do programador Não há ferramentas que identifiquem ocorrência de paralelismo em aplicações genéricas e gerem código eficiente
Concorrência X Paralelismo X Distribuição Programação Concorrente Processamento simultâneo que não requer múltiplos processadores Programação Paralela Processamento executado em múltiplos processadores compartilhando memória Programação Distribuída Processamento executado em múltiplos processadores sem compartilhamento de memória (em uma rede de computadores, por exemplo) As duas últimas podem ser entendidas como subclasses da primeira
Programação Concorrente Concorrência Implícita Operações que são executadas em paralelo com a execução do programa (impressão, leitura de disco) Concorrência Explícita Comportamento determinado pelo projetista/programador do programa Neste curso, obviamente, nos deteremos no estudo da concorrência explícita
Programação Concorrente Programa Sequencial Especifica uma execução de uma lista de declarações em sequência Impõe uma ordenação total na execução das declarações Programa Concorrente Formado por unidades concorrentes, ou seja, módulos que não precisam ser executados antes ou depois de outros módulos do programa Não-determinista Impõe uma ordenação parcial, pois o programa não tem total controle sobre a execução das unidades concorrentes
Fluxo de Execução Execução seqüencial Execução concorrente Comandos de controle de fluxo de execução Seqüencial Condicional Iterativo Requisição de execução de unidades explícita:chamada de métodos implícita: ativação de exceções Programa controla a ordem de execução Execução concorrente Cada tarefa é uma unidade de execução autônoma Tarefas podem ser totalmente independentes Exemplo: execução de um mesmo método sobre dois objetos (da mesma classe) Tarefas podem necessitar comunicação Programa não controla a ordem de execução
Fluxo Sequencial X Concorrente Fluxo único de execução Vários fluxos de execução tarefa 1 tarefa 1 tarefa 2 tarefa 3 tarefa 2 tarefa 3 cada fluxo possui uma pilha de execução
Interação entre Processos Todo programa concorrente envolve a interação entre processos Processos competem para obter acesso exclusivo aos recursos compartilhados, como dispositivos e dados Processos se comunicam para a troca de dados Nesse caso, a palavra-chave é sincronização Evitar conflito quando for necessário obter um recurso Estabelecer comunicação quando na troca de dados Interação entre processos Variáveis compartilhadas Passagem de mensagens de um processo para outro
Gerenciamento de Recursos Recurso compartilhado Um processo deve adquiri-lo antes de usá-lo Deve liberá-lo quando seu uso não for mais necessário Se o processo não puder obter o recurso desejado, ele deve ficar suspenso até que o recurso esteja disponível Mais de um recurso pode ser obtido simultaneamente Alguns recursos podem ser obtidos enquanto outros processos o estão compartilhando Processos podem visualizar dados, mas somente um deles pode alterá-los
Comunicação entre Processos Síncrona Processos sincronizam a troca de dados Um processo receptor precisa estar pronto para receber os dados do emissor Assíncrona Processos podem enviar dados para outros mesmo que esses não estejam prontos para recebê-los Uso de buffer de comunicação compartilhado
Problemas de Concorrência Violação de exclusão mútua Algumas operações em um programa podem falhar quando executadas por dois ou mais processos simultaneamente A esta parte do código do programa chamamos de região crítica ou seção crítica Quando um processo está na região crítica, todos os demais processos ficam aguardando até que este finalize seu trabalho Cabe ao desenvolvedor do programa analisar quais as áreas onde deverão ocorrer a exclusão mútua e controlá-las
Problemas de Concorrência Deadlock Um processo está em deadlock, quando está esperando por um evento que NÃO vai acontecer Geralmente é um problema associado ao gerenciamento de recursos compartilhados Quatro condições são necessárias para a ocorrência de deadlock: Processos devem ter acesso exclusivo ao recurso Processos não liberam alguns recursos enquanto esperam por outros Recursos não podem ser removidos dos processos Há uma corrente circular de processos onde cada um está com um recurso que está sendo esperado por um outro processo na corrente Técnicas para evitar deadlock têm que quebrar pelo menos uma das condições acima
Problemas de Concorrência Bloqueado indefinidamente Um processo está nesse estado, quando está esperando por um evento que PODE não acontecer Processos com maior prioridade podem ser executados sempre antes de processos com menor prioridade Erros Transientes Na presença de não-determinismos, falhas em um programa concorrente podem ocorrer de forma transiente, ou seja, um erro pode ou não ocorrer dependendo do fluxo seguido na execução do programa São difíceis de se detectar
Interação entre Processos Geralmente, a interação é feita via variáveis compartilhadas ou pela passagem de mensagens Linguagens de programação tendem a oferecer suporte apenas a um tipo de interação acima Interação via variáveis compartilhadas Manipuladas dentro de uma região crítica Exclusão mútua deve ser implementada Adquirir acesso exclusivo à região crítica REGIÃO CRÍTICA Liberar o acesso exclusivo à região crítica
Interação entre Processos Os principais caminhos para prover essa proteção são: Variáveis de status Indica se uma região está ou não ocupada por um processo A própria variável de status requer acesso exclusivo Isso pode ser feito por uma operação atômica (sem interrrupção) que inspecione a variável e altere o seu valor Apesar de simples, não é muito usado e pode causar problemas Semáforos É uma abstração de mais alto nível para as variáveis de status
Interação entre Processos (Semáforos) Exemplo: Produtor X Consumidor Produtor - produz item - coloca item no buffer, se não estiver cheio Consumidor: - busca item no buffer, se não estiver vazio - consome item aguarda se cheio aguarda se vazio BUFFER de ITENS
Interação entre Processos (Semáforos) FILA código de acesso a recursos compartilhados
Interação entre Processos (Semáforos) Aguarda / Bloqueia: P(semáforo S) se S.contador > 0 então decrementa S.contador senão coloca a tarefa na S.fila, tenta transferir o controle para alguma tarefa apta; se não existir tarefa apta, ocorre deadlock Continua / Libera: V (semáforo S) se se S.contador > 0 então incrementa S.contador senão coloca a tarefa como apta e transfere o controle para uma tarefa da S.fila
Interação entre Processos (Semáforos) Process Produtor; Process Consumidor; Var i: integer; Var i: integer; begin begin loop loop produz(i); P(nãovazio); P(nãocheio); P(exclusão); P(exclusão); retira(i); coloca(i); V(exclusão); V(exclusão); V(nãocheio); V(nãovazio); consome(i); end loop; end loop; end; end; código crítico exclusão nãocheio nãovazio
Interação entre Processos (Semáforos) Process Produtor; Process Consumidor; Var i: integer; Var i: integer; begin begin loop loop produz(i); P(exclusão); P(nãocheio); P(nãovazio); P(exclusão); retira(i); coloca(i); V(exclusão); V(exclusão); V(nãocheio); V(nãovazio); consome(i); end loop; end loop; end; end; exemplo: inverter ordem