89
Processos Comunicação e Sincronização

SO-03 Comunicação e Sincronização de Processos

Embed Size (px)

DESCRIPTION

Comunicação e Sincronização de Processos. Problemas Clássicos de Sincronização de Processos (Sistemas Operacionais)

Citation preview

Page 1: SO-03 Comunicação e Sincronização de Processos

Processos Comunicação e Sincronização

Page 2: SO-03 Comunicação e Sincronização de Processos

2 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Processos Concorrentes   Comunicação Interprocessos   O Problema da Seção Crítica   Sincronização por Hardware e por Software   Semáforos   Problemas Clássicos de Sincronização

Page 3: SO-03 Comunicação e Sincronização de Processos

3 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Processos que executam ao mesmo tempo podem existir de maneira independente um dos outros ou podem requerer sincronização ocasional ou cooperação.

  Processos Independentes versus Processos Cooperantes   Independentes: não afetam nem são afetados pela execução de um

outro processo   Cooperantes: podem afetar ou serem afetados pela execução de

outros processos   Vantagens da cooperação:

  compartilhamento de informação   aumento da velocidade de computação   modularidade   conveniência

Page 4: SO-03 Comunicação e Sincronização de Processos

4 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Paradigma de processos cooperantes:   producer produz informação que é consumida pelo consumer

 Buffer sem limite  Buffer limitado

Processo Produtor

Processo Consumidor

Sincronização

buffer tamanho ilimitado x limitado

dados dados

Page 5: SO-03 Comunicação e Sincronização de Processos

5 Comunicação e Sincronização Eduardo Nicola F. Zagari

public interface Buffer{ // producers call this method public abstract void insert(Object item);

// consumers call this method public abstract Object remove();}

Page 6: SO-03 Comunicação e Sincronização de Processos

6 Comunicação e Sincronização Eduardo Nicola F. Zagari

import java.util.*;public class BoundedBuffer implements

Buffer{

private static final int BUFFER SIZE = 5;private int count; // number of items in

the bufferprivate int in; // points to the next

free positionprivate int out; // points to the next

full positionprivate Object[] buffer;public BoundedBuffer() {

// buffer is initially emptycount = 0;in = 0;out = 0;buffer = new Object[BUFFER SIZE];

}// producers calls this methodpublic void insert(Object item) { // Slide 7}// consumers calls this methodpublic Object remove() { // Slide 8}

}

Page 7: SO-03 Comunicação e Sincronização de Processos

7 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void insert(Object item) { while (count == BUFFER SIZE) ; // do nothing -- no free buffers // add an item to the buffer ++count; buffer[in] = item; in = (in + 1) % BUFFER SIZE;}

Page 8: SO-03 Comunicação e Sincronização de Processos

8 Comunicação e Sincronização Eduardo Nicola F. Zagari

public Object remove() { Object item; while (count == 0) ; // do nothing -- nothing to consume // remove an item from the buffer --count; item = buffer[out]; out = (out + 1) % BUFFER SIZE; return item;}

Page 9: SO-03 Comunicação e Sincronização de Processos

9 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Mecanismo do SO que permite que processos se comuniquem e sincronizem suas ações

  Sistema de Mensagens – processos se comunicam entre si sem a necessidade de compartilhar variáveis

  IPC fornece duas operações:   send(message) – mensagem de tamanho fixo ou variável   receive(message)

  Se P e Q desejam se comunicar, eles precisam:   Estabelecer um canal de comunicação entre eles   Trocar mensagens via send/receive

  Implementação do canal de comunicação:   físico (p.ex.: memória compartilhada)   lógico (p.ex.: propriedades lógicas)

Page 10: SO-03 Comunicação e Sincronização de Processos

10 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Como a ligação é estabelecida?   Pode ser associada a mais de 2 processos?   Quantas ligações podem existir entre 2 processos?   Qual a capacidade?   Tamanho da mensagem fixo ou variável?   Unidirecional ou bidirecional?

Page 11: SO-03 Comunicação e Sincronização de Processos

11 Comunicação e Sincronização Eduardo Nicola F. Zagari

send(P, mensagem) receive(Q, mensagem)   ligação automática   ligação entre 2 processos   só existe uma ligação   uni ou bidirecional   desvantagem: se mudar o ID do

processo?

send(A, mensagem) receive(A, mensagem)   ligação entre processos que

compartilham A   ligação entre 2 ou mais processos   podem existir várias ligações   uni ou bidirecional   Processos têm que compartilhar o

mailbox (ID único)

Comunicação direta x indireta

mailbox

Page 12: SO-03 Comunicação e Sincronização de Processos

12 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Troca de Mensagens pode ser bloqueante ou não-bloqueante   Bloqueante é considerada síncrona

  send bloqueante – quem envia espera até que uma mensagem seja recebida

  receive bloqueante – quem recebe espera até que uma mensagem esteja disponível

  Não-bloqueante é considerada assíncrona   send não-bloqueante – o transmissor envia a mensagem e

continua   receive não-bloqueante – o receptor recebe uma mensagem

válida ou um null

Page 13: SO-03 Comunicação e Sincronização de Processos

13 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Filas de mensagens implementam uma das três capacidades: 1.  Zero – 0 mensagens

não pode haver mensagem esperando, quem envia deve esperar até que a mensagem seja recebida (sincronizada)

2.  Limitada – número finito de n mensagensse está cheio, quem envia deve esperar

5.  Ilimitada – tamanho infinito quem envia nunca espera

Page 14: SO-03 Comunicação e Sincronização de Processos

14 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Acesso concorrente a dados compartilhados podem resultar em inconsistência dos mesmos

  Manter a consistência dos dados requer mecanismos para assegurar a execução ordenada dos processos cooperantes

  Race condition : situação em que dois ou mais processos querem partilhar um recurso (escrever e ler dados compartilhados) e o resultado final depende de quem executou quando (ordem de escalonamento)

  Processos concorrentes necessitam de mecanismos de sincronização para evitar que outro processo tenha acesso a uma variável comum, quando esta está sendo modificada por um processo

Page 15: SO-03 Comunicação e Sincronização de Processos

15 Comunicação e Sincronização Eduardo Nicola F. Zagari

Produtor while (1) { while (count ==BUFFER_SIZE) ; // não faz nada // produz um item e o coloca

em nextProduced buffer[in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; }

Consumidor while (1) { while (count == 0) ; // não faz nada nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; // consome o item em nextConsumed }

 A solução de Shared-memory para o problema do buffer limitado tem uma condição de corrida na classe de dados count.

Page 16: SO-03 Comunicação e Sincronização de Processos

16 Comunicação e Sincronização Eduardo Nicola F. Zagari

  count++ poderia ser implementado como

register1 = count register1 = register1 + 1 count = register1

  count– poderia ser implementado como

register2 = count register2 = register2 - 1 count = register2

  Considere esta intercalação de execução: S0: produtor executa register1 = count {register1 = 5}

S1: produtor executa register1 = register1 + 1 {register1 = 6} S2: consumidor executa register2 = count {register2 = 5} S3: consumidor executa register2 = register2 - 1 {register2 = 4} S4: produtor executa count = register1 {count = 6 } S5: consumidor executa count = register2 {count = 4}

Page 17: SO-03 Comunicação e Sincronização de Processos

17 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Como evitar condições de corrida?   Evitar que os processos leiam e escrevam dados compartilhados ao

mesmo tempo   Exclusão Mútua: se um processo estiver usando uma variável ou

arquivo, o outro processo está excluído do uso   Isto é, garantia de acesso exclusivo a um recurso

  Parte do tempo o processo executa computação que não leva a condições de corrida a parte do programa em que memória compartilhada é acessada é chamada de Região Crítica ou Seção Crítica

Page 18: SO-03 Comunicação e Sincronização de Processos

18 Comunicação e Sincronização Eduardo Nicola F. Zagari

1.  Exclusão Mútua – Se o processo Pi está executando dentro da sua seção crítica, então nenhum outro processo pode estar executando em sua seção crítica correspondente   Dois processos não podem estar simultaneamente dentro de suas regiões

críticas correpondentes 3.  Progresso – Se nenhum processo está executando dentro de sua

seção crítica e existem alguns processos que desejam adentrar suas seções críticas, então a seleção do próximo processo que irá entrar em sua seção crítica não pode ser adiada   Nenhum processo que esteja rodando fora de sua seção crítica pode

bloquear a execução de outro processo 5.  Espera Limitada - Nenhum processo pode ser obrigado a esperar

indefinidamente para entrar em sua região crítica   Nenhuma suposição pode ser feita com relação à velocidade de execução

dos processos ou ao número de processadores disponíveis no sistema

Page 19: SO-03 Comunicação e Sincronização de Processos

19 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Mecanismos de Hardware:   Inibição de Interrupções   Instrução TSL (Test and Set Lock)

  Mecanismos de Software:   Com Espera Ocupada:

 Variáveis de Travamento (Lock Variables)  Alternância Estrita  Solução de Peterson

  Sem Espera Ocupada:   Dormir e Acordar (Sleep and Wakeup)   Semáforos   Contadores de Eventos   Monitores   Troca de Mensagens

Page 20: SO-03 Comunicação e Sincronização de Processos

20 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Solução mais simples   Desabilitam-se todas as interrupções após se entrar na região

crítica ao sair, reabilitam-nas   Se as interrupções não ocorrem, o processo não pode sofrer

preempção   Problema 1: ... e se o processo não reabilitar as interrupções?   Problema 2: se o sistema tem 2 CPUs e somente uma tem as

interrupções inibidas, a outra pode acessar a memória compartilhada

  Por outro lado, é muito conveniente que o kernel possa desabilitar as interrupções para atualizar variáveis ou listas

  Conclusão: solução adequada para o kernel, mas não para processos de usuário

Page 21: SO-03 Comunicação e Sincronização de Processos

21 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Instrução especial que permite ler uma variável, armazenar seu conteúdo em uma outra área e atribuir um novo valor a esta variável (hardware)

  É uma instrução indivisível: executada sem interrupção   Variável compartilhada flag: quando flag = 0, qualquer processo

pode fazê-la igual a 1 (instrução TSL)

Page 22: SO-03 Comunicação e Sincronização de Processos

22 Comunicação e Sincronização Eduardo Nicola F. Zagari

enter_region:

tsl register, flag | copia flag p/

| registrador e faz flag = 1

cmp register, #0 | o flag é zero?

jnz enter_region | se não,lock e setado;loop

ret | retorna, entrou na R.C.

leave_region:

mov flag, #0 | guarda um 0 em flag

ret | retorna a quem chamou

Page 23: SO-03 Comunicação e Sincronização de Processos

23 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Define-se uma única variável compartilhada, inicialmente com valor zero

  Se um processo deseja entrar na região crítica, ele testa a variável. Se ela for 1 (recurso liberado), ela é feita 0 (recurso trancado) e o processo entra. Caso contrário, o processo aguarda até que o valor da variável seja 1 (um)

Page 24: SO-03 Comunicação e Sincronização de Processos

24 Comunicação e Sincronização Eduardo Nicola F. Zagari

x = 0, recurso trancado x = 1, recurso liberado

while (x == 0) do /* nada */; Entrada x = 0; Entrada

... Região Crítica x = 1; Saída

  Problema: Este mecanismo apresenta a falha de que a alteração de valor para “trancado”ʼ, após o teste, permite que dois processos executem a Região Crítica (RC) ao mesmo tempo

  O teste e a alteração necessitam ser feitos de forma indivisível (atômica)

Page 25: SO-03 Comunicação e Sincronização de Processos

25 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Inicialmente a variável turn é feita igual a 0 (zero)   Assim, o Processo A consegue entrar na região crítica   Enquanto isto, o Processo B ficará continuamente testando a

variável (Espera Ocupada)

while (TRUE) {

while (turn != 0);

Reg_Crítica();

turn = 1;

Reg_Não_Crítica();

}

while (TRUE) {

while (turn != 1);

Reg_Crítica();

turn = 0;

Reg_Não_Crítica();

}

Processo A Processo B

Page 26: SO-03 Comunicação e Sincronização de Processos

26 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Problema 1: o fato do Processo B ficar fazendo “Espera Ocupada” deve ser evitado, pois consome tempo de CPU

  Problema 2: não é uma boa solução quando um processo é muito mais lento que o outro

  Problema 3: viola a condição de que um processo que não esteja em sua região crítica não bloqueie outro

Page 27: SO-03 Comunicação e Sincronização de Processos

27 Comunicação e Sincronização Eduardo Nicola F. Zagari

 Antes de entrar na Região Crítica (RC), cada processo chama enter_region com seu no (0 ou 1) como parâmetro. Ao sair, leave_region

#include “prototypes.h”

#define FALSE 0

#define TRUE 1

#define N 2 /* no de processos */

int turn; /* de quem é a vez */

int interested[N]; /* todos valores inici- */

/* almente 0 (FALSE) */

Page 28: SO-03 Comunicação e Sincronização de Processos

28 Comunicação e Sincronização Eduardo Nicola F. Zagari

void enter_region (int process) { /* process = quem

está entrando (0 ou 1) */

int other; /* no do outro processo */

other = 1 - process; /* o outro processo */

interested[process] = TRUE; /* mostra interesse */

turn = process; /* define flag */

while (turn==process && interested[other]==TRUE);

}

void leave_region (int process) { /* process = quem

está saindo */

interested[process] = FALSE; /* indica saída RC */

}

Page 29: SO-03 Comunicação e Sincronização de Processos

29 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Duas tarefas, T0 e T1 (Ti e Tj)   Três “soluções” são apresentadas. Todas elas implementam a

interface MutualExclusion :

public interface MutualExclusion { public static final int TURN_0 = 0; public static final int TURN_1 = 1;

public abstract void enteringCriticalSection(int turn); public asbtract void leavingCriticalSection(int turn); }

Page 30: SO-03 Comunicação e Sincronização de Processos

30 Comunicação e Sincronização Eduardo Nicola F. Zagari

Usado para criar duas threads e testar cada algoritmo public class AlgorithmFactory { public static void main(String args[]) { MutualExclusion alg = new Algorithm_1(); Thread first = new Thread( new Worker("Worker 0", 0, alg)); Thread second = new Thread(new Worker("Worker 1", 1, alg));

first.start(); second.start(); } }

Page 31: SO-03 Comunicação e Sincronização de Processos

31 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Worker implements Runnable {

private String name; private int id; private MutualExclusion mutex;

public Worker(String name, int id, MutualExclusion mutex) { this.name = name; this.id = id; this.mutex = mutex; } public void run() { while (true) { mutex.enteringCriticalSection(id); MutualExclusionUtilities.criticalSection(name); mutex.leavingCriticalSection(id); MutualExclusionUtilities.nonCriticalSection(name); } } }

Page 32: SO-03 Comunicação e Sincronização de Processos

32 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Threads compartilham uma variável inteira comum (turn)   Se turn==i, thread i é permitda a executar   Não satisfaz o requisito “Progresso”

  Por quê?

Page 33: SO-03 Comunicação e Sincronização de Processos

33 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Algorithm_1 implements MutualExclusion { private volatile int turn;

public Algorithm_1() { turn = TURN_0; } public void enteringCriticalSection(int t) { while (turn != t) Thread.yield(); } public void leavingCriticalSection(int t) { turn = 1 - t; } }

Page 34: SO-03 Comunicação e Sincronização de Processos

34 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Adicionar mais informação de estado   Flags booleanas para indicar o interesse das threads em

entrar na seção crítica   O requisito “Progresso” ainda não é satisfeito

  Por quê?

Page 35: SO-03 Comunicação e Sincronização de Processos

35 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Algorithm_2 implements MutualExclusion { private volatile boolean flag0, flag1; public Algorithm_2() { flag0 = false; flag1 = false; } public void enteringCriticalSection(int t) { if (t == 0) { flag0 = true; while(flag1 == true) Thread.yield(); } else { flag1 = true; while (flag0 == true) Thread.yield(); } } // Continued On Next Slide

Page 36: SO-03 Comunicação e Sincronização de Processos

36 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void leavingCriticalSection(int t) { if (t == 0) flag0 = false; else flag1 = false; } }

Page 37: SO-03 Comunicação e Sincronização de Processos

37 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Combina as idéias de 1 e 2   Ele satisfaz os requisitos da solução do problema da seção

crítica?

Page 38: SO-03 Comunicação e Sincronização de Processos

38 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Algorithm_3 implements MutualExclusion { private volatile boolean flag0; private volatile boolean flag1; private volatile int turn; public Algorithm_3() { flag0 = false; flag1 = false; turn = TURN_0; } // Continued on Next Slide

Page 39: SO-03 Comunicação e Sincronização de Processos

39 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void enteringCriticalSection(int t) { int other = 1 - t; turn = other; if (t == 0) { flag0 = true; while(flag1 == true && turn == other) Thread.yield(); } else { flag1 = true; while (flag0 == true && turn == other) Thread.yield(); } } // Continued on Next Slide

Page 40: SO-03 Comunicação e Sincronização de Processos

40 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void leavingCriticalSection(int t) { if (t == 0) flag0 = false; else flag1 = false; } }

Page 41: SO-03 Comunicação e Sincronização de Processos

41 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Problema da Solução de Peterson e da Instrução TSL: o processo que não consegue acesso à R.C. permanece em “espera ocupada” (busy waiting):   gasta tempo de processador inutilmente   pode provocar o Problema da Inversão de Prioridade: Dois processos A (alta prioridade) e B (baixa prioridade)

» B entra na Região Crítica; » A vai para estado de pronto; » A passa para estado de execução; » A fica testando indefinidamente.

  Chamadas de sistema: SLEEP e WAKEUP

Page 42: SO-03 Comunicação e Sincronização de Processos

42 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Dois processos compartilham um buffer de tamanho fixo. Um dos processos, o produtor, coloca informação no buffer, e o outro, o consumidor, retira informação do buffer.

  Se o buffer estiver cheio, o produtor dorme e é acordado quando o consumidor remover um item

  Se o buffer estiver vazio, o consumidor dorme até que seja produzido e armazenado algum item

Page 43: SO-03 Comunicação e Sincronização de Processos

43 Comunicação e Sincronização Eduardo Nicola F. Zagari

#define N 100 /* no máximo de ítens */

int count = 0; /* no de ítens no buffer */

void producer (void) {

int item;

while (TRUE) {

produce_item(&item);

if (count==N) sleep();

enter_item(item);

count += 1;

if (count==1) wakeup(consumer);

}

}

void consumer(void) {

int item;

while (TRUE) {

if (count==0) sleep();

remove_item(&item);

count -= 1;

if (count==N-1) wakeup(producer);

consume_item(item);

}

}

Produtor Consumidor

Page 44: SO-03 Comunicação e Sincronização de Processos

44 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Problema:   Se o buffer estiver vazio e o consumidor sofrer preempção antes de

dormir o produtor produz e envia um wakeup para o consumidor que ainda não está dormindo o sinal se perde e o consumidor dormirá para sempre...

Page 45: SO-03 Comunicação e Sincronização de Processos

45 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Mecanismo de sincronização que não requer espera ocupada   Dijkstra propôs usar uma variável inteira para contar o no de

WAKEUPs para uso futuro   Menos complicado   Esta variável, denominada semáforo, pode ter valor 0 (nenhum

WAKEUP pendente) ou um valor inteiro positivo

  Apenas duas operações são definidas sobre estas variáveis: as operações P (Down) e V (Up)

Page 46: SO-03 Comunicação e Sincronização de Processos

46 Comunicação e Sincronização Eduardo Nicola F. Zagari

P(s) (Down) - checa o valor do semáforo. Se o valor é maior que 0 (zero), decrementa e continua. Se for igual a 0, o processo é posto para dormir  Ação atômica: é garantido que, uma vez iniciada a operação, nenhum

outro processo tem acesso ao semáforo (essencial para resolver problemas de sincronização e evitar condições de corrida)

P(s) equivale a: Se s > 0 então s := s - 1 senão bloqueia o processo até s > 0 (= wait(s))

V(s) (Up) - se um ou mais processos estão dormindo no semáforo, um deles é escolhido aleatoriamente pelo SO e continua sua operação Down (o valor zero continua). Se não há ninguém “dormindo” no semáforo, incrementa o valor dele  Operação também é indivisível

V(s) equivale a: Verifica se existe uma lista com processos bloqueados por causa

de s, se existe escolhe um e o “acorda”, deixando-o pronto para seguir sua

execução de P(s) (= signal(s)) senão s := s + 1

Page 47: SO-03 Comunicação e Sincronização de Processos

47 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Semáforo Contador – valor inteiro positivo pode variar sem limites

  Semáforo Binário – valor inteiro só pode variar entre 0 e 1;   Também conhecido como mutex locks

  Para fornecer exclusão mútua:

Semaphore S; // initialized to 1

P(S); criticalSection(); V(S);

Page 48: SO-03 Comunicação e Sincronização de Processos

48 Comunicação e Sincronização Eduardo Nicola F. Zagari

#define N 100 /* no máximo de ítens */ typedef int semaphore;

semaphore mutex = 1; /* controla acesso à RC */ semaphore empty = N; /* conta slots vazios */ semaphore full = 0; /* conta slots ocupados */

void producer (void) {

int item;

while (TRUE) {

produce_item(&item);

P(&empty);

P(&mutex);

enter_item(item);

V(&mutex);

V(&full);

}

}

void consumer(void) {

int item;

while (TRUE) {

P(&full);

P(&mutex);

remove_item(&item);

V(&mutex);

V(&empty);

consume_item(item);

}

}

Page 49: SO-03 Comunicação e Sincronização de Processos

49 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Worker implements Runnable { private Semaphore sem; private String name; public Worker(Semaphore sem, String name) { this.sem = sem; this.name = name; } public void run() { while (true) { sem.acquire(); MutualExclusionUtilities.criticalSection(name); sem.release(); MutualExclusionUtilities.nonCriticalSection(name); } } }

Page 50: SO-03 Comunicação e Sincronização de Processos

50 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class SemaphoreFactory { public static void main(String args[]) { Semaphore sem = new Semaphore(1); Thread[] bees = new Thread[5]; for (int i = 0; i < 5; i++) bees[i] = new Thread(new Worker (sem, "Worker " + (new Integer(i)).toString() )); for (int i = 0; i < 5; i++) bees[i].start(); } }

Page 51: SO-03 Comunicação e Sincronização de Processos

51 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Deadlock – dois ou mais processos ficam esperando indefinidamente por um evento que pode ser causado apenas por um dos processos bloqueados

  Sejam S e Q dois semáforos inicializados com 1 P0 P1

P(S); P(Q); P(Q); P(S); . . . . . . V(S); V(Q); V(Q); V(S);   Starvation – bloqueio indefinido. Um processo pode nunca ser

removido da fila de semáforos na qual ele está bloqueado.

Page 52: SO-03 Comunicação e Sincronização de Processos

52 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Problema do Buffer Limitado   Problema dos Leitores e Escritores   Problema do Jantar dos Filósofos

Page 53: SO-03 Comunicação e Sincronização de Processos

53 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class BoundedBuffer implements Buffer { private static final int BUFFER SIZE = 5; private Object[] buffer; private int in, out; private Semaphore mutex; private Semaphore empty; private Semaphore full;

// Continued on next Slide

Page 54: SO-03 Comunicação e Sincronização de Processos

54 Comunicação e Sincronização Eduardo Nicola F. Zagari

public BoundedBuffer() { // buffer is initially empty in = 0; out = 0; buffer = new Object[BUFFER SIZE]; mutex = new Semaphore(1); empty = new Semaphore(BUFFER SIZE); full = new Semaphore(0); } public void insert(Object item) { /* next slides */ }

public Object remove() { /* next slides */ } }

Page 55: SO-03 Comunicação e Sincronização de Processos

55 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void insert(Object item) { empty.acquire(); mutex.acquire(); // add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER SIZE; mutex.release(); full.release(); }

Page 56: SO-03 Comunicação e Sincronização de Processos

56 Comunicação e Sincronização Eduardo Nicola F. Zagari

public Object remove() { full.acquire(); mutex.acquire(); // remove an item from the buffer Object item = buffer[out]; out = (out + 1) % BUFFER SIZE; mutex.release(); empty.release(); return item; }

Page 57: SO-03 Comunicação e Sincronização de Processos

57 Comunicação e Sincronização Eduardo Nicola F. Zagari

import java.util.Date; public class Producer implements Runnable { private Buffer buffer; public Producer(Buffer buffer) { this.buffer = buffer; } public void run() { Date message; while (true) { // nap for awhile SleepUtilities.nap(); // produce an item & enter it into the buffer message = new Date(); buffer.insert(message); } } }

Page 58: SO-03 Comunicação e Sincronização de Processos

58 Comunicação e Sincronização Eduardo Nicola F. Zagari

import java.util.Date; public class Consumer implements Runnable { private Buffer buffer; public Consumer(Buffer buffer) { this.buffer = buffer; } public void run() { Date message; while (true) { // nap for awhile SleepUtilities.nap(); // consume an item from the buffer message = (Date)buffer.remove(); } } }

Page 59: SO-03 Comunicação e Sincronização de Processos

59 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Factory { public static void main(String args[]) { Buffer buffer = new BoundedBuffer(); // now create the producer and consumer threads Thread producer = new Thread(new Producer(buffer)); Thread consumer = new Thread(new Consumer(buffer)); producer.start(); consumer.start(); } }

Page 60: SO-03 Comunicação e Sincronização de Processos

60 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Acesso a uma base de dados   É aceitável que haja mais de um processo lendo a base de

dados ao mesmo tempo, mas...   ... se um processo estiver escrevendo na base, nenhum outro

processo, nem mesmo os leitores, podem ter acesso a ela, enquanto o escritor não tiver terminado

Page 61: SO-03 Comunicação e Sincronização de Processos

61 Comunicação e Sincronização Eduardo Nicola F. Zagari

Program Solução; typedef int semaphore; semaphore mutex = 1; semaphore db = 1; int rc = 0;

void writer (void) {

while (TRUE) {

think_up_data();

P(&db);

write_data_base();

V(&db);

}

}

void reader (void) {

while (TRUE) {

P(&mutex);

rc++;

if (rc == 1)

P(&db);

V(&mutex);

read_data_base();

P(&mutex);

rc--;

if (rc == 0)

V(&db);

V(&mutex);

use_data_read();

}

}

Page 62: SO-03 Comunicação e Sincronização de Processos

62 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Reader implements Runnable { private RWLock db; public Reader(RWLock db) { this.db = db; } public void run() { while (true) { // nap for awhile db.acquireReadLock();

// you now have access to read from the database // read from the database

db.releaseReadLock(); } } }

Page 63: SO-03 Comunicação e Sincronização de Processos

63 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Writer implements Runnable { private RWLock db; public Writer(RWLock db) { this.db = db; } public void run() { while (true) { db.acquireWriteLock(); // you have access to write to the database

// write to the database

db.releaseWriteLock(); } } }

Page 64: SO-03 Comunicação e Sincronização de Processos

64 Comunicação e Sincronização Eduardo Nicola F. Zagari

public interface RWLock { public abstract void acquireReadLock(); public abstract void acquireWriteLock(); public abstract void releaseReadLock(); public abstract void releaseWriteLock(); }

Page 65: SO-03 Comunicação e Sincronização de Processos

65 Comunicação e Sincronização Eduardo Nicola F. Zagari

public class Database implements RWLock { private int readerCount; private Semaphore mutex; private Semaphore db; public Database() { readerCount = 0; mutex = new Semaphore(1); db = new Semaphore(1); } public int acquireReadLock() { /* next slides */ } public int releaseReadLock() {/* next slides */ } public void acquireWriteLock() {/* next slides */ } public void releaseWriteLock() {/* next slides */ } }

Page 66: SO-03 Comunicação e Sincronização de Processos

66 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void acquireReadLock() { mutex.acquire(); ++readerCount; // if I am the first reader tell all others // that the database is being read if (readerCount == 1) db.acquire(); mutex.release(); } public void releaseReadLock() { mutex.acquire(); --readerCount; // if I am the last reader tell all others // that the database is no longer being read if (readerCount == 0) db.release(); mutex.release(); }

Page 67: SO-03 Comunicação e Sincronização de Processos

67 Comunicação e Sincronização Eduardo Nicola F. Zagari

public void acquireWriteLock() { db.acquire(); }

public void releaseWriteLock() { db.release(); }

Page 68: SO-03 Comunicação e Sincronização de Processos

68 Comunicação e Sincronização Eduardo Nicola F. Zagari

Page 69: SO-03 Comunicação e Sincronização de Processos

69 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Cinco filósofos passam a vida meditando em suas salas e, quando têm fome, vão ao refeitório, comem e voltam a meditar

  Para um filósofo comer é necessário conseguir os dois chopsticks (pauzinhos chineses) que, originalmente, estão à esquerda e à direita do lugar onde se sentou

  Um filósofo pode sentar em qualquer dos cinco lugares   O estoque de comida é interminável   Deve-se garantir:

  exclusão mútua   não ocorrência de deadlock   não ocorrência de adiamento indefinido (starvation)   não existência de prioridade para algum filósofo   possibilidade de velocidades diferenciadas

Page 70: SO-03 Comunicação e Sincronização de Processos

70 Comunicação e Sincronização Eduardo Nicola F. Zagari

Procedure filosofo(i:integer)

begin

while TRUE do

begin

Pensando;

P(pauzinho[i]);

P(pauzinho[(i+1)mod N]);

Comendo;

V(pauzinho[i]);

V(pauzinho[(i+1)mod N]);

end;

end;

Program Tentativa_Um; var pauzinho: array[1..5] of semaforo; i: integer;

Begin for i:= 1 to 5 do

pauzinho[i] := 1;

Cobegin

filosofo(1);

filosofo(2);

filosofo(3);

filosofo(4);

filosofo(5);

Coend;

End.

Page 71: SO-03 Comunicação e Sincronização de Processos

71 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Não funciona se os filósofos resolverem comer ao mesmo tempo e cada um pegar o pauzinho esquerdo

não haverá pauzinho direito (deadlock)

  Pode-se modificar o programa de tal forma que, após pegar pauzinho esquerdo, verifica-se se o pauzinho direto está livre se não, põe-se de volta o pauzinho

suponha que todos peguem e testem juntos adiamento indefinido (starvation)

  Se cada filósofo aguardar um tempo randômico tempo de resposta variável (além de

ainda ser susceptível à falha de inanição)

Page 72: SO-03 Comunicação e Sincronização de Processos

72 Comunicação e Sincronização Eduardo Nicola F. Zagari

Procedure filosofo;

begin

while TRUE do

begin

Pensando;

P(lugar);

Comendo;

V(lugar);

end;

end;

Program Tentativa_Dois; var lugar: semaforo;

Begin lugar := 1;

Cobegin

filosofo;

filosofo;

filosofo;

filosofo;

filosofo;

Coend;

End.

Page 73: SO-03 Comunicação e Sincronização de Processos

73 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Tentativa Dois: proteção através de semáforo binário antes de começar a comer

demais filósofos ficam esperando o primeiro liberar o pauzinho

  Na prática, não funciona a cada instante, apenas um filósofo senta-se à mesa para comer

sub-utilização dos recursos do sistema

Page 74: SO-03 Comunicação e Sincronização de Processos

74 Comunicação e Sincronização Eduardo Nicola F. Zagari

Procedure filosofo(i:integer)

begin

while TRUE do begin

Pensando;

P(lugar);

P(pauzinho[i]);

P(pauzinho[(i+1)mod N]);

Comendo;

V(pauzinho[i]);

V(pauzinho[(i+1)mod N]);

V(lugar);

end;

end;

Program Tentativa_Três; var pauzinho: array[1..5] of semaforo; lugar: semaforo, i: integer;

Begin lugar := 4;

for i:= 1 to 5 do

pauzinho[i] := 1;

Cobegin

filosofo(1);

filosofo(2);

filosofo(3);

filosofo(4);

filosofo(5);

Coend;

End.

Page 75: SO-03 Comunicação e Sincronização de Processos

75 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Tentativa Três: no máximo quatro filósofos sentam-se à mesa ao mesmo tempo

  Para 5 garfos disponíveis, devemos permitir que dois filósofos comam ao mesmo tempo

  Não funciona apenas um irá comer por vez (posse de dois pauzinhos)

  Solução não controlar os recursos, mas os estados dos filósofos...

Page 76: SO-03 Comunicação e Sincronização de Processos

76 Comunicação e Sincronização Eduardo Nicola F. Zagari

Procedure filosofo(i:integer)

begin

while TRUE do begin

Pensando;

Pega_pauzinho(i);

Comendo;

Coloca_pauzinho(i);

end;

end;

Program Solução; Cons N = 5; Pensando = 0; Com_fome = 1; Comendo = 2; Type situacao = [Pensando, Com_fome, Comendo]; var pode_sentar: array[1..5] of semaforo; estado: array[1..5] of situacao; mutex: semaforo; i: integer;

Begin mutex := 1; for i:= 1 to 5 do begin estado[i] := Pensando; pode_sentar[i] := 0; end;

Cobegin

filosofo(1); filosofo(2);

filosofo(3); filosofo(4);

filosofo(5);

Coend;

End.

Page 77: SO-03 Comunicação e Sincronização de Processos

77 Comunicação e Sincronização Eduardo Nicola F. Zagari

Procedure pega_pauzinho(i:integer);

begin

P(mutex);

estado[i] := Com_fome;

testa(i);

V(mutex);

P(pode_sentar[i]);

end;

Procedure testa(i:integer); begin

if (estado[i]= Com_fome and estado[(i-1)mod N] <> Comendo and estado[(i+1) mod N] <> Comendo) then begin

estado[i] := Comendo;

V(pode_sentar[i]); end; end.

Procedure coloca_pauzinho(i:integer);

begin

P(mutex);

estado[i] := Pensando;

testa((i-1) mod N);

testa((i+1) mod N);

V(mutex);

end;

Page 78: SO-03 Comunicação e Sincronização de Processos

78 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Dados compartilhados Semaphore chopStick[] = new Semaphore[5];   Filósofo i:

while (true) { // get left chopstick chopStick[i].acquire(); // get right chopstick chopStick[(i + 1) % 5].acquire(); eating(); // return left chopstick chopStick[i].release(); // return right chopstick chopStick[(i + 1) % 5].release(); thinking(); }

Page 79: SO-03 Comunicação e Sincronização de Processos

79 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Considere que, no projeto da solução do produtor-consumidor com semáforos, os 2 “downs” tenham sido trocados   Se o buffer estiver cheio deadlock

  Monitor = coleção de variáveis, estruturas e procedimentos que são agrupados em um módulo ou pacote (tipo abstrato de dados com operações bem definidas para atuarem sobre sua estrutura de dados)

  Um monitor é uma abstração de alto nível que provê exclusão mútua

  Os procedimentos de um monitor só executam alguma tarefa quando chamados por processos (são passivos) e operam sobre variáveis comuns que constituem sua estrutura de dados

Page 80: SO-03 Comunicação e Sincronização de Processos

80 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Os processos podem chamar procedimentos dos monitores, mas não têm acesso à estrutura interna dos mesmos

  Somente um processo pode estar ativo em um monitor em cada instante, sendo assim, definem regiões críticas criando exclusão mútua para a estrutura de dados do monitor

  Quando um processo chama um procedimento num monitor, verifica-se se outro processo está ativo no monitor   Sim: processo suspenso   Não: processo pode entrar na Região Crítica

  A sincronização entre processos concorrentes se faz através de operações WAIT e SIGNAL sobre variáveis do tipo evento, definidas dentro do monitor   Uma thread (ou procedimento) que invoca x.wait é suspensa até

que outra(o) invoque x.signal   Implementação: precisa de suporte da linguagem

Page 81: SO-03 Comunicação e Sincronização de Processos

81 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Somente uma thread (ou procedimento) pode estar ativo dentro do monitor por vez

monitor monitor-name { // variable declarations public entry p1(…) { … } public entry p2(…) { … } }

Page 82: SO-03 Comunicação e Sincronização de Processos

82 Comunicação e Sincronização Eduardo Nicola F. Zagari

Page 83: SO-03 Comunicação e Sincronização de Processos

83 Comunicação e Sincronização Eduardo Nicola F. Zagari

procedure producer;

begin

while true do

begin

produce_item;

ProduceConsumer.enter;

end;

end;

procedure consumer;

begin

while true do

begin

ProduceConsumer.remove;

consume_item;

end;

end;

Page 84: SO-03 Comunicação e Sincronização de Processos

84 Comunicação e Sincronização Eduardo Nicola F. Zagari

monitor ProducerConsumer condition full, empty; integer count;

procedure enter; begin if count = N then wait(full); enter_item; count := count + 1; if count = 1 then signal(empty); end; procedure remove; begin if count = 0 then wait(empty); remove_item; count := count - 1; if count = N - 1 then signal(full); end; count := 0;

end monitor;

Page 85: SO-03 Comunicação e Sincronização de Processos

85 Comunicação e Sincronização Eduardo Nicola F. Zagari

monitor DiningPhilosophers { int[] state = new int[5]; static final int THINKING = 0; static final int HUNGRY = 1; static final int EATING = 2; condition[] self = new condition[5]; public diningPhilosophers { for (int i = 0; i < 5; i++) state[i] = THINKING; } public entry pickUp(int i) { state[i] = HUNGRY; test(i); if (state[i] != EATING) self[i].wait; } // Continued on Next Slide

Page 86: SO-03 Comunicação e Sincronização de Processos

86 Comunicação e Sincronização Eduardo Nicola F. Zagari

public entry putDown(int i) { state[i] = THINKING; // test left and right neighbors test((i + 4) % 5); test((i + 1) % 5); } private test(int i) { if ( (state[(i + 4) % 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) % 5] != EATING) ) { state[i] = EATING; self[i].signal; } } }

Page 87: SO-03 Comunicação e Sincronização de Processos

87 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Os mecanismos anteriores permitem comunicação indireta   O mecanismo de troca de mensagens entre um processo gerente,

destinado a disciplinar a utilização de determinado recurso, e os processos concorrentes pode ser usado para se obter exclusão mútua

  Duas primitivas -não há compartilhamento de memória   SEND(destino, msg)

  RECEIVE(fonte, &msg)

– Caso não exista mensagem, o processo pode ser bloqueado até a existência de uma

destino: processo destinatário (ex.: PID) msg: mensagem que se quer enviar

fonte: processo que enviou msg: mensagem retornada, se existir

Page 88: SO-03 Comunicação e Sincronização de Processos

88 Comunicação e Sincronização Eduardo Nicola F. Zagari

  Identificação dos processos: processo@máquina   Nomes de máquinas iguais domínio (proc@máq.domínio)

  O armazenamento e a sincronização são feitos pelas primitivas, ou seja, pelo SO, que é o responsável

  A mensagem pode se perder na rede:   mensagem de reconhecimento (acknowledgement)

 se ACK não chegar, retransmite   e se a msg chega, mas o ACK se perde?

 fonte envia msg novamente no de identificação de msg

  Confiabilidade autenticação   Se transmissor e receptor estão na mesma máquina, o

rendimento cai pelo excesso de cópias de dados

Page 89: SO-03 Comunicação e Sincronização de Processos

89 Comunicação e Sincronização Eduardo Nicola F. Zagari

void producer(void) {

int item;

message m;

while (TRUE) {

produce_item(&item);

receive(cons, &m);

build_msg(&m, item);

send(cons, &m);

}

}

void consumer(void) {

int item, i;

message m;

for(i=0; i<N; i++)

send(prod, &m);

while (TRUE) {

receive(prod, &m);

extract_msg(&m,item);

send(prod, &m);

consume_item(item);

}

}

#include “prototypes.h” #define N 100 #define MSIZE 4 typedef int message[4];