A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Sistemas Distribuídos Aula 04 – Programação Multithread/Paralela

Apresentações semelhantes


Apresentação em tema: "Sistemas Distribuídos Aula 04 – Programação Multithread/Paralela"— Transcrição da apresentação:

1 Sistemas Distribuídos Aula 04 – Programação Multithread/Paralela
Prof. Hélio de Sousa Lima Filho

2 Referencial Bibliográfico
Coulouris, George; Dollimore, Jean e Kindberg, Tim. Sistemas Distribuídos: conceitos e projeto. Ribeiro, Uirá. Sistemas Distribuídos, Desenvolvendo aplicações de Alta Performance no Linux. Sistemas Distribuídos

3 Sistemas Distribuídos
Sumário Arquiteturas, Conceitos e Características, Implementação de Seções Críticas Semáforos e Monitores Estudo de Caso: Java Sistemas Distribuídos

4 Sistemas Distribuídos
Sumário Arquiteturas, Conceitos e Características Implementação de Seções Críticas Semáforos e Monitores Estudo de Caso: Java Sistemas Distribuídos

5 Programação Concorrente
Podemos dividir os programas computacionais em duas categorias distintas: Programas seqüenciais único fluxo execução Programa concorrentes vários fluxos execução Em nossa disciplina, iremos dar foco apenas a programação concorrente. Sistemas Distribuídos

6 Programação Concorrente
A programação concorrente, pode ser dividida em 3 grupos distintos: Multithread Paralelos Distribuídos Sistemas Distribuídos

7 Programação Concorrente Multithread
Thread (processos leves) É uma parte de um programa que é executado concorrentemente. É composto por 5 partes: Segmento de código Segmento de dados Pilha Segmento de entrada e saída Tabela de sinais Sistemas Distribuídos

8 Programação Concorrente Multithread
núm. fluxos execução > núm. processadores Objetivo: fazer várias coisas ao mesmo tempo reduzindo o gasto desnecessário de memória de processamento. Como? Através do compartilhamento do segmento de código, segmento de dados e espaço de endereçamento. Exemplos: GUI, SO, SGBD, servidores Web Sistemas Distribuídos

9 Programação Concorrente Multithread
Gerenciador de Processos Pthread Create Thread A Instrução Exit Thread B Pthread Create Instrução Exit “Main” Thread Pthread Join “A” Pthread Join “B” Instrução Instrução Sistemas Distribuídos

10 Programação Concorrente Programas Paralelos
núm. fluxos execução = núm. processadores Objetivo: fazer uma tarefa mais rápido. Exemplos: multiplicar matrizes, previsão tempo, processar/gerar imagem, simulações Sistemas Distribuídos

11 Programação Concorrente Programas Distribuídos
fluxos de execução em nodos de uma rede Objetivo: “compartilhar recursos” Exemplo: aplicações Cliente/Servidos web dados Sistemas Distribuídos

12 Programas Concorrentes Comunicação/Sincronização
Mem. compartilhada Multithreads e Paralelos Troca de mensagens todos os 3 tipos Sistemas Distribuídos

13 Programas Concorrentes Comunicação/Sincronização
A sincronização é a principal dificuldade dos programas concorrentes Seção Crítica Código no qual apenas um processo pode executar por vez Técnicas Exclusão Mútua: assegurar que seções críticas não sejam executadas ao mesmo tempo Dois processos não podem gravar ao mesmo tempo no buffer Sincronização condicional: atrasar a execução até que uma condição seja verdadeira Canal só pode ler dados se buffer cheio Sistemas Distribuídos

14 Sistemas Distribuídos
Conceitos Fluxos execução assíncronos: cada fluxo de execução tem a sua própria “velocidade” Processo: fluxo execução + espaço de endereçamento próprio Thread (“processos leves”): fluxo execução + espaço de endereçamento compartilhado Sistemas Distribuídos

15 Sistemas Distribuídos
Arquiteturas Arquiteturas Monoprocessadas: Programação seqüencial com interrupções Núcleo de multiprogramação (SO, VM, ou biblioteca) cria um modelo de programação assíncrono Vários processos compartilham CPU Arquiteturas Multiprocessadas: Memória Compartilhada Memória Distribuída Sistemas Distribuídos

16 Arquiteturas Multiprocessadas Memória compartilhada
Podem ser: UMA (Uniform Memory Access Time) NUMA (Non-Uniform Memory Access Time) Comunicação via memória compartilhada ou troca de mensagens Vantagem barramento de alta velocidade, memória compartilhada facilita programação Desvantagem limitação no número de nodos Sistemas Distribuídos

17 Arquiteturas Multiprocessadas Memória compartilhada
... Memória Rede de Interconexão Cache CPU ... Sistemas Distribuídos

18 Arquiteturas Multiprocessadas Memória Distribuída
Processos podem acessar apenas memória local Processos se comunicam por troca de msgs Vantagem Escalabilidade Desvantagem Dificuldade de programação Memória Compartilhada Distribuída (DSM) Abstração de um espaço de endereçamento único criada pelo SO SO mapeia “endereço virtual” para endereço físico de um processador Custo de comunicação Sistemas Distribuídos

19 Arquiteturas Multiprocessadas Memória Distribuída
Rede de Interconexão Memória Memória ... Cache Cache CPU CPU Sistemas Distribuídos

20 Arquiteturas Multiprocessadas - Clusters
Computadores “comuns” conectados em rede Cada nodo tem sua CPU, memória e SO Vantagens escalabilidade, custo, tolerância a falhas Desvantagens conexão em rede e administração Custo de administração similar ao de n máquinas independentes Sistemas Distribuídos

21 Arquiteturas Multiprocessadas memória compartilhada
Idéia: calcular produtos internos paralelamente Variáveis compartilhadas: double a[n,n], b[n,n], c[n,n] Sistemas Distribuídos

22 Arquiteturas Multiprocessadas memória compartilhada
Código da multiplicação: process row [i= 0 to n-1] % cria n processos for j:= 0 to n-1 do c[i,j]= 0; for k:= 0 to n-1 do c[i,j] = c[i,j] + a[i,k] * b[k,j] Na solução acima, cada processo gera uma linha da resposta Sistemas Distribuídos

23 Arquiteturas Multiprocessadas memória compartilhada
Outra solução: computar cada produto interno em paralelo process [i= 0 to n-1, j= 0 to n-1] % cria n*n proc c[i,j]= 0; for k:= 0 to n-1 do c[i,j] = c[i,j] + a[i,k] * b[k,j] Sistemas Distribuídos

24 Arquiteturas Multiprocessadas memória distribuída
Agora o mesmo problema de multiplicação de matrizes em memória distribuída process worker[i=0 to n-1] { double a[n]; double b[n,n]; double c[n]; receive initial values for vector a and matrix b; for [j=0 to n-1] { c[j]=0.0; for [k=0 to n-1] c[j]=c[j] + a[k]*b[k,j]; } send result vector c row to the coordinator process; Sistemas Distribuídos

25 Arquiteturas Multiprocessadas memória distribuída
process coordinator { double a[n,n]; double b[n,n]; double c[n,n]; initialize a and b; for [i=0 to n-1] { send row i of a to worker[i]; send all of b to worker[i]; } for [i=0 to n-1] receive row i of c from worker[i]; print the result matrix c; Sistemas Distribuídos

26 Sistemas Distribuídos
IPC via Unix Pipes Pipes mecanismo de IPC (Inter Process Communication) Fila de bytes unidirecional residente no kernel Criação de um pipe: int d [2]; int pipe (d); Escrita e leitura int write (d[1], “hello world”); int read (d[0], buffer, tam_buffer); Pipes entre processos diferentes: Criado por processo pai; em seguida, pai executa um fork Pai e filho passam a compartilhar o pipe Somente pode ser usado entre processos pai e filho ou entre “processo irmãos” Sistemas Distribuídos

27 Produtores/Consumidores via Pipes
void main () { // comunicação de pai para filho int n, d[2]; pid_t pid; char line [MAX_LINE]; if (pipe (d) < 0) printf (“Erro na criação do pipe”); else if ((pid = fork()) < 0) printf (“Erro no fork”); else if (pid > 0) { // processo pai: pid= PID filho close (d[0]); write (d[1], “hello world\n”); } else { // processo filho: pid = 0 close (d[1]); n= read (d[0], line, MAX_LINE); // síncrona cout << line; Sistemas Distribuídos

28 Sistemas Distribuídos
Sumário Arquiteturas, Conceitos e Características Implementação de Seções Críticas Semáforos e Monitores Estudo de Caso: Java Sistemas Distribuídos

29 Processos e Sincronização
Estado valor das variáveis de um processo em um instante Processo executa uma seqüência de comandos Comando: seqüência de ações atômicas Ação atômica: ação que inspeciona/altera estado de forma indivisível Não podem ser quebradas em ações mais simples Exemplos: instruções de máquina que acessam palavras da memória Execução de programa concorrente gera uma história: s0  s1  ...  sn (si: ação atômica) Histórias podem variar de execução para outra Sistemas Distribuídos

30 Processos e Sincronização
Exemplo (atribuições e leituras atômicas): HORA PESSOA A PESSOA B 06:00 Olha a geladeira: sem leite 06:05 Sai para a padaria 06:10 Chega na padaria 06:15 Sai da padaria 06:20 Chega em casa: guarda o leite 06:25 06:30 Chega em casa: Ops! Sistemas Distribuídos

31 Processos e Sincronização
O problema anterior ocorre porque a pessoa não sabia o que a outra estava fazendo A solução para este problema envolve dois conceitos Exclusão mútua: apenas um processo pode fazer alguma coisa em determinado momento Seção Crítica: uma seção crítica de código no qual apenas um processo pode executar de cada vez Sistemas Distribuídos

32 Processos e Sincronização
Exemplo (atribuições e leituras atômicas): int y= 0, z= 0; P1:: x = y +z; P2:: y= 1; z= 2; Algumas histórias possíveis rd y  rd z  x= y+z  y= 1  z= 2 x= 0 y= 1  rd y  rd z  x= y+z  z= 2 x= 1 rd y  y= 1  z= 2  rd z  x= y+z x= 2 y= 1  z= 2  rd y  rd z  x= y+z x= 3 Sistemas Distribuídos

33 Sistemas Distribuídos
Sincronização Sincronização Restringe as histórias possíveis Exclusão mútua requer a criação de ações atômicas via software Uma ação atômica ”de maior granularidade” é chamada de seção crítica Exemplo: < ... > cria uma seção crítica int y= 0, z= 0; P1:: <x = y +z;> P2:: <y= 1; z= 2;> Histórias possíveis: rd y ; rd z ; x= y+z  y= 1 ; z= x= 0 y= 1 ; z= 2  rd y ; rd z ; x= y+z x= 3 Sistemas Distribuídos

34 Sistemas Distribuídos
Sincronização Sincronização condicional: atrasar uma ação atômica até que uma condição seja verdadeira Até que o estado atenda uma condição Propriedade: condição que é verdadeira em qualquer história de um programa concorrente Podem ser de dois tipos: safety e liveness Sistemas Distribuídos

35 Sincronização condicional Safety e Liveness
propriedades que asseguram a não ocorrência de um estado indesejável O programa nunca entra em um estado inconsistente Liveness: propriedade que assegura a ocorrência de um estado desejável Em algum momento o programa entra em um estado consistente Dado um programa concorrente mostrar: Não ocorre deadlock/livelock (safety) Possui uma seção crítica (SC) (safety) Termina (liveness) Eventualmente entra em uma SC (liveness) Sistemas Distribuídos

36 Safety [ Introdução ] Objetos interagindo em múltiplas Threads normalmente provocam interferência Programas concorrentes devem possuir 2 propriedades: Safety: Nada de mau acontecerá durante a execução do programa. Liveness: Algo de bom acontecerá durante a execução do programa.

37 Safety [ Introdução ] Em geral há mais atenção sobre Safety na engenharia É melhor que o programa não faça nada a ter um comportamento aleatório ou até perigoso Liveness está relacionada ao progresso do programa Em alguns casos é melhor obter uma informação imprecisa a não receber Sistemas de Suporte a Decisão, Data Warehouse e Simulação de Trânsito Melhorar a Liveness pode implicar em reduzir a Safety

38 Safety [ Objetos Seguros ]
Em programa OO, o controle de interferência é implementado de classe a classe Objetos/variáveis podem entrar temporariamente em um estado inconsistente Um objeto/variável é considerado seguro quando: Seu estado consistente é sempre consistente Operações não são realizadas enquanto está em um estado inconsistente

39 Safety [ Objetos Seguros ]
Há 3 estratégias conservadoras para projetar objetos/variáveis seguros: Imutabilidade: evitar mudanças de estado Sincronização: garantir acesso exclusivo dinamicamente Contenção: garantir acesso exclusivo estruturalmente

40 Safety [ Imutabilidade ]
Variáveis de instância constantes (final em Java) Encapsulamento Não requer sincronização Classes sem estado (stateless) Como não há estado, não há interferência

41 Safety [ Sincronização ]
Um Objeto/variável sempre está pronto para sofrer modificações, mesmo quando ainda está no meio do processamento de alguma Acesso a estados inconsistentes devem ser evitados: Conflitos de leitura/escrita: vários lêem enquanto um escreve Conflitos de escrita/escrita: vários lêem e escrevem ao mesmo tempo

42 Safety [ Sincronização ]
No contexto de OO, podemos ter: Sincronização Total Objetos totalmente sincronizados. Podem fazer apenas uma operações por vez Sincronização Parcial Parte do objeto é sincronizado. Somente métodos sincronizados são travados

43 Safety [ Contenção ] Baseia-se na idéia de manter referências únicas para objetos internos isolados dos demais. São acessados apenas através de métodos sincronizados do objeto no qual estão contidos, estando, portanto, protegidos. externo1 interno1 interno2 subinterno1

44 Safety [ Contenção ] Recursos Exclusivos
Garante que somente um objeto por vez é “proprietário” do recurso exclusivo. Porém, a propriedade de um recurso pode mudar Semelhanças com objetos físicos: Se você tem um, então pode usá-lo Se você tem um, ninguém mais pode tê-lo Se você da um para alguém, então deixa de tê-lo Se você destrói um, ninguém nunca mais o terá

45 Safety [ Contenção ] É preciso definir um protocolo que garanta a exclusividade do recurso serviço 2 serviço 0 serviço 3 serviço 1 vizinho null Recurso

46 Liveness [ Introdução ]
Projetos baseados em combinações de Imutabilidade, Sincronização e Contenção são abordagens simples, rápidas e de fácil entendimento para o desenvolvimento de programas concorrentes OO Porém, essas técnicas nem sempre são a melhor solução Utilização de Sincronização pode provocar problemas de Liveness (eficiência)

47 Liveness [ Falhas de Liveness ]
São tão sérias quanto falhas de Safety São mais difíceis de identificar e evitar durante o projeto Tipos de falhas Contenção: uma thread, apesar de estar pronta para executar, não executa porque outra tomou recursos (também conhecida como starvation ou adiamento infinito)

48 Liveness [ Falhas de Liveness ]
Dormência: uma thread não pronta falha ao tentar passar para esse estado. Deadlock: duas ou mais threads bloqueiam-se em um ciclo vicioso enquanto tentam acessar travas sincronizadas necessárias para continuar suas atividades Término prematuro: uma thread é parada ou encerrada prematuramente

49 Liveness [ Análise de Variáveis de Instância ]
Através de análise de variáveis e métodos, é possível identificar oportunidades para reduzir a sincronização Muitas vezes, a proteção implementada é exagerada

50 Liveness [ Análise de Variáveis de Instância ]
Acesso Métodos de acesso podem deixar de ser sincronizados para permitir leitura durante a escrita Condições para remover a sincronização: A variável não pode assumir valores ilegais durante a execução dos métodos Atribuição atômica

51 Liveness [ Análise de Variáveis de Instância ]
Atualização Métodos de atualização podem abdicar da sincronização quando satisfaz, além das condições para acesso: Valor da variável permanece consistente em todas as possíveis situações (Ex: atributo temperatura sendo atualizado constantemente por múltiplas threads) Não requer ações especiais sincronizadas para certos valores assumidos pelas variáveis (Ex: reconstruir uma estrutura de dados após atingir um tamanho)

52 Sincronização condicional Safety e Liveness
Como provar que uma propriedade é atendida? Testes (“provam a presença de erros, mas não a ausência”) Formalmente (via asserções etc) Notação (similar a linguagem SR): co “bloco de comandos” co “bloco d comandos” // em SR, “// “ oc “Braços de um comando co” são executados em paralelo (comando termina quando todos braços terminarem) Sistemas Distribuídos

53 Independência de Processos Concorrentes
read set: variáveis lidas e não alteradas write set: variáveis que são alteradas Independência: dois blocos de comandos são independentes se o “write set” de cada bloco é disjunto do “read set” e “write set” do outro bloco Exemplo: P1:: x = y +z; P2:: y= 1; z= 2; read_set(P1)= {y, z} write_set(P2)= {y, z} Sistemas Distribuídos

54 Independência de Processos Concorrentes
race condition: quando programa permite a execução concorrente de blocos de comandos não independentes (ou conflitantes) Exemplo: como paralelizar um grep? String line; read a line of input from stdin into line; while (!EOF) { look for pattern in line; if (pattern is in line) write line; read next line of input; } Sistemas Distribuídos

55 Exemplo: grep paralelo
Versão incorreta (com conflitos): String line1; read a line of input from stdin into line1; while (!EOF) { co look for pattern in line1; // read set= line if (pattern is in line1) print line1 co read next line into line1; // write set= line1 oc } Sistemas Distribuídos

56 Exemplo: grep paralelo
Versão correta: String line1,line2; read a line of input from stdin into line1; while (!EOF) { co look for pattern in line1; // read set= line if (pattern is in line1) print line1 co read next line into line2; // write set= line2 oc line1 = line2; } Desvantagens: cópia entre linhas e criação de duas threads a cada repetição do laço Sistemas Distribuídos

57 Sistemas Distribuídos
Sincronização Execução de programa concorrente: intercalação de “ações atômicas” Sincronização: evita “intercalações indesejadas” Via seções críticas Via sincronização condicional Ação atômica sem condição (ou incondicional): < S > : executa comandos “S” atomicamente Ação atômica com condição (ou condicional): < await (B); S >: espera ocorrência da condição B, então executa “S” atomicamente Sistemas Distribuídos

58 Sistemas Distribuídos
Sincronização Exemplo: < await(s>0); s=s-1 > < s= s+1 > Que operações são estas acima? Exemplo: < x= x+1; y= y+1; > “Estados internos” (como x já incrementado e y não) não são visíveis a outros processos. Regiões críticas são usadas para tratar blocos de código conflitantes No entanto, definir a granularidade de uma seção crítica não é simples Sistemas Distribuídos

59 Exemplo: Computadores e Leite
Processo B if (Aviso){ if (SemLeite){ CompraLeite; } RemoveAviso; Processo A if (SemAviso){ if (SemLeite){ CompraLeite; } DeixaAviso; Funciona? Porque? Somente A deixa aviso e somente se não existe um aviso Somente B remove um aviso Portanto: Se houver um aviso, B compra leite Se não houver um aviso, A compra leite Sendo assim, somente um processo executa a seção crítica O que acontece se B sair de férias? A vai comprar leite uma vez e não poderá comprar mais até que B retorne Sistemas Distribuídos

60 Exemplo: Computadores e Leite
Processo A Deixa AvisoA; while (AvisoB); if (SemLeite){ Compra Leite; } Remove AvisoA; Processo B Deixa AvisoB; if (SemAvisoA){ if(SemLeite){ Compra Leite; } Remove AvisoB; Solução funciona, mas não é boa Muito complicado. Difícil de entender e se convencer que está correto Código de A é diferente de B E se houver mais de 2 processos? Enquanto A está esperando, está consumindo CPU Funciona? Se SemAvisoA, B pode comprar porque A ainda não começou Se AvisoA, A está comprando ou esperando até que B desista. B pode desistir Se SemAvisoB, A pode comprar Se AvisoB não se sabe: Se B comprar, remove AvisoB, fim Se B não comprar, remove AvisoB, A pode comprar Sistemas Distribuídos

61 Sincronizando Produtores e Consumidores
Copiar um vetor de inteiros “a” de um processo para outro, usando um buffer compartilhado Buffer é uma único inteiro “buf” (compartilhado) Sincronização via await implica em uma espera ocupada (“busy wait”) int buf, p=0, c=0; // p: ints produzidos process Producer {//c: ints consumidos int a[n]; while (p<n) { < await (p==c); > // produzido já foi consumido buf=a[p]; // “produz” p=p+1; } process Consumer { int b[n]; while (c<n) { < await (p>c); > // produzido não foi consumido b [c]=buf; // “consome” c=c+1; Sistemas Distribuídos

62 Políticas de Escalonamento
Vários processos, com várias ações candidatas a execução. Como escolher/eleger uma ? Por meio de uma política de escalonamento Escalonamento incondicionalmente justo (fair): uma ação atômica incondicional candidata a execução é eventualmente executada Sistemas Distribuídos

63 Políticas de Escalonamento
Escalonamento fortemente justo: incondicionalmente justo Em <await B; S>, se B às vezes é falsa e às vezes é verdade, então a ação não é sempre selecionada quando sua condição é falsa. Escalonamento fracamente justo: quando não garante a segunda condição acima. Sistemas Distribuídos

64 Políticas de Escalonamento
Exemplo: bool continue= true, try= false; co while (continue) { try = true; try= false; } co <await (try) continue= false>; oc Se fortemente justo, programa sempre termina Se fracamente justo, pode nunca terminar Na prática, fortemente justo não é atendido Sistemas Distribuídos

65 Sistemas Distribuídos
Locks e Barreiras Como implementar uma seção crítica(SC)? Por meio de < .... > Mas na prática, o que é < .... > ? Locks (bloqueios) Sistemas Distribuídos

66 Sistemas Distribuídos
Locks e Barreiras Problema da Seção Crítica: Process SC[i = 1 to n] { while (true) { entry protocol; critical section; exit protocol; noncritical section; } Sistemas Distribuídos

67 Sistemas Distribuídos
Locks e Barreiras Propriedades: Exclusão Mútua (safety) Ausência de deadlocks/livelocks (safety) Ausência de atrasos desnecessários (safety) Entrada em tempo finito (liveness) Sistemas Distribuídos

68 Seção Crítica via Locks
lock: variável booleana que indica se algum processo encontra-se na SC: lock= true: algum processo está na SC lock= false: nenhum processo está na SC SC com locks: < await (!lock) lock = true; > critical section lock = false; Sistemas Distribuídos

69 Seção Crítica via Locks
Como implementar o await acima? Via uma instrução de hardware Test and Set: bool TS(bool lock) { < bool initial = lock; lock = true; return initial; > } SC por meio de Test and Set: while (TS(lock)) skip; // CSEnter critical section; // TS(lock) retornou false; lock=true lock = false; // CSExit Sistemas Distribuídos

70 Seção Crítica via Locks
Exclusão Mútua: Dois processos tentam entrar mesmo tempo Um deles executa TS(lock) primeiro e seta lock para true (entrando na SC) Outro, executa TS(lock), retorna true e espera Ausência de deadlocks: Se 2 processos bloqueados, lock=true sempre Mas para lock ser true, significa que um processo entrou na SC; ele tem que sair e fazer lock= false Ausência de atrasos desnecessários: Se processo fora da SC, então ele não pode bloquear a entrada do outro Sistemas Distribuídos

71 Seção Crítica via Locks
Entrada em tempo finito: Requer escalonamento fortemente justo Nesse caso, assegura-se que “processo atrasado” irá, em algum momento, chamar TS(lock) quando lock=false Por fim, <await (B); S> é implementado como: CSEnter; while(!B) { CSExit; delay; CSEnter; } S; CSExit; Sistemas Distribuídos

72 Algoritmo Tie-Breaker
Solução fair para SC, com dois processos: “in1” e “in2”: processo está ou não na SC “last”: último proc. iniciou protocolo entrada Sistemas Distribuídos

73 Algoritmo Tie-Breaker
bool in1= false, in2= false; int last= 1; process P1 { while (true) { in1= true; last= 1; while (in2 and last ==1) skip; critical section; in1= false; non-critical section; } process P2 { in2= true; last= 2; while (in1 and last ==2) skip; in2= false; Sistemas Distribuídos

74 Algoritmo Tie-Breaker
Exclusão Mútua: Se P1 na SC, (in2==false ou last==2) Logo, P2 não pode estar também na SC Interferência entre processos: Suponha que in2= false e P1 tente entrar Antes de P1 entrar, P2 faz in2= true. P1 entra, mas P2 não consegue pois last==2 Sistemas Distribuídos

75 Algoritmo Tie-Breaker
Fair: Se P1 e P2 disputando SC (in1= in2= true) P2 entrou (isto é, P1 setou last por último) P2 saiu e disputa SC (in2= true; last= 2) P1 entra (já que last==2) Algoritmo Tie-breaker: solução para n processos é mais complexa. Sistemas Distribuídos

76 Sistemas Distribuídos
Algoritmo do Ticket Solução fair para SC, com n processos Algoritmo da “senha” do banco: cliente chega ao banco, pega uma senha e aguarda ser chamado Variáveis: “number”: núm. da próx. “senha” a distribuir “next”: núm. do próx. processo a ser atendido “turn[n]”: armazena senha dos n processos Sistemas Distribuídos

77 Sistemas Distribuídos
Algoritmo do Ticket Algoritmo: int number= 1, next=1; int turn[n]; process CS[i= 1 to n] { while (true) { < turn[i]= number; number++; > < await (turn[i] == next); > critical section; < next++; > non-critical section; } Depende de uma instrução FA (fetch and add): FA(x, incr)= < int t= x; x=x+incr; return t; > Alternativa: usar “test and set” p/ implementar FA Sistemas Distribuídos

78 Sistemas Distribuídos
Barreiras Ponto de sincronização: todos os processos devem atingir este ponto para que a execução de quaisquer deles possa prosseguir Barreiras usando um contador compartilhado: Quando processo atinge a barreira, contador é incrementado Quando contador igual a “n”, abre-se barreira Sistemas Distribuídos

79 Sistemas Distribuídos
Barreiras Exemplo: int count=0 ...... code to implement task i; < count++; > // barreira < await (count==n); > Problemas: como reutilizar a barreira, isto é, como resetar o contador ? Contador deve ser resetado antes que um processo tente incrementá-lo de novo contenção acesso à memória (n-1) processos inspecionando contador, esperando último processo atingir a barreira Sistemas Distribuídos

80 Barreiras com Processo Coordenador
Evita contenção no acesso à memória “arrive[i]”: indica se processo i atingiu barreira “continue[i]”:indica pode prosseguir execução Quem testa um flag, deve resetá-lo int arrive[n], continue[n]; // inicializados com zero process Worker[i=1 to n] { while (true) { code to implement task i; arrive[i]=1; // anuncia chegada < await (continue[i]==1); > // permissão prosseguir continue[i]=0; // reseta flag } process Coordinator for [i=1 to n] { < await (arrive[i]==1); > // aguarda todos chegarem arrive[i]=0; for [i=1 to n] continue[i]=1; // avisa podem prosseguir Sistemas Distribuídos

81 Sistemas Distribuídos
Semáforos Implementação de SC não é trivial Logo, necessita-se de mecanismos de sincronização de mais alto nível, tais como < S > e < await (B); S > (linguagem SR) Semáforos e monitores Semáforos (Dijkstra, 1968): variável inteira compartilhada entre processos. Operações sobre semáforos: sem s; (inicialização) P(s): < await (s>0) s = s-1; > (ou wait) V(s): < s = s+1; > (ou signal) Sistemas Distribuídos

82 Sistemas Distribuídos
Semáforos Exemplo 1: Implementação de Seção Crítica sem livre=1; // livre= 1: SC livre process CS[i=1 to n] { while (true){ wait(livre); critical section; // livre= 0: processo na SC signal(livre); noncritical section; } Sistemas Distribuídos

83 Sistemas Distribuídos
Semáforos Exemplo 2: Erros na utilização de semáforos: wait(livre); CS; wait(livre); (deadlock) signal(livre); CS; wait(livre); (sem exclusão) Semáforo binário: valor é sempre 0 ou 1 Semáforo sinalizador: inicializado com zero Esperando um evento: wait(s) Sinalizando evento: signal(s) Sistemas Distribuídos

84 Sistemas Distribuídos
Semáforos Exemplo 3: Barreiras (semáforo sinalizador) sem arrive1= 0, arrive2= 0; process Worker1 { “executa task1”; signal(arrive1); wait(arrive2); // assegura-se que task1 e task2 executadas } process Worker2 { “executa task2”; signal(arrive2); wait(arrive1); // assegura-se que task1 e task2 executadas Sistemas Distribuídos

85 Sistemas Distribuídos
Produtor/Consumidor M prod., N consumidores e buffer com um inteiro Semáforos: empty: usado para sinalizar que buffer vazio full: usado para sinalizar que buffer cheio Semáforos particionados (split): um processo executa P(s);...;V(r) e outro processo P(r);...;V(s) int buf; sem empty=1, full=0; // inicialmente buffer vazio process Producer[i=1 to M] { while(true) { “produce data“ P(empty); // espera buffer vazio para produzir buf=data; V(full); // após produzir, sinaliza qbuffer está cheio } process Consumer[j=1 to N] { P(full); // espera buffer cheio para consumir result=buf; V(empty); // após consumir, sinaliza buffer vazio Sistemas Distribuídos

86 Produtor/Consumidor com Buffer de Tamanho n
Variáveis: rear: índice onde será inserido próximo valor front: índice de onde será lido próximo valor Valores armazenados no buffer: iniciam em front e terminam em rear-1, de forma circular Possível intercalar “produtores” com “consumidores” (em posições diferentes) Intercalações impossíveis: “produtores com produtores”, “consumidores com consumidores” Sistemas Distribuídos

87 Produtor/Consumidor com Buffer de Tamanho n
Semáforos para criar SC: mutexP e mutexC Produtor: P(mutexP); “produz”; V(mutexP) Consum.: P(mutexC); “consome”; V(mutexC) Semáforos para sinalizar mudanças no buffer: empty: armazena número de posições vazias full: armazena número de posições ocupadas empty+full == n (por construção do algoritmo) Antes produzir, deve existir slot vazio: P(empty) Após produzir, um slot ficou ocupado: V(full) Antes consumir, deve existir slot ocupado: P(full) Após consumir, um slot ficou vazio: V(empty) Sistemas Distribuídos

88 Produtor/Consumidor com Buffer de Tamanho n
int buf[n]; int front=0, rear=0; sem empty=n, full=0; sem mutexP=1, mutexC=1 # for mutual exclusion process Producer[i=1 to M] { # M producers while(true) { “produce data“ P(empty); # block if buffer full - empty is 0 P(mutexP); # block multiple producers to access buffer buf[rear]=data; rear=(rear+1)%n; V(mutexP); # leave critical section V(full); # increment full counter - split semaphore } Sistemas Distribuídos

89 Produtor/Consumidor com Buffer de Tamanho n
process Consumer[j=1 to N] { # N consumers while(true) { P(full); #block if buffer empty - full is 0 P(mutexC); # block multiple consumers to access # buffer result=buf[front]; front=(front+1)%n; V(mutexC); #leave critical section V(empty); # increment empty counter-split # semaphore “consume result” } Sistemas Distribuídos

90 Sistemas Distribuídos
Jantar dos Filósofos Filósofos pensam, comem, pensam, comem, ... Para comer, precisam de dois garfos Existem apenas cinco garfos na mesa Sistemas Distribuídos

91 Sistemas Distribuídos
Jantar dos Filósofos O problema dos filósofos é um exemplo clássico da Programação Concorrente. Tem por objetivo demonstrar a alocação de recursos quando temos processos que concorrem pela alocação dos mesmos, ou seja, os recursos são escassos A implementação proposta apresenta cinco filósofos e cinco garfos. A idéia central deste problema é que dado os FILÓSOFOS e os GARFOS em um jantar, cada filósofo necessita de dois garfos para comer. Os filósofos podem estar em três estados: PENSANDO, FAMINTO ou COMENDO. Se um dos filósofos está no estado PENSANDO e quer passar para o estado COMENDO, ele tenta pegar dois garfos. Se ele não consegue pegar os dois garfos, passa para o estado FAMINTO. Se consegue pegar dois garfos ele passa para o estado COMENDO. Enquanto no estado faminto, o filósofo permanece tentando pegar os garfos, ou seja, fica esperando a liberação de garfos. Como é de conhecimento, caso não exista uma ordem para pegar os garfos, pode ocorrer deadlocks ou espera eterna. Para tanto adotamos a seguinte solução: quando um filósofo quer comer, ele toma um garfo do filósofo a sua direita, se este filósofo não o estiver usando. Assim sendo, os métodos que implementam o ato de pegar e liberar os garfos são sincronizados, ou seja, somente um filósofo entra no corpo do método por vez Sistemas Distribuídos

92 Sistemas Distribuídos
Jantar dos Filósofos Solução: vetor de semáforos representa garfos sem fork[5]= {1,1,1,1,1} # garfos estão livres Pegar garfo i: P(fork[i]) < await fork[i] > 0; fork[i]= fork[i] -1; > Liberar garfo i: V(fork[i]); < fork[i]= fork[i]+1; > Sistemas Distribuídos

93 Sistemas Distribuídos
Jantar dos Filósofos Filósofos pegam o garfo da direita e, logo em seguida, o garfo da esquerda P(fork[i]); P(fork[(i+1)mod 5 ] ); comer V(fork[i]); V(fork[(i+1) mod 5 ]); Sistemas Distribuídos

94 Sistemas Distribuídos
Jantar dos Filósofos Deadlock: filósofos morrem de fome quando cada um pega o garfo à sua esquerda e se recusa a liberá-lo Deadlock: é um ciclo de espera P1 espera por recurso com P2; P2 espera por recurso com P3; ..... Pn espera por recurso com P1 Sistemas Distribuídos

95 Sistemas Distribuídos
Jantar dos Filósofos Solução: quebrar o ciclo acima Filósofo 4 pega primeiro o garfo à sua esquerda (isto é, garfo à direita do Filósofo 3) Assim, Filósofo 3 e 4 disputam este garfo: quem ganhar, come (e evita-se o deadlock) Outra solução: limitar a quatro o número de filósofos que podem comer simultaneamente sem room= 4; Ao ficar com fome: P(room) Após comer: V(room) Sistemas Distribuídos

96 Sistemas Distribuídos
Leitores e Escritores Dois tipos de processos -- leitores e escritores -- compartilham um banco de dados: Escritores devem ter acesso exclusivo ao BD Vários leitores podem acessar juntos o BD Sistemas Distribuídos

97 Sistemas Distribuídos
Leitores e Escritores Escritor: acessa BD em uma SC (semáforo rw=1) P(rw); “write database”; V(rw) Leitor: nr: número de leitores ativos (acessando BD) Ao inciar leitura: incrementar nr Ao terminar leitura: decrementar nr Se primeiro leitor a usar (nr == 1): P(rw) Se último leitor a usar (nr == 0): V(rw) Sistemas Distribuídos

98 Sistemas Distribuídos
Leitores e Escritores Primeira versão do leitor: process Reader[i= 1 to M] { while(true) { < nr++; if (nr == 1) then P(rw); > "read database" < nr--; if (nr == 0) then V(rw); > } Semáforo mutexR: exclusão mútua no acesso à variável nr Sistemas Distribuídos

99 Sistemas Distribuídos
Leitores e Escritores int nr= 0; # number of active readers int rw= 1; # lock for reader/writer exclusion sem mutexR= 1;# lock for reader access to nr process Reader[i= 1 to M] { while(true) { P(mutexR); nr++; if (nr == 1) then P(rw); # if first, get lock V(mutexR) "read database" P(mutexR) nr--; if (nr == 0) then V(rw); # if last, release lock } process Writer[j= 1 to n] { while (true) { .... P(rw); "write the database”; V(rw); } Esta solução não é fair, pois privilegia leitores Se um leitor usando; e se um leitor e um escritor desejarem usar, então leitor vai usar Um fluxo de leitores atrasa um escritor Sistemas Distribuídos

100 Sistemas Distribuídos
Monitores Mecanismo de sincronização de mais alto nível, quando comparado com semáforos Adotado em várias linguagens, como em Java Monitor = variáveis + procedimentos (objeto) Monitor: mecanismo de abstração de dados Suporta automaticamente exclusão mútua em um dado instante, apenas um processo pode executar procedimentos de um monitor Logo, compilador (e não o programador) fica responsável por assegurar exclusão mútua Sistemas Distribuídos

101 Sistemas Distribuídos
Monitores Sintaxe: monitor <name> { <declaração de variáveis> <procedimentos> } Chamando procedimento de um monitor: call <name>.<opname> ( <argumentos> ) Variáveis de um monitor são sempre privadas Sistemas Distribuídos

102 Sistemas Distribuídos
Monitores Sincronização condicional (await) em monitores: implementada usando “variáveis condicionais” Sintaxe: cond cv; // cv é uma var. condicional Valor de uma var. condicional: fila de processos Manipulando variáveis condicionais: empty(cv): fila de cv vazia ? wait(cv): processo se “auto-enfilera” na fila de cv e libera o monitor signal(cv): “acorda” o processo na 1a posição da fila associada a cv Sistemas Distribuídos

103 Sistemas Distribuídos
Monitores Existem duas semânticas para um signal: Signal and Continue (SC): quem emitiu o signal continua executando (processo sinalizado executa mais tarde) Signal and wait (SW): quem emitiu o signal “libera” o monitor (processo sinalizado então inicia execução) Sistemas Distribuídos

104 Implementando Semáforos com Monitores
monitor semáforo { int s= 0; // valor do semáforo cond pos; // fila de processos esperando procedure P() { while (s == 0) wait(pos); s= s - 1; } procedure V() { s= s + 1; signal(pos); Sistemas Distribuídos

105 Implementando Produtor Consumidor com Monitores
monitor Buffer { int buf[n]; # buffer int primeiro=0, #primeira posição ocupada buf ultimo=0; # primeira posição livre em buf cont=0; # número de slots ocupados em bh cond full,#produtores esperando pq buf cheio empty;#consumidores esperando pq buf vazio Sistemas Distribuídos

106 Implementando Produtor Consumidor com Monitores
procedure inserir (int dado) { while (cont==n) wait(full); # enquanto buf cheio, esperar buf[ultimo]=dado; ultimo=(ultimo+1) % n; cont++; signal (empty); # acorda consumidor esperando } Sistemas Distribuídos

107 Implementando Produtor Consumidor com Monitores
procedure retirar (int &dado) { while (cont==0) wait (empty); # enquanto buf vazio, espera dado=buf[primeiro]; primeiro=(primeiro+1) % n; cont--; signal(full); # acorda produtor esperando } Sistemas Distribuídos


Carregar ppt "Sistemas Distribuídos Aula 04 – Programação Multithread/Paralela"

Apresentações semelhantes


Anúncios Google