Sincronização Arquivo - Comunidade Aprender Livre
Transcrição
Sincronização Arquivo - Comunidade Aprender Livre
Sincronização de Processos Sistemas Operacionais Informática (Técnico) CEFET Atualizado em 19/03/2014 Introdução Processos ou threads de uma aplicação concorrente compartilham recursos do sistema Arquivos Memória Dispositivos de E/S O compartilhamento destes recursos pode ocasionar situações indesejadas, que podem comprometer a execução da aplicação Introdução Para evitar esse problema, os processos e threads devem ter sua execução sincronizada O sistema operacional deve oferecer mecanismos que garantam o correto funcionamento destes processos e threads Exemplo Concorrência Existem várias maneiras de especificar a concorrência entre programas A primeira notação de concorrência em um programa foram os comandos FORK e JOIN Conway (1963) Dennis e Van Horn (1966) Concorrência – FORK e JOIN PROGRAM A; ... FORK B; ... JOIN B; ... END; PROGRAM B; ... ... ... END; Concorrência – FORK e JOIN O FORK faz com que seja criado um outro processo para a execução do programa B, concorrentemente ao programa A. O comando JOIN permite que o programa A sincronize-se com B. Ou seja, o programa A irá esperar pelo término do processamento de B. Concorrência – PARBEGIN e PAREND Uma das implementações mais claras e simples de expressar concorrência foi introduzida por Dijkstra, em 1965 O comando PARBEGIN especifica que a seqüência de comandos seja executada numa ordem imprevisível, através da criação de um processo (Processo_1, Processo_2, Processo_N) para cada comando (Comando_1, Comando_2, Comando_N). O comando PAREND define um ponto de sincronização, onde o programa só continuará quando todos os processos ou threads criados tiverem terminado suas execuções. Problema de Compartilhamento Suponha que um programa principal, P, possua uma variável X, inteira, e duas threads, A e B. Quando executada, a thread A soma 1 a X. Quando executada, a thread B diminui 1 em X. Ao executar as threads concorrentemente qual será o valor de X ? Problema de Compartilhamento Um comando de atribuição em uma linguagem de alto nível pode ser decomposto em mais comandos em linguagem Assembly. Logo, podemos pensar que, para o processador, um comando em linguagem de alto nível pode ainda significar diversos comandos a serem processados. Problema de Compartilhamento Thread A: Thread B: LOAD X, Ra ADD 1, Ra STORE Ra, X LOAD X, Rb SUB 1, Rb STORE Rb, X Problema de Compartilhamento Imagine que A execute: LOAD X, Ra ADD 1, Ra E neste momento A sofra preempção* por tempo e B entre em execução: LOAD X, Rb SUB 1, Rb Neste momento B sofre preempção e A volta a ser processado: STORE Ra, X Finalmente, B retorna a execução: STORE Rb, X X ficará zero (0) ! Preempção: é o direito a preferência Problema de Compartilhamento Recaptulando o exemplo, sendo X = 1: Thread A A B B A B Instrução LOAD X, Ra ADD 1, Ra LOAD X, Rb SUB 1, Rb STORE Ra, X STORE Rb, X X 1 1 1 1 2 0 Ra 1 2 2 2 2 2 Rb ? ? 1 0 0 0 Conclusão Em qualquer situação onde dois ou mais processos ou threads compartilhem um mesmo recurso, devem existir mecanismos de controle para evitar este tipo de problema. Este problema é conhecido como Condição de Corrida (Race Condition). Exclusão Mútua A solução mais simples para evitar o acesso simultâneo a um recurso é impedílo. Enquanto um processo estiver acessando um recurso, os demais processos devem esperar até que o acesso termine. Essa idéia de exclusividade é chamada de Exclusão Mútua (ou “mutex”). Deve afetar apenas os processos concorrentes somente quando os mesmos acessarem um recurso compartilhado. Exclusão Mútua – Região Crítica A parte do código onde é feito o acesso a um recurso compartilhado é chamado de Região Crítica. A idéia é que o código dentro de uma Região Crítica seja executado de forma exclusiva, ou seja, por somente um processo por vez. No código é preciso sinalizar o início e o término da região crítica. Soluções de Hardware A exclusão mútua pode ser implementada através de mecanismos de hardware: Desabilitação de Interrupções Test-And-Set Soluções de Hardware – Desabilitação de Interrupções Ao entrar em uma região crítica, todas as interrupções são desabilitadas Como a preempção é realizada através de uma interrupção, o processo que as desabilitou terá acesso exclusivo garantido. Não haverá preempção ! Soluções de Hardware – Desabilitação de Interrupções Essa solução é simples, mas tem algumas limitações: A multiprogramação pode ficar comprometida, já que a concorrência tem como base o uso de interrupções (preempção). Em sistemas com múltiplos processadores, a solução pode ser ineficiente por causa do tempo de propagação da sinalização (desabilitação/habilitação) para todas as CPUs (caso contrário, outra CPU poderia acessar). Interfere no mecanismo de clock (sinal que coordena as ações de circuitos eletrônicos) do sistema, que é implementado através de interrupções. Logo, deve ser usada com cuidado. Logo, é indicada para o kernel do Sistema Operacional, mas não para processos do usuário. Soluções de Hardware – Test and Set Lock (TSL) É uma instrução especial que permite carregar uma variável booleana (1 bit) compartilhada (global) armazenando seu valor num registrador (LOAD) e atribuindo o valor (STORE) 1 à mesma, num só passo. TSL Ra, flag Copia flag para Ra e faz flag igual a 1 de forma exclusiva. Soluções de Hardware – Test and Set Lock (TSL) Servirá para simularmos uma região crítica. Enquanto o flag for 1, estamos na região crítica. Quando atribuirmos 0 (zero), saímos da região crítica. Como flag é global, todos sabem que enquanto seu valor for 1, todos devem esperar. Soluções de Hardware – Test and Set Lock (TSL) O uso da instrução especial TSL oferece vantagens, como: Simplicidade de implementação da exclusão mútua em múltiplas regiões críticas Pode ser usada em arquiteturas com múltiplos processadores A principal desvantagem é a possibilidade de haver starvation. Primitivas de Exclusão Mútua As soluções de software iniciais usavam as primitivas EnterCriticalSession e LeaveCriticalSession. A maioria era feita pensando na utilização de um único processador. Primitivas de Exclusão Mútua Enquanto uma thread não estiver em sua sessão crítica, outras threads podem entrar em sua própria sessão crítica. Se uma sessão crítica de uma thread não for codificada adequadamente, pode comportar-se mal, levando ao adiamente indefinido de outras threads, ou até ao deadlock*. *Deadlocks serão vistos adiante Sleep e WakeUp São primitivas de comunicação interprocessos que bloqueiam ao invés de gastar tempo de CPU. Sleep é uma chamada ao sistema que faz com que quem a chama fique suspenso até que um outro processo o desperte. WakeUp desperta um processo desejado, passado por parâmetro. Semáforo Conceito criado por Edsger Dijkstra, em 1965. É uma forma de gerar Exclusão Mútua. Pode ser visto como uma variável num programa que controla o acesso a um determinado recurso. Semáforo Se é controlado se um recurso está disponível ou ocupado, dizemos que é um semáforo binário (0 ou 1). Se é controlado a quantidade disponível de um determinado recurso, dizemos que é um semáforo de contagem (0..n). Exemplo com Semáforo Binário Suponha que, num sítio, 5 crianças queiram andar de bicicleta, mas haja apenas 1 bicicleta disponível. Para evitar disputas, cada criança deve solicitar a bicicleta ao caseiro. Enquanto a bicicleta está sendo usada por uma criança, as outras esperam. Quando uma criança entrega a bicicleta ao caseiro, ele a libera para uma outra criança poder usá-la. Pense na bicicleta como o recurso, nas crianças como os processos e o caseiro como o semáforo, que indica se a bicicleta (recurso) está disponível ou não quando a criança (processo a requisita). Exemplo com Semáforo de Contagem Suponha que, num sítio, 30 crianças queiram andar de bicicleta, e hajam 12 bicicletas idênticas disponíveis. Para evitar disputas, cada criança deve solicitar a bicicleta ao caseiro. O caseiro verifica, em sua prancheta, quantas bicicletas estão disponíveis (não importam quais, já que são idênticas). Quando o caseiro cede à uma criança alguma bicicleta, ele diminui a quantidade de bicicletas disponíveis em sua prancheta. Se a quantidade de bicicletas disponíveis chegar a zero, as demais crianças terão de esperar pela liberação de alguma bicicleta. Quando uma criança entrega a bicicleta ao caseiro, ele aumenta a quantidade de bicicletas disponíveis para uso. Pense na bicicleta como o recurso, nas crianças como os processos e o caseiro como o semáforo, que controla se há bicicletas (recursos) disponíveis para uso. Semáforo O uso de semáforos foi adotado em diversos sistemas operacionais para tratar problemas de concorrência (condição de corrida). Apesar de funcionar bem para muitos casos, há a possibilidade de haver bloqueio perpétuo (deadlock), quando ocorrem determinadas seqüências de eventos. Deadlock É um bloqueio perpétuo causado por um impasse. Exemplo: Linhas de Trem Deadlock Um processo está em deadlock quando espera por um evento particular que jamais ocorrerá. Um sistema está em deadlock quando um ou mais processos estão nesta situação. Exemplo Uma cadeia sucessiva de solicitações de recursos que culminam num arranjo circular. Um processo A, que detém um recurso R1, solicita um recurso R2 alocado para um processo B. B por sua vez está solicitando o recurso R1, em uso por A. Como nenhum processo dispõe a, voluntariamente, liberar o recurso que aloca, configura-se uma situação de bloqueio perpétuo. Exemplo A R1 R2 B Maneiras de Resolver 1. 2. 3. 4. Ignorar o problema e conviver com ele Detectar e se recuperar Prevenção dinâmica (por análise) Prevenção estrutural (exclusão mútua, etc.) Questões 1. 2. 3. 4. 5. Por que devemos efetuar a sincronização do acesso a recursos feitos por threads? O que é uma Condição de Corrida? Dê um exemplo de uma situação onde há uma Condição de Corrida. O que é Exclusão Mútua? O que é uma Região Crítica? Questões 6. Como funciona a implementação de Exclusão Mútua por hardware através da Desabilitação de Interrupções? Quais as suas vantagens e desvantagens? 7. Como funciona a implementação de Exclusão Mútua por hardware através da instrução TSL ? Questões Qual é a idéia por trás dos algoritmos propostos por Dekker e Peterson? Qual é a desvantagem desses algoritmos? 9. Para que servem as primitivas Sleep e WakeUp? 10. Qual a idéia dos Semáforos, introduzidos por Dijkstra, aproveitando o uso das primitivas Sleep e WakeUp? 8. Questões 11. O que é Deadlock? Dê o exemplo de uma situação, no contexto de processos e threads, em que ele ocorre.