Sistemas - s3-sa-east-1.amazonaws.com · projetos de sistemas operacionais e em aplicações...

37
Sistemas Operacionais Sincronização e Comunicação entre Processos – parte 2/2

Transcript of Sistemas - s3-sa-east-1.amazonaws.com · projetos de sistemas operacionais e em aplicações...

Sistemas

Operacionais Sincronização e

Comunicação entre

Processos – parte 2/2

Sumário

1. Introdução

2. Programação Concorrente

3. Aplicações Concorrentes

4. Especificação de Concorrência

5. Compartilhamento de Recursos

6. Exclusão Mútua

1. Soluções de Hardware

2. Soluções de Software

7. Sincronização Condicional

8. Semáforos

9. Monitores

1. Exclusão Mútua

2. Sincronização Condicional

10. Troca de Mensagens

11. Deadlock

1. Prevenção

2. Detecção e Correção

7. Sincronização Condicional

Situação em que o acesso ao recurso compartilhado exige a sincronização de processos vinculada à uma condição de acesso.

Um recurso pode não se encontrar pronto para uso devido a uma condição específica.

O processo que deseja acessá-lo deverá permanecer bloqueado até que o recurso fique disponível.

7. Sincronização Condicional

Exemplo:

Os processos devem estar sincronizados a uma variável de condição, de forma que um processo não tente gravar dados em um buffer cheio ou realizar uma leitura em um buffer vazio.

Cont = 0 (buffer vazio) e Cont = 1 (buffer cheio).

8. Semáforos

O conceito de semáforos foi proposto por E. W. Dijkstra em 1965, sendo apresentado como um mecanismo de sincronização.

Esse mecanismo permite implementar, de forma simples:

Exclusão mútua

Sincronização condicional

Semáforos tornou-se um dos principais mecanismos utilizados em projetos de sistemas operacionais e em aplicações concorrentes.

Atualmente, a maioria das linguagens de programação disponibiliza rotinas para uso de semáforos.

8. Semáforos

De forma geral, o semáforo é uma variável inteira, não-negativa, que só pode ser manipulada por duas instruções: down e up.

As quais são indivisíveis, ou seja, a execução dessas instruções não podem ser interrompidas:

a instrução UP incrementa uma unidade ao valor do semáforo;

a instrução DOWN decrementa uma unidade do valor da variável.

Por definição, valores negativos não podem ser atribuídos a um semáforo.

A instrução DOWN executada em um semáforo com valor zero faz com que o processo entre no estado de espera (bloqueado, diferente da espera ocupada).

8. Semáforos

O problema do produtor/consumidor é um exemplo de como a exclusão mútua e a sincronização condicional podem ser implementadas com o uso de semáforos.

A solução a ser apresentada usa um buffer de apenas 2 posições.

O programa utiliza 3 semáforos:

1 semáforo binário, utilizado para implementar a exclusão mútua.

2 semáforos contadores para a sincronização condicional.

9. Monitores

O uso de semáforos exige do desenvolvedor bastante cuidado.

Equívocos podem levar a problemas de sincronização imprevisíveis.

O monitor é um conceito de linguagem de programação que o compilador deve reconhecer e organizar.

Os semáforos são mecanismos de sincronização de baixo nível, já os monitores são mecanismos de alto nível.

Simplifica e minimiza erros no desenvolvimento.

Atualmente, a maioria das linguagens de programação oferece suporte ao uso de monitores.

Exemplos: Java, Python, Ruby e C#.

9. Monitores

O monitor é formado por procedimentos e variáveis encapsulados dentro de um módulo.

Sua característica mais importante é a implementação automática da exclusão mútua entre os procedimentos declarados.

Somente um processo pode estar executando um dos procedimentos do monitor em um determinado instante.

Toda vez que algum processo faz uma chamada a um dos procedimentos do monitor, o monitor verifica se já existe outro processo executando algum procedimento do monitor. Caso exista, o processo ficará aguardando a sua vez em uma fila de entrada.

9. Monitores

9.1. Monitores Exclusão Mútua

A implementação da exclusão mútua utilizando monitores não é realizada diretamente pelo programador, como nos semáforos.

As regiões críticas devem ser definidas como procedimentos no monitor.

O compilador se encarregará de garantir a exclusão mútua entre esses procedimentos.

A comunicação do processo com o monitor é feita unicamente por meio de chamadas a seus procedimentos e dos parâmetros passados.

Por exemplo: O programa Monitor_1, apresentado a seguir, mostra a solução para um problema em que dois processos somam e diminuem, concorrentemente, o valor 1 da variável X compartilhada.

9.1. Monitores Exclusão Mútua

9.2. Monitores Sincronização Condicional

Monitores também podem ser utilizados na implementação da sincronização condicional.

Por meio de variáveis especiais de condição, é possível associar a execução de um procedimento que faz parte do monitor a uma determinada condição, garantindo a sincronização condicional.

As variáveis especiais de condição são manipuladas por intermédio de duas instruções, conhecidas como WAIT e SIGNAL.

A instrução WAIT faz com que o processo seja colocado no estado de espera, até que algum outro processo sinalize com a instrução SIGNAL que a condição de espera foi satisfeita.

9.2. Monitores Sincronização Condicional

É possível que vários processos estejam com suas execuções suspensas, aguardando a sinalização de diversas condições.

Para isso, o monitor organiza os processos em espera utilizando filas associadas às condições de sincronização.

A execução da instrução SIGNAL libera apenas um único processo da fila de espera da condição associada.

Um processo pode executar um procedimento de um monitor, mesmo quando um ou mais processos estão na fila de espera de condições.

9.2. Monitores Sincronização Condicional

9.2. Monitores Sincronização Condicional

O monitor Condicional é estruturado com duas variáveis especiais de condição (Cheio e Vazio) e dois procedimentos (Produz e Consome).

Se o processo produtor desejar gravar um dado no buffer, deverá fazê-lo por meio do procedimento Produz do monitor (Condicional.Produz).

Nesse procedimento deve ser testado se o buffer está cheio (número de posições ocupadas no buffer é igual ao seu tamanho).

Se verdadeiro, o processo deve executar um WAIT em Cheio e permanecer aguardando em uma fila de espera associada à Cheio.

O processo bloqueado só poderá prosseguir sua execução quando um processo consumidor executar um SIGNAL em Cheio, indicando que um elemento do buffer foi consumido.

9.2. Monitores Sincronização Condicional

No caso do processo consumidor, sempre que este desejar ler um dado do buffer deverá fazê-lo por meio de uma chamada ao procedimento Consome do monitor (Condicional.Consome).

Sua condição de execução é existir ao menos um elemento no buffer.

Caso o buffer esteja vazio, o processo deve executar WAIT em Vazio, indicando que a continuidade da sua execução depende dessa condição, e permanecer aguardando em uma fila de espera associada à variável Vazio.

O processo produtor que inserir o primeiro elemento no buffer deverá sinalizar esta condição por meio do comando SIGNAL em Vazio, liberando o consumidor.

10. Troca de Mensagens

O mecanismo de troca de mensagens é outra forma de implementar a comunicação entre processos concorrentes.

Possibilita ao sistema trocar mensagens sem o uso de variáveis compartilhadas (semáforos e monitores).

A ideia da troca de mensagens é que, para que haja a comunicação entre processos, deve existir um canal de comunicação, podendo ser:

Um buffer ou;

Um link de uma rede de computadores.

Simplificadamente, a troca de mensagens permite que processos se comuniquem por meio da cópia do dado de interesse do espaço de endereçamento do emissor para o do receptor.

10. Troca de Mensagens

Os processos realizam a troca de mensagens por meio de duas rotinas: SEND e RECEIVE.

A rotina SEND permite o envio de uma mensagem para um processo receptor, enquanto a rotina RECEIVE possibilita o recebimento de mensagem enviada por um processo transmissor.

10. Troca de Mensagens

O mecanismo de troca de mensagens exige que os processos envolvidos na comunicação tenham suas execuções sincronizadas.

A sincronização é necessária, já que uma mensagem somente pode ser tratada por um processo após ter sido recebida.

O envio de mensagem pode ser uma condição para a continuidade de execução de um processo.

A troca de mensagens propriamente dita entre processos pode ser implementada de duas maneiras distintas de comunicação:

Direta: só permite a troca de mensagens entre dois processos.

Indireta: utiliza uma área (buffer) conhecida como mailbox.

10. Troca de Mensagens

Na comunicação indireta as mensagens são enviadas pelo processo transmissor e retiradas pelo processo receptor em uma área (buffer).

Esse tipo de buffer é conhecido como mailbox ou port.

Identificação e capacidade de armazenamento definidas na criação.

Vários processos podem estar associados à mailbox e os parâmetros das rotinas SEND e RECEIVE passam a ser mailboxes, e não mais nomes de processos.

10. Troca de Mensagens

Existem 3 formas para implementar a sincronização pelo mecanismo de troca de mensagens.

1º Forma: Síncrona

• O processo emissor fica bloqueado até que o receptor leia a mensagem e o receptor fica bloqueado até que o emissor envie-a.

• Execução dos processos depende do processamento das mensagens.

2º Forma: Síncrona

• O processo emissor enviará mensagens para diversos destinatários tão logo seja possível.

• Emissor não permanece bloqueado aguardando a leitura da mensagem pelo receptor mas o receptor sim.

10. Troca de Mensagens

3º Forma: Assíncrona

• Nem o processo receptor nem o processo transmissor permanecem aguardando o envio e o recebimento de mensagens.

Necessidade de buffers para armazenar as mensagens.

Deve haver outros mecanismos de sincronização que permitam ao processo identificar se uma mensagem já foi enviada ou recebida.

A grande vantagem é aumentar a eficiência de aplicações concorrentes.

11. Deadlock

11. Deadlock

Deadlock é a situação em que um processo aguarda por um recurso que nunca estará disponível ou um evento que não ocorrerá.

Essa situação é consequência, do compartilhamento de recursos.

Processos concorrentes em que a exclusão mútua é exigida.

Dispositivos, arquivos e registros.

O problema do deadlock torna-se cada vez mais frequente e crítico.

Paralelismo de forma intensiva.

Alocação dinâmica de um número maior de recursos.

11. Deadlock

Exemplo: P_A tem acesso exclusivo a R_1 e precisa de R_2 para prosseguir na execução. P_B tem acesso exclusivo a R_2 e precisa de R_1 para prosseguir na execução.

11. Deadlock

Para ocorrer deadlock, quatro condições existem simultaneamente:

1. Exclusão Mútua: cada recurso só pode ser alocado a um único processo em um determinado instante;

2. Espera por Recurso: um processo, além dos recursos já alocados, pode estar esperando por outros recursos;

3. Não-preempção: um recurso não pode ser liberado de um processo só porque outros processos desejam o mesmo recurso;

4. Espera Circular: um processo pode ter de esperar por um recurso alocado a outro processo, e vice-versa.

11.1. Deadlock Prevenção

Para a prevenção de deadlocks, é necessário garantir que uma das quatro condições apresentadas anteriormente nunca se satisfaça.

1. Exclusão Mútua: se não houver exclusão mútua, não haverá deadlock.

2. Espera por Recurso: o processo deve pré-alocar os recursos necessários antes da execução. Porém pode-se ter desperdício de recursos e pode ser difícil estimar os recursos que serão utilizados.

3. Não-Preempção: basta retirar o recurso de outro processo quando solicitado. Isso pode impedir que o outro processo prossiga.

4. Espera Circular: forçar que o processo tenha apenas um recurso por vez. Isso restringe o compartilhamento e processamento de programas.

11.2. Deadlock Detecção e Correção

Sistemas que não possuam mecanismos que previnam a ocorrência de deadlocks precisam de um esquema de detecção e correção do problema.

A detecção é o mecanismo que determina a existência de deadlock.

Para detectar deadlocks, os sistemas operacionais devem manter estruturas de dados capazes de:

Identificar cada recurso do sistema;

O processo que está alocando o recurso e

Os processos que estão a espera da liberação do recurso.

Sempre que um recurso é alocado ou liberado por um processo, essa estrutura de dados deve ser atualizada.

11.2. Deadlock Detecção e Correção

Os algoritmos que implementam esse mecanismo de detecção geralmente verificam a existência da espera circular.

O sistema operacional deverá de alguma forma corrigir o problema, após a detecção do deadlock.

Uma solução bastante utilizada pela maioria dos sistemas é:

1. Eliminar um ou mais processos envolvidos no deadlock ou;

2. Desalocar os recursos já garantidos a eles, quebrando, assim, a espera circular.

11.2. Deadlock Detecção e Correção

A eliminação dos processos envolvidos do deadlock e, consequentemente, a liberação de seus recursos podem, no entanto, não ser simples, dependendo do tipo do recurso envolvido.

Por exemplo: se um processo estiver atualizando um arquivo ou imprimindo uma listagem.

O sistema deve permitir que esses recursos sejam liberados somente após certificar-se que não ocasionará problemas ao processo.

A escolha do processo a ser eliminado para corrigir o deadlock é feita:

Forma aleatória ou;

Prioridade (pode gerar overhead).

11.2. Deadlock Detecção e Correção

Uma solução menos drástica envolve a liberação temporária apenas de alguns recursos alocados a processos ao invés de eliminar processos.

Para essa solução o sistema deve realizar os seguintes passos:

Suspender um processo;

Liberar seus recursos;

Após a solução do problema, retornar a execução do processo suspenso, sem perder o processamento já realizado.

Este mecanismo é conhecido como rollback.

Overhead.

Muito difícil de ser implementado, por ser bastante dependente da aplicação que está sendo processada.

[Fim] Comunicação entre Processos – Parte 2

“No meio de qualquer dificuldade encontra-se a oportunidade”

Albert Einstein

Próximo Módulo: Gerência de Processador