170 likes | 287 Views
Sistemas Distribuídos Aula 05 – Programação Multithread/Paralela Prof. Hélio de Sousa Lima Filho ( helio.filho@gmail.com ). Referencial Bibliográfico. Coulouris, George; Dollimore, Jean e Kindberg, Tim. Sistemas Distribuídos: conceitos e projeto .
E N D
Sistemas Distribuídos Aula 05 – Programação Multithread/Paralela Prof. Hélio de Sousa Lima Filho (helio.filho@gmail.com)
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
Sincronização publicclassContaBancaria { . . . publicvoid depositar(double valor) { doubleaux; aux = getSaldo(); aux = aux +valor; setSaldo(aux); } publicvoid sacar(double valor) { doubleaux; aux = getSaldo(); aux = aux - valor; setSaldo(aux); } } Sistemas Distribuídos
Sincronização • Se duas threads chamarem depositar(100); Sistemas Distribuídos
Sincronização • Como criar seções críticas? • Por meio da palavra synchronized. public class ContaBancaria { . . . public synchronized void depositar(double valor) { setSaldo(getSaldo()+valor); } public synchronized void sacar(double valor) { setSaldo(getSaldo()+valor); } } Sistemas Distribuídos
Sincronização • Todo objeto em Java possui um lock: • informa se o objeto foi ou não “travado” por alguma thread • Seja a chamada p.m(): (m é synchronized) • Antes executar m, thread deve adquirir lock de p (i.e., travar p). • Se p já estiver travado, thread espera até ser destravado. • Quando thread terminar execução de m, ela libera o lock de p • Durante execução de m, thread pode chamar outros métodos synchronized desse objeto (sem esperar) Sistemas Distribuídos
Sincronização • Como colocar uma thread para dormir: • por meio de wait() • Chamado por thread de posse do lock de um objeto p • Libera-se o lock deste objeto • Execução desta thread é suspensa até uma execução de notify() ou notifyAll() sobre p • Ao ser “acordada”, thread volta a disputar o lock de p. Execução reinicia na linha seguinte ao wait() Sistemas Distribuídos
Sincronização • Como “acordar” uma thread? notify() ou notifyAll() • notify(): • chamado por thread de posse do lock de um objeto p • Acorda (arbitrariamente) uma das threads que estejam “dormindo” sobre este objeto • Thread acordada volta a disputar lock de p • notifyAll(): • acorda todas as threads que estejam dormindo sobre um determinado objeto. Sistemas Distribuídos
Sincronização • Todo objeto em Java possui dois conjuntos: • Conjunto de entrada: • threads que estão bloqueadas, disputando o lock desse objeto (i.e., chamaram um método sincronizado, mas não iniciaram a execução do mesmo) • Conjunto de espera: • threads cuja execução está suspensa Sistemas Distribuídos
Sincronização • Operações: • wait(): • move a thread corrente para o conjunto de espera do objeto sobre o qual a operação foi chamada. • notify(): • move uma thread arbitrária do conjunto de espera para o conjunto de entrada • notifyAll(): • move todas as threads do conjunto de espera para o conjunto de entrada • Quando uma thread libera o lock de um objeto, uma thread arbitrária do conjunto de entrada é desbloqueada Sistemas Distribuídos
Produtor/Consumidor Java publicclass Produtor extends Thread { private Buffer buf; privateint numero; public Produtor(Buffer buf, int numero) { this.buf= buf; this.numero = numero; } publicvoidrun() { for (int i = 0; i < 10; i++) { // armazena 10 valores no buffer buf.put(i); System.out.println("Produtor #" + numero + " put: “+ i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } } Sistemas Distribuídos
Produtor/Consumidor Java publicclass Consumidor extends Thread { private Buffer buf; privateint numero; public Consumidor(Buffer buf, int numero) { this.buf= buf; this.numero = numero; } publicvoidrun() { // retira 10 valores do buffer int x; for (int i = 0; i < 10; i++) { x = buf.get(); System.out.println("Consumidor #"+ numero + " get: " + x); } } Sistemas Distribuídos
Produtor/Consumidor Java • Suponha um buffer com capacidade para apenas um inteiro e métodos get() e put(): • No método get(), ao sair do wait, • thread deve voltar a testar se buffer está vazio. • Pode ser que outro consumidor tenha obtido o lock do objeto na frente e esvaziado o buffer. • Se isso tiver acontecido, thread volta a dormir • No método put(), ao sair do wait, • thread deve voltar a testar se buffer está cheio. • Pode ser que outro produtor tenha obtido o lock do objeto na frente e ocupado o buffer. • Se isso tiver acontecido, thread volta a dormir publicclass Buffer { privateint valor; privateboolean cheio = false; publicsynchronizedintget() { while (!cheio) { try { wait(); } catch (InterruptedException e) { } } cheio= false; notifyAll(); return valor; } publicsynchronizedvoidput(int valor) { while (cheio) { try { wait(); } catch (InterruptedException e) { } } this.valor= valor; cheio= true; notifyAll(); } } Sistemas Distribuídos
Leitores e Escritores • Assuma que threads leitoras e escritoras compartilham um objeto de uma classe BD, a qual possui um atributo inteiro x e dois métodos: read (retorna o valor de x) e write (incrementa o valor de x). • A solução proposta deve permitir leituras concorrentes. Sistemas Distribuídos
Leitores e Escritores class BD { privateint x; privateintnr= 0; privatesynchronizedvoidstartRead() { nr++; } publicsynchronizedvoidendRead() { nr--; if (nr==0) notify(); } publicintread() { int t; startRead(); t= x; endRead(); return t; } publicsynchronizedvoidwrite() { while (nr > 0) wait(); x++; notify(); } } Sistemas Distribuídos
Leitores e Escritores • Se um escritor ativo: • leitor é bloqueado no startRead() • Se existe leitor ativo: • novos leitores conseguem ler; • novo escritor fica bloqueado no while • notify de endRead: • desbloquear escritores • notify de write; • desbloquear outros escritores Sistemas Distribuídos
Comando synchronized • Permite adquirir o lock de qualquer objeto (por uma duração inferior à execução completa de um método) • Exemplo: voidabs (int [] v) { synchronized (v) { // garante que v é acessado //em uma seção crítica for (int i= 0; i < v.lenghth; i++) if (v[i] < 0) v[i]= -v[i]; } } Sistemas Distribuídos