Computação Paralela Especificação de Concorrência/Paralelismo João Luís Ferreira Sobral Departamento do Informática Universidade do Minho Outubro 2005 Especificação de Concorrência/Paralelismo Baseada nos conceitos de fio de execução (thread)/ processos Fio de execução versus processo Paralelismo lógico versus paralelismo físico Preempção de fios de execução Escalonamento dos fios com base em prioridades Vantagens da utilização da concorrência Programas que requerem a execução de várias tarefas (reactivos) Existem objectos do mundo real que são activos Melhora a disponibilidade de serviços Possibilita as mensagens/invocações de métodos assíncronas Tira partido do paralelismo quando existem vários CPU Concorrência requerida (em Java várias classes executam de forma concorrente, ex. Swing, applet, beans) Computação Paralela 2 Especificação de Concorrência/Paralelismo Limitações da concorrência Segurança (safety) – inconsistências na execução de programas Vivacidade (liveness) – impasses na execução de programas Introduz não determinismo na execução dos programas Em sistemas OO existem menos actividades assíncronas que objectos Pouco útil na execução local de métodos, num modelo chamada/resposta Introduz uma sobrecarga devido à criação, escalonamento e sincronização dos fios de execução Concorrência em aplicações tradicionais Modelos de fork/join, cobegin/coend, e parfor. A sincronização é efectua com semáforos, barreiras ou monitores. Processos activos (CSP) Efectuam processamento através de um corpo activo, interactuando através da passagem de mensagens, síncrona com bloqueio, síncrona sem bloqueio ou assíncrona. Computação Paralela 3 Especificação de Concorrência/Paralelismo Concorrência em aplicações orientadas ao objecto Invocações síncronas (modelos tradicionais) Invocações assíncronas sem valor de retorno (one way) o cliente fica bloqueado enquanto o método é executado pelo servidor, mesmo que não exista um valor de retorno. Quando o método invocado não retorna um valor pode ser efectuada uma invocação assíncrona, podendo o cliente prosseguir a execução em simultâneo com a execução do método no servidor. Invocações assíncronas com valor de retorno Quando existe um valor de retorno as invocações também podem ser assíncronas, existindo, no entanto, três alternativas para o retorno do resultado da operação: Síncrona diferida - O cliente efectua uma segunda invocação ao servidor para obter o resultado Servidor Cliente tarefa() tempo resultado() Computação Paralela 4 Especificação de Concorrência/Paralelismo Concorrência em aplicações orientadas ao objecto (cont.) Invocações assíncronas com valor de retorno (cont) Com chamada de retorno (callback)– O servidor efectua uma invocação de um método pré-definido do cliente, quando a execução terminou Servidor Cliente tarefa() resultado() Com futuros – A invocação é delegada a outro objecto que armazena o resultado da operação. Servidor Futuro Cliente tarefa() tarefa() resultado() Computação Paralela 5 Programação Concorrente em Java JAVA é das poucas linguagens com suporte à programação concorrente Classe java.lang.Thread: Thread(Runnable r); // construtor da classe start(); // cria um fio de execução e invoca r.run() join(); // espera pelo fim da execução do fio sleep(int ms); // suspende o fio de execução setPriority(int Priority); // altera a prioridade Interface Runnable Deve ser implementado por todas as classes pretendam ser directamente executadas por um fio de execução. O método run() contém o código a executar pelo fio de execução. interface Runnable { public void run(); } Computação Paralela 6 Programação Concorrente em Java • Exemplo Dois fios de execução que incrementam cada um o seu contador public class Cont extends Thread { // implícito: implements Runnable public Cont() { } public void run() { for (int i=0; i<100; i++) System.out.println(“ i= “ + i); } } Execução sequencial: ... new Cont().run(); new Cont().run(); ... // join Computação Paralela z Execução concorrente: ... new Cont().start(); new Cont().start(); // ou new Cont().run(); ... // join, para esperar pelo fim da execução 7 Programação Concorrente em Java Segurança – nada de mau deve acontecer num programa Vivacidade – algo de bom deve acontecer num programa Exemplo de falta de segurança: execução do método inc() por dois fios em simultâneo pode originar um valor incoerente da variável ct public class Cont { protected int ct; public Cont() { ct=0; } public void inc() { ct = ct + 1; } } Computação Paralela 8 Programação Concorrente em Java Especificação de sincronização entre fios de execução (aumentar a segurança) Com a palavra chave synchronized (mutex) synchronized metodo() { ... } // metodo tem o acesso exclusivo ao objecto synchronized (umObj) { ... } // obtém o acesso exclusivo a umObj Com monitores (Implementados pela classe Object) wait() – espera pelo acesso ao monitor wait(int timeout) – wait, com temporização notify() – acorda um fio à espera de acesso notifyAll() – acorda todos os fios à espera Computação Paralela 9 Programação Concorrente em Java Exemplo de falta de vivacidade (deadlock): execução de método inc() por dois fios em simultâneo em objectos com referências cruzadas: Obj1: .... void syncronized inc() { obj2.inc() } .... Obj2: ... void syncronized inc() { obj1.inc() } Computação Paralela 10 Programação Concorrente em Java Padrões para melhorar a segurança objectos imutáveis ou sem estado (exemplo classe String) public int[] sort(int[] arr) { int[] copy = arr.clone(); // cópia local … // sort return(copy); } sincronização parcial class Cell { private int val; private Cell next; public int synchronized getValue() { return(val); } public void synchronized setValue(int vl) { val=vl; } public Cell getNext() { return(next); } } Objectos contidos em outros objectos Computação Paralela 11 Programação Concorrente em Java Padrões para melhorar a vivacidade Os métodos que apenas lêem o estado do objecto geralmente não necessitam de ser sincronizados (excepto para double e long) Não é necessário sincronizar as variáveis que são escritas apenas uma vez: void setEnd() { end = True; } Utilizar, sempre que possível, a sincronização separada, para acesso a cada parte do estado (ou dividir o estado em dois objectos) class doisPontos { Ponto p1, p2; public void movexp1(int x) { synchronized (p1) { p1.movex(x); } } public void movexp2(int x) { synchronized (p2) { p2.movex(x); } } } Computação Paralela 12 Programação Concorrente em Java Padrões para melhorar a vivacidade (cont.) Estruturas de dados ligadas podem utilizar fechos separados para a inserção e para a remoção. Os recursos devem ser acedidos sempre pela mesma ordem para minimizar os impasses. public void update() { synchronized(obj1) { synchronized(obj2) { ... // do update } } } Computação Paralela 13 Acções Dependentes do Estado dos Objectos Que acção tomar quando um objecto não pode satisfazer um pedido? Ignorar o pedido Retornar uma indicação de falha (excepção?) Suspender o cliente até que a condição se verifique Tomar uma acção provisória Prosseguir por forma a poder repor o estado se algo correr mal Repetir a acção até ser possível executá-la Estratégias pessimistas versus estratégias optimistas Representação lógica do estado versus representação física do estado Estado lógico: normalmente definido por predicados: expressões Booleanas em função do estado (ex. buffer cheio, meio e vazio) O estado lógico pode ser representado explicitamente em variáveis Computação Paralela 14 Acções Dependentes do Estado dos Objectos Suspensão do cliente através de guardas Métodos wait(), notify() e notifyAll() da classe Object Exemplo1 (wait()) public class GuardedClass { protected boolean cond=false; public synchronized void guardedAction() { while(!cond) { try { wait(); }catch (InterruptedException e) {} } } public synchronized void setCond() { cond=true; notifyAll(); } } Exemplo2 (espera activa – pouco eficiente) protected void spinWaitC() { while(!cond) { Thread.yield(); } } Problemas com monitores encadeados: wait() apenas liberta o fecho desse monitor e não do monitor do objecto exterior Computação Paralela 15 Invocações assíncronas de métodos Sem valor de retorno Implementada através de um padrão comando, onde o comando é executado em paralelo com o cliente. Os parâmetros do comando são passados no seu construtor. Exemplo: escrita de dados em ficheiro em background – activada pelo cliente: public class FileWriter extends Thread { private String nm; private byte[] d; public FileWriter(String n, byte data[]) { nm = n; d = data; } public void run() { writeBytes(nm,d); } } // código do cliente (new FileWriter(“Pic”,rawPicture)).start(); Computação Paralela 16 Invocações assíncronas de métodos Síncrona diferida Utilizando o Método Thread.join() start() r = new Service().start(); .. // doWork(); r.join(); r.getResult(); Service Cliente tempo getResult() Futuros O futuro irá conter o resultado da operação e bloqueia o cliente caso seja requerido o valor antes de estar disponível. class Future extends Thread { private Task tk=null; Cliente public Future(Task tsk) { tk = tsk; start(); } public Task getResult() { join(); return(tk); } public void run() { Computação Paralela } Servidor Futuro Future(t) doTask() getResult() tk = doTask(); } // realiza a tarefa 17 Invocações assíncronas de métodos Chamadas de retorno public interface Client { public void opOK(Task); } class OPCallBack extends Thread { private Client cl=null; private Task tk=null; public OPCallBack(Task tsk, Client clk) { tk = tsk; cl = clk start(); } public run() { tk = doTask(tk); cl.opOK(tk); // callback } } Computação Paralela Servidor Cliente OPCallBack() opOK() 18 Invocações assíncronas de métodos Suportadas em .Net (C#) através de delegates public class BaseObject { [OneWay] public void writeBytes(string, int); } // delegate para uma função void xxx(string,int) delegate void writeBytesDelegate(string, int); static void Main(string[] args) { ob = new BaseObject(); // cria um delegate para ab.writeBytes writeBytesDelegate wbd = new writeBytesDelegate(ob.writeBytes); // inicia a invocação IAsyncResul as = wbd.BeginInvoke(“Pic”,rawPic,null,null); // EndInvoke() retorna imediatamente wbd.EndInvoke(as); } Computação Paralela 19 Especificação de Concorrência/Paralelismo • Exercícios Codificar e executar o programa exemplo dos dois contadores em paralelo. Desenvolver um programa que implemente um relógio, com uma precisão de segundos e que execute em simultâneo com o resto do programa. Utilize o seguinte método: void sleep(miliseconds) throws InterruptedException Computação Paralela 20