Linguagens Concorrentes Antonio Francisco do Prado [email protected] Concorrência Multiprogramação: usada por um sistema "timesharing". Um processador compartilhado por diversos processos; Multiprocessamento: vários processadores. Possibilita que múltiplos processos sejam executados em processadores distintos. Memória comum compartilhada para comunicação entre os processos. Processamento Distribuído: também requer processadores separados, mas cada um com sua memória. Processadores conectados via linhas de comunicação. Concorrência A concorrência é naturalmente dividida em nível de: • instrução (executando duas ou mais instruções de máquina simultaneamente); • comando (executando dois ou mais comandos simultaneamente); e • unidade (executando dois ou mais programas simultaneamente). Os métodos concorrentes aumentam a flexibilidade de programação e foram criados originalmente para serem usados em problemas particulares dos em sistemas operacionais. Concorrência Concorrência relaciona-se com fluxo de controle de um programa. Tem-se mais de um fluxo de controle ativo. É diferente da execução seqüencial de programas, onde se tem apenas um fluxo de controle, ou seja, em um determinado momento, existe uma única instrução candidata à execução. Unidades concorrentes podem ser executadas em: • Um único processador ; • Vários processadores que compartilham uma memória; • Vários processadores independentes, sem compartilhamento de memória. Concorrência • Reduz o tempo total de processamento através de execução concorrente de diversas unidades; • Aumenta a confiabilidade para aplicações críticas, onde não se torna confiável a execução em um único processador; • Modela soluções que exploram a capacidade de máquinas com múltiplos processadores; • Implementa aplicações distribuídas. Conceitos básicos Seção crítica Quando processos concorrentes interagem com variáveis compartilhadas, a integridade destas variáveis pode ser violada se o acesso não for coordenado. Uma seção crítica é um segmento de código de um processo que acessa um recurso compartilhado. Deadlock É uma situação onde um processo ou um conjunto de processos estão bloqueados, a espera de um evento que nunca irá acontecer. Conceitos básicos Deadlock •Um deadlock é caracterizado por uma espera circular •Exemplo: o processo P1 está de posse do recurso r1 , e precisa do recurso r2; o processo P2 está de posse de r2 e precisa de r1; Nesse caso, nenhum dos processos pode prosseguir, pois ambos dependem de recursos que não serão liberados. P1 P2 r1 r2 Mecanismos de Sincronização Semáforos O conceito de semáforos consiste na colocação de proteções (guardas) no código que controlam o acesso a uma estrutura de dados. Em geral, a estrutura é uma fila, funcionando em regime FiFo(First in First out). A implementação do semáforo deve garantir que, uma vez que um processo inicie uma operação sobre um semáforo, nenhum outro processo terá acesso até que a operação conclua. Conceitos básicos Tarefa Uma tarefa é uma unidade de um programa que pode estar em execução concorrente com outras unidades do mesmo programa . Uma tarefa pode comunicar-se com outras tarefas através variáveis não-locais compartilhadas, mensagens ou de parâmetros. As tarefas disjuntas ocorrem, se uma tarefa não se comunicar ou não afetar a execução de qualquer outra tarefa. Devem de alguma forma se comunicar para que haja sincronização em suas execuções, no compartilhamento de dados. Conceitos básicos Tarefa tarefa1 tarefa2 Unidade concorrente Tarefa n Conceitos básicos Sincronização de tarefas Sincronização é um mecanismo que controla a ordem de execução das tarefas. Cooperação A cooperação entre processos revela-se quando um processo aguarda que outro processo realize alguma tarefa, para prosseguir sua execução. Assim a cooperação entre as tarefas A e B ocorre, quando B precisa aguardar que A conclua alguma atividade específica antes de prosseguir sua execução. Conceitos básicos Competição Ocorre quando ambas tarefas requerem algum recurso que não pode ser usado simultaneamente. Assim, se a tarefa A precisa acessar um dado compartilhado x que já esta sendo acessado pela tarefa B, a tarefa A precisa aguardar que B conclua seu acesso a x. Conceitos básicos Competição Tarefa T1 Unidade Concorrente Tarefa T2 Enquanto T1 estiver acessando, T2 tem que esperar Conceitos básicos Exclusão mútua A Exclusão Mútua ou, simplesmente, Mutex, é um caso particular competição por recurso, onde apenas se pode permitir o acesso individual ao recurso(regiões críticas).Os primeiros mecanismos da exclusão mútua faziam com que os processos testassem continuamente o valor de uma variável que guarda o estado do recurso, até sua liberação, podendo causar um Deadlock. Jantar dos filósofos •Os filosofos tentam comer e para isso dependem do recurso (palito). Para comer os filósofos precisam de dois palitos. Caso um filosofo não esteja comendo, pode estar pensando ou dormindo. Conceitos básicos Para que a competição por um recurso decorra sem qualquer problema são, normalmente, usados semáforos que permitem, ou não, o acesso de um ou mais processos à região crítica. Outros mecanismo de sincronização : • Monitores; e •Passagem de mensagem(rendezvous). Comportamento da comunicação entre tarefas: • Síncrono • Assíncrono Mecanismos de Sincronização Monitores Os monitores podem ser utilizados como uma solução em ambiente concorrente transformando as estruturas de dados compartilhados em Tipos Abstratos de Dados, que agrupam as estruturas de dados com suas operações, e ocultam suas representações. Os monitores implementam a exclusão mútua, onde somente um processo pode estar ativo dentro do monitor em um instante de tempo. Mecanismos de Sincronização Monitores (continuação) Quando um processo chama um método de um monitor, as primeiras instruções do método verificam se algum outro processo está ativo dentro dele. Se isto for verdade, o processo que chamou o método do monitor será suspenso até que o outro processo deixe o monitor. Se não houver nenhum processo ativo dentro do monitor, o processo poderá entrar e executar o método chamado. Mecanismos de Sincronização Monitores Processos aguardando entrada Mecanismos de Sincronização Passagem de mensagem A construção de monitores não moldam a sincronização em sistemas distribuídos, onde seria necessário a sincronização de unidades, na qual cada processador teria sua própria memória, em vez de uma única memória compartilhada. Para sincronizar os processos independentes é comum a utilização de monitores. Contudo, ao utilizarmos sistemas sem memória comum e com mais de um processador, a implementação dos monitores se torna inviável, porque não existe nenhum meio físico central. Surge assim uma técnica de encontros para tratar estes casos, que se faz através de mensagens. Mecanismos de Sincronização rendezvous Uma tarefa pode ser projetada de modo a poder suspender sua execução em certo ponto, porque está ociosa ou porque precisa de informações de outra unidade antes que possa prosseguir. Se uma tarefa A quer enviar uma mensagem para a tarefa B, e se esta estiver disposta a receber, a mensagem poderá ser transmitida. Essa transmissão é chamada rendezvous. Mecanismos de Sincronização Passagem de mensagem (Rendezvous) Tarefa 1 Tarefa 2 Requisição Processo Bloqueado Confirmação Resposta Confirmação Processo Contínuo Processo Contínuo Linguagens Concorrentes Java (Multilinhas) Multilinhas e Sincronização Multitarefas x Multilinhas Multitarefas - estão em espaço de endereçamento distinto e devem ser vistos como programas diferentes no mesmo sistema. Multilinhas - compartilham o mesmo espaço de endereçamento e dividem cooperativamente o mesmo processo. O modelo de Linhas de Execução de Java Java usa multilinhas de execução para permitir que todo o ambiente Java seja assíncrono. Não há um laço principal em um programa Java. Cada linha tem sua execução independente. Uma linha bloqueada não impede a execução das demais linhas. Sincronização A sincronização de recursos requeridos pelas linhas, executadas de forma assíncrona, é obtida pelo mecanismo Monitor. Em Java, não há uma classe monitor. Cada objeto tem seu próprio monitor, com seus métodos sincronizados. Quando uma linha está executando um método sincronizado, nenhuma outra linha pode executar este método. Thread Para criar programas concorrentes em Java reutiliza-se a classe Thread. A classe Thread encapsula todos os controles das linhas de execução. Um objeto Thread é o procurador de uma linha em execução. Quando um programa Java é iniciado já existe uma linha sendo executada. O programa principal de java é uma linha em execução. class ThreadCorrente { public static void main(String args[ ]){ Thread t = Thread.currentThread( ); t.setName("Minha Linha"); System.out.println("Linha corrente: " + t); try{ for (int n = 5; n > 0; n --) { System.out.println ( " " + n); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("interrompida"); } //fim do main } Resultado da execução Linha corrente: Thread [ Minha Linha,5,main ] 5 4 3 2 1 } Java – Concorrência Classe Thread notify notifyAll criado start Acorda pronto run resume yield executando wait esperando sleep adormecido suspend Completo (destroy) morto bloqueado Threads Java Principais métodos sleep: passa como parâmetro um número inteiro de milissegundos que a thread deve permanecer interrompida; suspend: interrompe temporariamente a thread, que pode ser reiniciada posteriormente; resume: reinicia a thread; yield: passa o controle para outra thread; syncronized: faz com que um recurso seja acessado atomicamente; notify: libera um recurso sincronizado para a próxima thread; notifyAll: libera um recurso sincronizado para todas as threads; e wait: aguarda pela liberação de um recurso sincronizado. Java – Concorrência A sincronização de competição em Java é obtida especificando-se os métodos sincronizados que acessam dados compartilhados. A execução destes métodos deve ser concluída para que outra thread execute-os novamente. Cada método sincronizado coloca um bloqueio no objeto, que impede que outros métodos sejam executados sobre este objeto. Usa o modificador synchronized na definição do método. A entrada em um monitor de objetos, é feita pela chamada de um método marcado com synchronized. synchronized void metodo() { Sincronização <HTML> <HEAD> <TITLE>Autogenerated HTML</TITLE> </HEAD> <BODY> <APPLET CODE="Applet1.class" WIDTH=426 HEIGHT=266></APPLET> </BODY> </HTML> roda.html Sincronização import java.awt.*; class Chamado{ synchronized void Chama(String msg) { Applet1.ShowMessage(msg); //try {Thread.sleep(1000);} try { Thread.sleep((int)Math.random()*1000); } catch(Exception e){ } Applet1.ShowMessage(msg); } } class Chamador implements Runnable { String msg; Chamado alvo; public Chamador(Chamado c, String s){ alvo = c; msg = s; new Thread(this).start(); } public void run(){ alvo.Chama(msg); } } import java.applet.*; Sincronização public class Applet1 extends Applet { public void init() { setLayout(null); setSize(426,266); button1 = new java.awt.Button(); button1.setLabel("Executar!"); button1.setBounds(324,72,66,94); button1.setBackground(new Color(12632256)); add(button1); list1 = new java.awt.List(4); add(list1); list1.setBounds(12,60,276,140); Acoes aAcoes = new Acoes(); button1.addMouseListener(aAcoes); } java.awt.Button button1; static java.awt.List list1; class Acoes extends java.awt.event.MouseAdapter { public void mouseClicked(java.awt.event.MouseEvent event) { Object object = event.getSource(); if (object == button1) executarThread(event); } } Sincronização void executarThread(java.awt.event.MouseEvent event) { Chamado alvo = new Chamado(); Thread corrente=Thread.currentThread(); ShowMessage(String.valueOf(corrente)); new Chamador(alvo,"Ola"); new Chamador(alvo,"Pessoal"); new Chamador(alvo,"Sincronizado"); ShowMessage("Fim criação chamador"); } static void ShowMessage(String s) { list1.addItem(s); } }// fim da classe Applet1 Java – Concorrência A sincronização de cooperação em Java é obtida com os métodos wait e notify definidos em na classe Object. O método wait é colocado em um laço que testa a condição de acesso a uma região crítica. Se a condição for falsa, a thread é colocada em uma fila de espera. O método notify é chamado para notificar uma thread, que a região crítica está liberada. wait e notify somente podem ser chamados de dentro de um método sincronizado. Usam o bloqueio do objeto realizado pelo syncronized. Produtor e Consumidor <HTML> <HEAD> <TITLE>Relogio</TITLE> procon.html </HEAD> <BODY> <P><APPLET CODE="Applet1.class" WIDTH=“426" HEIGHT=“266" ALIGN="BOTTOM"> </APPLET> </BODY> </HTML> Java – Produtor e Consumidor class Controle{ static int n; boolean flag1 = false; synchronized int get() { while(!flag1) //if(!flag1) try { wait(); } catch(InterruptedException e){ } Applet1.ShowMessage("Lendo: "+ String.valueOf(n)); flag1 = false; notify(); return n; } synchronized void put(int n) { while(flag1) //if(flag1) try { wait(); }catch(InterruptedException e){ } this.n = n; flag1 = true; Applet1.ShowMessage("Colocando: "+ n); notify(); } } class Produtor implements Runnable{ Controle c1; Produtor (Controle c1) { this.c1=c1; new Thread(this, "Produtor").start(); } public void run() { int i = 0; while(Controle.n < 10) { //while(true) c1.put(i++); } } } class Consumidor implements Runnable{ Controle c1; Consumidor(Controle c1) { this.c1=c1; new Thread(this,"Consumidor").start(); } public void run(){ while(Controle.n < 10) { //while(true) c1.get(); } } } import java.awt.*; import java.applet.*; public class Applet1 extends Applet { public void init() { setLayout(null); setSize(426,266); button1 = new java.awt.Button(); button1.setLabel("button"); button1.setBounds(264,96,116,60); button1.setBackground(new Color(12632256)); add(button1); list1 = new java.awt.List(4); add(list1); list1.setBounds(12,36,222,194); SymMouse aSymMouse = new SymMouse(); button1.addMouseListener(aSymMouse); } java.awt.Button button1; static java.awt.List list1; class SymMouse extends java.awt.event.MouseAdapter { public void mouseClicked(java.awt.event.MouseEvent event) { Object object = event.getSource(); if (object == button1) button1_MouseClicked(event); } void button1_MouseClicked(java.awt.event.MouseEvent event) { Controle c1 = new Controle(); new Produtor(c1); new Consumidor(c1); } } static void ShowMessage(String s) { list1.addItem(s); } } Jantar dos filósofos public class Palitos { private boolean[] catched = new boolean[5]; //vetor de Palitos - True(em uso) False(liberado) public Palitos( ) { } public synchronized void pick2(Filosofos f){ //método para pegar os 2 Palitos (sincronizado) Int key = f.getKey( ); //identifica o filósofo que quer pegar os Palitos while ( catched[key] || catched[((key +1)%5)] ){ //Espera até que seu Palito ou //o do seu vizinho à direita estiver em uso f.setStatus(2); //passa para o estado FAMINTO try{ wait( ); } //espera catch(Exception e){} } catched[key] = true; catched[((key +1)%5)] = true; f.setStatus(1); //passa para o estado COMENDO }//fim pick2 public synchronized void put2(Filosofos f){ // método para liberar os 2 Palitos usados int key; key = f.getKey( ); //identifica o filósofo que vai liberar os Palitos catched[key] = false; //libera o seu Palito //e o de seu vizinho à direita int aux = (key+1)%5; catched[aux] = false; try{ notifyAll( ); } //notifica que liberou os Palitos catch(Exception e){ } }//fim put2 }//fim da classe Palitos public class Jantar { private Filosofos f0,f1,f2,f3,f4; public Palitos palito; public Jantar() { palito = new Palitos(); // cria objeto palitos f0 = new Filosofos(0,this); //cria threads filósofos f1 = new Filosofos(1,this); f2 = new Filosofos(2,this); f3 = new Filosofos(3,this); f4 = new Filosofos(4,this); f0.start(); f1.start(); f2.start(); f3.start(); f4.start(); } public static void main(String[] args) { new Jantar(); } public void SetInfo(int key, int status){ if (key == 0) { if (status ==0) { System.out.println("0 else if (status ==1) { System.out.println("0 else if (status ==2) { System.out.println("0 else if (key == 1) { if (status ==0) { System.out.println("1 else if (status ==1) { System.out.println("1 else if (status ==2) { System.out.println("1 else if (key == 2) { if (status ==0) { System.out.println("2 else if (status ==1) { System.out.println("2 else if (status ==2) { System.out.println("2 else if (key == 3) { if (status ==0) { System.out.println("3 else if (status ==1) { System.out.println("3 else if (status ==2) { System.out.println("3 else if (key == 4) { if (status ==0) { System.out.println("4 else if (status ==1) { System.out.println("4 else if (status ==2) { System.out.println("4 } } } - Pensando"); } - Comendo"); } - Faminto"); } } - Pensando"); } - Comendo"); } - Faminto"); } } - Pensando"); } - Comendo"); } - Faminto"); } } - Pensando"); } - Comendo"); } - Faminto"); } } - Pensando"); } - Comendo"); } - Faminto"); } public class Filosofos extends Thread{ //cada filósofo é visto como um processo private int key; // identifica o filósofo private int status; // 0 = pensa , 1 = come , 2 = faminto private Jantar j; // objeto jantar public Filosofos(int key,Jantar j) { this.key = key; this.j = j; } public int getKey(){ // pega identificador do filósofo return key; } public void setStatus(int status = i; switch ( i ){ case 0 : j.SetInfo(key, case 1 : j.SetInfo(key, case 2 : j.SetInfo(key, } i){ // seta status do filósofo 0); break; 1); break; 2); break; } private void pensando(){ // no estado pensando bloqueia //por um certo tempo 2000ms) try{Thread.sleep(2000);} catch(Exception e){} } private void comendo(){ // no estado comendo //bloqueia por um certo tempo (2500 ms) try{Thread.sleep(2500);} catch(Exception e){} } public void run(){ while(true){ // roda indefinidamente setStatus(0); // filósofo pensando pensando(); // pensa - bloqueia por certo tempo j.palito.pick2(this); // filósofo pega os Palitos comendo(); // come - bloqueia por certo tempo j.palito.put2(this); // libera os Palitos } } } }//fim da classe Filosofos 3 Threads relogio <HTML> <HEAD> <TITLE>Relogio</TITLE> relogio.html </HEAD> <BODY> <P><APPLET CODE="Applet1.class" WIDTH="500" HEIGHT="361" ALIGN="BOTTOM"> </APPLET> </BODY> </HTML> import java.awt.*; class relogio extends Canvas implements Runnable { private Thread UmaThread; // declara a thread private Polygon UmPoligono; private int polyX[] = new int[9], //coordenadas X polyY[] = new int[9], //coordenadas Y posicao, //posicao da linha delay = 100; // sleep em milesegundos public relogio() { resize(130, 130); DefinePoligono(); UmPoligono = new Polygon(polyX, polyY, 9); posicao = 0; UmaThread = new Thread(this); / cria a thread UmaThread.start(); //inicia a thread } public relogio(int _delay) // construtor da classe relogio { this(); if(_delay < 50) delay = 50; else if(_delay > 300) delay = 300; else delay = _delay; } public void reset() {posicao = 0;} public void resume() { UmaThread.resume(); } // resume( ) public void suspende() { UmaThread.suspend(); } // suspend ( ) public void destroy() { this.UmaThread = null; } // destroy ( ) public void run() // run do objeto Runnable, passado para a Thread { while (true) { repaint(); // chama o paint passando uma caneta gráfica try{ Thread.sleep(delay); } // sleep ( ) catch(InterruptedException e) { this.suspende(); } avancar(); } } //Desenha a linha do centro até a posição public void paint(Graphics g) { // chamado pelo repaint() g.drawPolygon(UmPoligono); g.drawLine(65, 65, polyX[posicao], polyY[posicao]); } private void avancar() { if(posicao < 6) posicao++; else posicao = 0; } //vetor com as coordenadas X e Y polyY[0] = 1; private void DefinePoligono() polyY[1] = 1; { polyY[2] = 37; polyX[0] = 37; polyY[3] = 97; polyX[1] = 97; polyY[4] = 129; polyX[2] = 129; polyY[5] = 129; polyX[3] = 129; polyY[6] = 97; polyX[4] = 97; polyY[7] = 37; polyX[5] = 37; polyY[8] = 1; polyX[6] = 1; } // fim DefinePoligono polyX[7] = 1; }// fim da classe relogio polyX[8] = 37; import java.awt.*; import java.applet.*; public class Applet1 extends Applet { void suspende3_Clicked(java.awt.event.ActionEvent event) { pa3.suspende(); } void resume3_Clicked(java.awt.event.ActionEvent event) { pa3.resume(); } void suspende2_Clicked(java.awt.event.ActionEvent event) { pa2.suspende(); } void resume2_Clicked(java.awt.event.ActionEvent event) { pa2.resume(); } void suspende1_Clicked(java.awt.event.ActionEvent event) { pa1.suspende(); } void resume1_Clicked(java.awt.event.ActionEvent event) { pa1.resume(); } void resetButton_Clicked(java.awt.event.ActionEvent event) { suspendeButton_Clicked(null); pa1.reset(); pa2.reset(); pa3.reset(); pa1.repaint(); pa2.repaint(); pa3.repaint(); } void suspendeButton_Clicked(java.awt.event.ActionEvent event) { pa1.suspende(); pa2.suspende(); pa3.suspende(); } void resumeButton_Clicked(java.awt.event.ActionEvent event) { pa1.resume(); pa2.resume(); pa3.resume(); } public void init() { super.init(); setLayout(new BorderLayout(0,0)); setSize(507,300); mainButtonPanel = new java.awt.Panel(); mainButtonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,20,10)); mainButtonPanel.setBounds(0,257,507,43); add("South", mainButtonPanel); resumeButton = new java.awt.Button(); resumeButton.setLabel("Resume todos"); resumeButton.setBounds(155,10,55,23); mainButtonPanel.add(resumeButton); suspendeButton = new java.awt.Button(); suspendeButton.setLabel("Suspende Todos"); suspendeButton.setBounds(230,10,55,23); mainButtonPanel.add(suspendeButton); resetButton = new java.awt.Button(); resetButton.setLabel("Resseta"); resetButton.setBounds(305,10,47,23); mainButtonPanel.add(resetButton); animationArea = new java.awt.Panel(); animationArea.setLayout(new GridLayout(1,3,0,0)); animationArea.setBounds(0,0,507,257); add("Center", animationArea); aPanel1 = new java.awt.Panel(); aPanel1.setLayout(new BorderLayout(0,0)); aPanel1.setBounds(0,0,507,257); aPanel1.setBackground(new Color(16711680)); animationArea.add(aPanel1); ap1 = new java.awt.Panel(); ap1.setLayout(new FlowLayout(FlowLayout.CENTER,5,25)); ap1.setBounds(0,0,169,224); aPanel1.add("Center", ap1); subP1 = new java.awt.Panel(); subP1.setLayout(new FlowLayout(FlowLayout.CENTER,5,5)); subP1.setBounds(0,224,169,33); aPanel1.add("South", subP1); resume1 = new java.awt.Button(); resume1.setLabel("Resume"); resume1.setBounds(43,5,39,23); subP1.add(resume1); suspende1 = new java.awt.Button(); suspende1.setLabel("Suspende"); suspende1.setBounds(87,5,39,23); subP1.add(suspende1); aPanel2 = new java.awt.Panel(); aPanel2.setLayout(new BorderLayout(0,0)); aPanel2.setBounds(169,0,169,257); animationArea.add(aPanel2); ap2 = new java.awt.Panel(); ap2.setLayout(new FlowLayout(FlowLayout.CENTER,5,25)); ap2.setBounds(0,0,169,224); aPanel2.add("Center", ap2); subP2 = new java.awt.Panel(); subP2.setLayout(new FlowLayout(FlowLayout.CENTER,5,5)); subP2.setBounds(0,224,169,33); aPanel2.add("South", subP2); resume2 = new java.awt.Button(); resume2.setLabel("Resume"); resume2.setBounds(43,5,39,23); subP2.add(resume2); suspende2 = new java.awt.Button(); suspende2.setLabel("Suspende"); suspende2.setBounds(87,5,39,23); subP2.add(suspende2); aPanel3 = new java.awt.Panel(); aPanel3.setLayout(new BorderLayout(0,0)); aPanel3.setBounds(338,0,169,257); aPanel3.setBackground(new Color(255)); animationArea.add(aPanel3); ap3 = new java.awt.Panel(); ap3.setLayout(new FlowLayout(FlowLayout.CENTER,5,25)); ap3.setBounds(0,0,169,224); aPanel3.add("Center", ap3); subP3 = new java.awt.Panel(); subP3.setLayout(new FlowLayout(FlowLayout.CENTER,5,5)); subP3.setBounds(0,224,169,10); aPanel3.add("South", subP3); resume3 = new java.awt.Button(); resume3.setLabel("Resume"); resume3.setBounds(43,5,39,23); subP3.add(resume3); suspende3 = new java.awt.Button(); suspende3.setLabel("Suspende"); suspende3.setBounds(87,5,39,23); subP3.add(suspende3); ap1.add(pa1); // adição da Thread pa1 ap2.add(pa2); // adição da Thread pa2 ap3.add(pa3); // adição da Thread pa3 Acoes lAcoes = new Acoes(); resumeButton.addActionListener(lAcoes); suspendeButton.addActionListener(lAcoes); resetButton.addActionListener(lAcoes); resume1.addActionListener(lAcoes); suspende1.addActionListener(lAcoes); resume2.addActionListener(lAcoes); suspende2.addActionListener(lAcoes); resume3.addActionListener(lAcoes); suspende3.addActionListener(lAcoes); } java.awt.Panel mainButtonPanel; java.awt.Button resumeButton; java.awt.Button suspendeButton; java.awt.Button resetButton; java.awt.Panel animationArea; java.awt.Panel aPanel1; java.awt.Panel ap1; java.awt.Panel subP1; java.awt.Button resume1; java.awt.Button suspende1; java.awt.Panel aPanel2; java.awt.Panel ap2; java.awt.Panel subP2; java.awt.Button resume2; java.awt.Button suspende2; java.awt.Panel aPanel3; java.awt.Panel ap3; java.awt.Panel subP3; java.awt.Button resume3; java.awt.Button suspende3; relogio pa1 = new relogio(100); // criação da Thread pa1 relogio pa2 = new relogio(120); // criação da Thread pa2 relogio pa3 = new relogio(150); // criação da Thread pa3 class Acoes implements java.awt.event.ActionListener { public void actionPerformed(java.awt.event.ActionEvent event) { Object object = event.getSource(); if (object == resumeButton) resumeButton_Clicked(event); else if (object == suspendeButton) suspendeButton_Clicked(event); else if (object == resetButton) resetButton_Clicked(event); else if (object == resume1) resume1_Clicked(event); else if (object == suspende1) suspende1_Clicked(event); else if (object == resume2) resume2_Clicked(event); else if (object == suspende2) suspende2_Clicked(event); else if (object == resume3) resume3_Clicked(event); else if (object == suspende3) suspende3_Clicked(event); } } // fim da classe Ações } // fim da classe Applet1 Threads - Prioridades Prioridades de Linha Quando uma linha de prioridade baixa está sendo executa e uma linha de prioridade mais alta torna-se ativa, ou sai de uma espera de E/S, ela é executada imediatamente. class Clicador implements Runnable { int clique = 0; private Thread t; private boolean rodando = true; public Clicador (int p) { t = new Thread(this); t.setPriority(p); } public void run( ) { while (rodando) { clique++; } } public void stop( ) { rodando = false; } public void start( ) { t.start( ); } } Threads - Prioridades class PriAltaBaixa { public static void main (String args[ ]) { Thread.currentThread( ).setPriority(Thread.MAX_PRIORITY); Clicador alta = new Clicador( Thread.NORM_PRIORITY + 2); Clicador baixa = new Clicador( Thread.NORM_PRIORITY - 2); baixa.start( ); alta.start( ); try { O resultado da execução Thread.sleep(10000); } deste programa é: catch (Exception e) { }; c:\> java PriAltaBaixa baixa.stop( ); 5785717 vs. 465881948 alta.stop( ); System.out.println(baixa.clique + " vs." + alta.clique); } } Bloqueio Mútuo class A { synchronized void foo(B b) { class B { String name = synchronized void bar(A a) { Thread.currentThread().getName(); String name = System.out.println(name + " Thread.currentThread().getName(); entrou em A.foo"); System.out.println(name + " try { Thread.sleep(1000);} catch entrou em B.bar"); (Exception e){ }; try { Thread.sleep(1000); } catch System.out.println(name + (Exception e) { }; " tentando chamarB.last()"); System.out.println(name + b.last(); "tentando chamarA.last()"); } a.last(); synchronized void last() { } System.out.println(" dentro de synchronized void last() { A.last"); System.out.println(" dentro de } B.last"); } } } Bloqueio Mútuo (continuação) class Deadlock implements Runnable { A a = new A( ); B b = new B( ); Deadlock() { Thread.currentThread( ).setName("MainThread"); new Thread(this).start( ); a.foo(b); //consegue bloqueio a nesta linha. System.out.println("de novo na linha principal"); } public void run( ) { Thread.currentThread( ).setName("RacingThread"); b.bar(a); //consegue bloqueio em b em outra linha. System.out.println("de novo em outra linha"); } public static void main(String args[ ]) { new Deadlock( ); } } // fim da classe Deadlock Bloqueio Mútuo (continuação) O resultado deste programa é: MainThread entrou em A.foo RacingThread entrou em B.bar MainThread tentando chamar B.last( ) RacingThread tentando chamar A.last( ) Java em Rede Sockets e Threads import java.io.*; import java.net.*; public class Envia extends Thread { ObjectOutputStream os; Socket s; public Envia() { super(); try {//s=new Socket(InetAddress.getLocalHost()); // s = new Socket("200.18.99.130",12345); s = new Socket(“localhost",12345); os = new ObjectOutputStream(s.getOutputStream()); } catch(Exception e) {} } public static void main(String args[]) { (new Envia()).start(); } public void run( ) { while (true) { try { os.writeObject(new Dados(1,"Testando dados")); os.flush(); } catch (Exception e) {} } } } import java.net.*; import java.io.*; public class trata extends Thread { ObjectInputStream is; Socket s; public trata (Socket s) { this.s = s; try { is = new ObjectInputStream(s.getInputStream()); } catch (Exception e) {} } public void run( ) { while (true) { try { Dados d = (Dados) is.readObject(); System.out.println(d.i); System.out.println(d.a); (new Thread(d)).start(); }catch(Exception e) {} } } } import java.io.*; import java.net.*; public class Recebe extends Thread { ServerSocket s; public Recebe() { super(); try { s = new ServerSocket(12345); }catch(Exception e) {} } public static void main(String args[]) { (new Recebe()).start(); } public void run( ) { try { (new trata(s.accept())).start(); }catch(Exception e) {} } } public class Dados extends Object implements java.io.Serializable, Runnable { public int i; public String a; public Dados (int i, String a) { this.i = i; this.a = a; } public void run () { System.out.println(“Funcionou !!!!!!"); } } } Para executar: > Java Recebe Em outra janela DOS: > Java Envia Explorando o java java.util.concurrent Operações Atômicas Tipos: Integer, Long, Boolean, IntegerArray, e LongArray. Acesso sincronizado pelas threads, através de operações atômicas. Por exemplo: private AtomicLong val1 val1.incrementAndGet() val1.get() Pacote: import java.util.concurrent.atomic.*; Pacote java.util.concurrent.atomic.AtomicReference; public class AtomicReference<V> Serializable implements public AtomicReference() public AtomicReference(V initialValue) public final V get() public final void set(V newValue) public final boolean compareAndSet(V expect, V update) public final V getAndSet(V newValue) package atomico; import java.util.concurrent.atomic.AtomicReference; public class Atomica extends AtomicReference<Integer> { public Atomica() { } public static void main(String args[]) { Atomica a = new Atomica(); a.set(Integer.MIN_VALUE); System.out.println("Teste1: " + a.get()); System.out.println("Teste2: " + a.getAndSet(22)); System.out.println("Teste1: " + a.get()); } } Saída: Teste1: -2147483648 Teste2: -2147483648 Teste1: 22 Argumentos variáveis menorNumero(1, 3, 2, 7); menorNumero(3, 6, 1, 8, 3, 9, 0); public static Integer menorNumero (Integer a, Integer b) public static Integer menorNumero (Integer... numeros) Tipos Genéricos Usa padrão formatado de uma categoria sintática em Tempo de Compilação; Observações: List<String> NÃO é Subtipo de List<Object> List<?> NÃO é o Mesmo que List<Object> List<String> É Subtipo de List<? extends Object> List<Integer> É Subtipo de List<? extends Number> List<?> Lista de Qualquer Coisa extends (Leia, Que Seja Subtipo) List<? extends Number> Lista de Qualquer Coisa que Seja Subtipo de Number super (Leia, Que Seja Supertipo) List<? super ArrayList> Lista de Qualquer Coisa que Seja Supertipo de ArrayList public interface Callable<V> A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call. The Callable interface is similar to Runnable, in that both are designed for classes whose instances are potentially executed by another thread. A Runnable, however, does not return a result and cannot throw a checked exception. public interface Executor An object that executes submitted Runnable tasks. This interface provides a way of decoupling task submission from the mechanics of how each task will be run, including details of thread use, scheduling, etc. An Executor is normally used instead of explicitly creating threads. For example, rather than invoking new Thread(new(RunnableTask())).start() ; for each of a set of tasks, you might use: Executor executor = anExecutor; executor.execute(new RunnableTask1()); executor.execute(new RunnableTask2()); ... public interface ExecutorService extends Executor An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks. An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods are provided for shutting down an ExecutorService. The ExecutorService.shutdown method will allow previously submitted tasks to execute before terminating, while the ExecutorService.shutdownNow method prevents waiting tasks from starting and attempts to stop currently executing tasks. Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused ExecutorService should be shut down to allow reclamation of its resources. public interface ExecutorService extends Executor Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.) The Executors class provides factory methods for the executor services provided in this package. Here is a sketch of a network service in which threads in a thread pool service incoming requests. It uses the preconfigured Executors.newFixedThreadPool factory method class NetworkService implements Runnable { private final ServerSocket serverSocket; private final ExecutorService pool; public NetworkService(int port, int poolSize) throws IOException { serverSocket = new ServerSocket(port); pool = Executors.newFixedThreadPool(poolSize); } public void run() { // run the service try { for (;;) { pool.execute(new Handler(serverSocket.accept())); } } catch (IOException ex) { pool.shutdown(); } }} class Handler implements Runnable { private final Socket socket; Handler(Socket socket) { this.socket = socket; } public void run() { // read and service request on socket } } The following method shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and then calling shutdownNow, if necessary, to cancel any lingering tasks. void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); }} public interface Future<V> Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. Cancellation is performed by the cancel method. Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled. If you would like to use a Future for the sake of cancellability but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task. Parâmetros: V - The result type returned by this Future's get method <T> Future<T> submit(Callable<T> task) void shutdown() List<Runnable> shutdownNow() boolean awaitTermination (long timeout, TimeUnit unit) throws InterruptedException interface ArchiveSearcher { String search(String target); } class App { ExecutorService executor = ... ArchiveSearcher searcher = ... void showSearch(final String target) throws InterruptedException { Future<String> future = executor.submit (new Callable<String>() { public String call() { return searcher.search( target); }}); displayOtherThings(); // do other things while searching try { displayText(future.get()); // use future } catch (ExecutionException ex) { cleanup(); return; } } } The FutureTask class is an implementation of Future that implements Runnable, and so may be executed by an Executor. For example, the above construction with submit could be replaced by: FutureTask<String> future = new FutureTask<String>(new Callable<String>() { public String call() { return searcher.search(target); }} ); executor.execute(future); Tarefas Agendadas public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) public ScheduledFuture<?> scheduleWithFixedDelay (Runnable command, long initialDelay, long delay, TimeUnit unit) public interface BlockingQueue<E> extends Queue<E> A Queue that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element. A BlockingQueue does not accept null elements. Exemplo Produtor e Consumidor class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while (true) { queue.put(produce()); } } catch (InterruptedException ex) { ... handle ...} } Object produce() { ... } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while (true) { consume(queue.take()); } } catch (InterruptedException ex) { ... handle ...} } void consume(Object x) { ... } } class Setup { void main() { BlockingQueue q = new SomeQueueImplementation(); Producer p = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } } public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable A bounded blocking queue backed by an array. This queue orders elements FIFO (first-in-first-out). The head of the queue is that element that has been on the queue the longest time. The tail of the queue is that element that has been on the queue the shortest time. New elements are inserted at the tail of the queue, and the queue retrieval operations obtain elements at the head of the queue. public class CountDownLatch extends Object A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the CountDownLatch.countDown method, after which all waiting threads are released and any subsequent invocations of await return immediately. Meta Classes package geral.reflex; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class TesteReflection { ... public static void main(String[] args) { Field[] campos = TesteReflection.class.getDeclaredFields(); for (Field campoAtual : campos) { System.out.println(campoAtual.getName() + ": " + campoAtual.getType().getName()); } } Constructor<TesteReflection>[] constr = (Constructor<TesteReflection>[]) TesteReflection.class.getDeclaredConstructors(); System.out.println("Construtores de TesteReflection:"); for (Constructor<TesteReflection> constrAtual : constr) { try { Class<?>[] params = constrAtual.getParameterTypes(); System.out.print("\t"); System.out.print(Modifier.toString(constrAtual.getModifiers())); System.out.print(" TesteReflection("); if (params.length > 0) { System.out.print(params[0].getName()); for (int i = 1; i < params.length; i++) { System.out.print(", "); System.out.print(params[i].getName()); } } System.out.println(")"); } catch (Exception e) { e.printStackTrace(); } } TesteReflection var = new TesteReflection("Primeiro Teste"); try { Field campo = TesteReflection.class.getDeclaredField("algo"); System.out.println("\nCampo: " + campo + " contendo: " + campo.get(var)); Method metodo = TesteReflection.class.getDeclaredMethod("getAlgo"); if (metodo != null) { System.out.println(metodo.getName()+ " retorna: "+ metodo.invoke(var)); } } catch (Exception e) { e.printStackTrace(); } } Outras Linguagens Concorrentes: Ada Modula Ada – Introdução Ada é uma linguagem de programação de alto nível e imperativa baseada em Pascal e criada através de um concurso realizado pelo Depto. de Defesa dos EUA. O nome Ada é uma homenagem a condessa de Lovelace, Augusta Ada Byron, filha de Lord Byron que trabalhou com Charles Babbage e é considerada como a primeira programadora de computadores da História. Ada – Características •Grande capacidade numérica tornando-a útil para uso acadêmico; •Foi projetada para detectar erros não apenas durante a compilação mas também em tempo de execução; •Foi feita para implementar programas rápidos e para ser usada em máquinas que usam computadores para fins militares; •É uma linguagem estruturada, imperativa e fortemente tipada; •Ada 95 suporta programação orientada ao objeto e permite interfaces com C/C++, FORTRAN e também com Java; Ada – Estruturas básicas Declarações de eventuais bibliotecas Procedure nome_do_programa is Declarações de possíveis variáveis Begin Corpo do programa End nome_do_programa; Exemplo: with Text_IO; use Text_IO; procedure alomundo is begin Put_Line("Alo Mundo!!!"); end alomundo; Ada – Estruturas básicas Declaração de bibliotecas With Ada.Text_IO; Declaração de Variáveis. Nome_variável : tipo_variável [:= valor]; Comentário Tudo o que estiver a direita de "--" é comentário no programa. Ada – Comandos IF if condição then seqüência de comandos elsif condicao2 then seqüência de comandos2 else outra seqüência de comandos end if; FOR for a in 1..10 loop sequencia de comandos end loop; Ada – Comandos While while a /=3 and b <=15 and c=3.0 loop seqüência de comandos end loop; Loop-laço loop seqüência de comandos end loop; Case case x is when 1 => executa alguma coisa when others => Put_Line("Oi"); end case; Ada – Concorrência A concorrência em Ada pode ser expressada através de tarefas (tasks). São entidades passivas que fornecem serviços de gerenciamento para dados compartilhados armazenados neles. Eles fornecem seus serviços, mas somente quando eles são solicitados. As tarefas Ada possuem diversos mecanismos que permitem a escolha entre solicitações concorrentes para acesso a seus recursos. As tarefas são declaradas em duas partes, uma de especificação e uma de corpo através das clausula entry e accept . Ada – Concorrência •As tarefas comunicam-se usando mecanismo de passagem de mensagem (rendezvous); •Quando um accept recebe uma mensagem que não está preparado para aceitar, a tarefa emissora deve ser suspensa até que a tarefa receptora esteja preparada para receber a mensagem •Accept trabalha com uma fila associada; Task body Tarefa is begin loop Accept entrada(parametros) do .................. end entrada; end loop; end tarefa; Ada – Concorrência Um outro exemplo mostra como mais de uma tarefa são tratadas: Task body tarefa is loop Fila select Seção crítica accept entrada_1 (parâmetros) do controlada ..... pelos comandos end entrada_1; Fila Accept e or select accept entrada_2 (parâmetros) do ..... end entrada_2; end select; O select examina as filas end loop; selecionando qual accept end tarefa; será executado primeiro Ada – Concorrência Pode ser feita também a sincronização de competição, onde a clausula accept pode ter uma proteção(guarda) anexada, na forma do comando when podendo retardar o mecanismo. when not cheio(buffer) => accept deposita(novo) do Um accept com um when pode ser aberto ou fechado. Se a expressão boolena da when for verdadeira, accept será aberto e estará sempre disponível para rendezvous, caso contrário será fechado e não poderá ter rendezvous. Ada – Concorrência Produtor/consumidor with Ada.Integer_text_IO,Ada.Text_IO; use Ada.Integer_Text_IO,Ada.Text_IO; -- Bibliotecas usadas -procedure Prod_Cons is -- Procedimento principal ---Declaração da tarefa buffer e seus métodos-Define o nome do task buffer is entry deposita(ITEM : in INTEGER); método que será entry busca(ITEM : out INTEGER); usado na end buffer; concorrência --Estrutura corpo do buffer-task body buffer is tambuffer:constant INTEGER :=100; buf : array(1..tambuffer) of INTEGER; preenchido : INTEGER range 0..tambuffer := 0; prox_in,prox_out : INTEGER range 0..tambuffer := 1; ITEM : INTEGER; Ada – Concorrência begin loop select when preenchido < tambuffer => accept deposita(ITEM :in INTEGER) do o accept determina buf(prox_in) := ITEM; quem vai entrar para end deposita; prox_in := (prox_in mod tambuffer) + 1; acessar o recurso preenchido := preenchido + 1; seleciona qual or when preenchido > 0 => método será usado accept busca(ITEM : out INTEGER) do ITEM := buf(prox_out); end busca; prox_out := (prox_out mod tambuffer) + 1; preenchido := preenchido - 1; end select; end loop; end buffer; Ada – Concorrência task produtor; Declarações das tarefas que task consumidor; task body produtor is vão acessar os métodos do buffer novo_valor : INTEGER; begin loop buffer.deposita(novo_valor); put_line("Produzindo..."); Os métodos estão end loop; end produtor; sendo chamados task body consumidor is da task buffer, valor_armazenado : INTEGER; que é comum as begin loop outras tarefas buffer.busca(valor_armazenado); put_line("Consumindo..."); -- consome valor_armazenado -end loop; end consumidor; end Prod_Cons; Ada – Concorrência Objetos Protegidos •Oferece sincronização por competição que não envolve o mecanismo de rendezvous. •Podem ser acessados ou por sub-programas protegidos ou por entradas similares existentes em tarefa. •Esses objetos oferecem acesso mutuamente exclusivo de leitura e escrita aos dados e funções do objeto, que oferecem acesso concorrente. •As chamadas de entrada a um objeto protegido proporcionam comunicação síncrona com uma ou mais tarefas usando o mesmo objeto protegido Ada – Concorrência protected body buffer is accept deposita(ITEM :in INTEGER) do when preenchido < tambuffer is begin buf(prox_in):= ITEM; prox_in := (prox_in mod tambuffer) + 1; preenchido := preenchido + 1; end deposita; accept busca(ITEM : out INTEGER) when preenchido > 0 is begin ITEM := buf(prox_out); prox_out := (prox_out mod tambuffer) + 1; preenchido := preenchido - 1; end busca; end loop; end buffer; Ada – Concorrência Semáforos Nesse exemplo estão implementadas duas tarefas, que são controladas pelo semáforo with TEXT_IO, SEMAPHORES; use TEXT_IO, SEMAPHORES; procedure EXAMPLE is SCREEN : SEMAPHORE; task ONE; task body ONE is begin loop WAIT (SCREEN); PUT_LINE (“Tarefa 1"); SIGNAL (SCREEN); end loop; end ONE; task TWO; task body TWO is begin loop WAIT (SCREEN); PUT_LINE (“Tarefa 2"); SIGNAL (SCREEN); end loop; end TWO; begin INITIAL (SCREEN, 1); end EXAMPLE; Ada – Concorrência Tela do programa Ada+SQL Modula – Introdução •Criada em 1975 pelo professor Niklaus Wirth, criador da linguagem Pascal •linguagem segura, confiável e com muito mais recursos que o Pascal; Apresenta as seguintes características: Modula – Características •Linguagem fortemente tipada, com grande variedade de tipos e estruturas de controle; •Faz menos uso de blocos (begin...end), otimizando estruturas de controle como if e for; • Eliminou o label e goto; •Capacidade de criar programas utilizando multiprocessamento através de co-rotinas; •Case sensitive Modula Estruturas Básicas MODULE Nome_Programa; Declaração de bibliotecas; Declaração de variáveis; Begin Corpo do programa; End Nome_programa. Exemplo: MODULE Exemplo; FROM InOut IMPORT WriteString, WriteInt, WriteLn; VAR digito: INTEGER; BEGIN WriteString(“âlo mundo”); END Exemplo. (* Fim do Programa*) Modula Estruturas Básicas Declaração de bibliotecas FROM IO IMPORT WriteString ,WriteCard ,Writeln; Declaração de variáveis VAR Nome_variável : Tipo_da_variável; Comentário Tudo que estiver entre ( *....*) é comentário do programa. Modula – Comandos IF Exemplo: IF maior > menor THEN Verdade := maior ELSE HALT; END; Case CASE variável OF constante 1: comando 1; constante 2: comando 2; constante n: comando n; END; Modula – Comandos While WHILE condição DO comandos; END; Repeat REPEAT comandos; UNTIL condição; Loop LOOP Seqüência de Estruturas END Modula – Comandos For soma :=0; FOR i :=1 TO n BY 2 DO soma := soma + i * i END; With WITH designador DO SeqComandos END; Modula – Declarações Uma declaração de procedure deve ter: o nome da procedure; informação sobre os parâmetros da procedure(se existirem); o tipo de valor que a procedure retorna (se é uma função); declaração das entidades que pertencem à procedure; uma seqüência de estruturas para serem executadas quando a procedure é chamada. Sintaxe: procedure <identificador>; OU procedure <identificador> ( parâmetros ); Modula – Declarações Função São métodos que realizam cálculos e retornam um valor. Exemplo: PROCEDURE potencia (x:REAL; i:INTEGER):REAL; VAR z:REAL; BEGIN z:=1.0; WHILE i>0 DO IF ODD(i) THEN z:=z*x END; x:= x*x; i:=i DIV 2; END; RETURN z; END potencia; Modula – Módulos •Os módulos são características que distinguem o Modula do seu ancestral, o Pascal; • Todo programa em Modula é um módulo, ou, na maioria das vezes, é formados por um programa módulo (programa principal), e por um número qualquer de módulos de biblioteca; •Módulos locais, declarados dentro de outros módulos ou procedures; •Nem todas as entidades pertencem a um módulo assim como nem todas entidades declaradas em outros módulos estão disponíveis para este módulo; Modula – Concorrência •Pode-se definir um processo como sendo um programa em execução; •Definimos concorrência quando dois ou mais processos são executados simultaneamente sem que nenhum destes seja prejudicado ; •Em Modula implementa-se "concorrência" através das Co-rotinas. Modula – Concorrência Definição de um Módulo Processes: DEFINITION MODULE Processes; TYPE SIGNAL; PROCEDURE StartProcess(P:PROC; n:INTIGER); (*inicia um processo concorrente*) PROCEDURE SEND(VAR s:SIGNAL); (*um processo esperando por um s é continuado*) PROCEDURE WAIT(VAR s:SIGNAL); (*espera algum processo enviar s*) PROCEDURE Awaited(s:SIGNAL):BOOLEAN; (*Acordado(s)=“pelo menos um processo espera por s”*) PROCEDURE Init(VAR s:SIGNAL); (*inicialização compulsória*) END Processes. Modula – Concorrência •As Co-rotinas são implementadas a partir da procedure NewProcess; •Co-rotinas necessitam de programas ou procedures que manipulem valores de endereços de memória, pois elas agem diretamente no hardware do computador; •Na chamada da procedure NewProcess deve ser especificada em qual será criada a Co- rotina, o Workspace que é o bloco de memória onde será armazenado o estado da Co-rotina, o endereço de memória do Workspace,o tamanho do Workspace e a referência para a nova Co-rotina; Modula – Concorrência Sintaxe de NewProcess: Procedure NewProcess ( P : Procedure; A : Address "endereço do Workspace"; S : Cardinal "tamanho do Workspace"; Var E : Address "referência para nova Co-rotina"); Antes de chamarmos a procedure NewProcess devemos alocar memória para a Workspace, pois é nela que ficam as variáveis locais, a Co-rotina e a pilha de Co-rotinas e outras informações. Para criarmos a Workspace devemos declarar um array de Bytes ou Words. Também devemos criar uma variável do tipo Address, que retornará o endereço e o tamanho do Workspace(ADR e SIZE). Modula – Concorrência A procedure Transfer tem a função de transferir o controle de execução de uma Co-rotina para outra caracterizando a concorrência, ela também é fundamental para executar as Co-rotinas, pois NewProcess apenas prepara a Co-rotina para a execução. Esta é a sintaxe da procedure Transfer: Procedure Transfer ( A, B : Address); Quando a procedure Transfer é chamada, ela interrompe a Co-rotina que está sendo executada no momento, que é referenciada por A, e inicia a outra que é referenciada por B. A procedure Transfer deve ser importada de System. Modula – Concorrência MODULE Aplic; FROM Nucleo IMPORT CriarProcesso, DestruirProcesso, Boot, EnviarMsg, ReceberMsg, TipoNome, TipoMsg, TamNome, TamMsg, Sempre, NemSempre,EscreveFrase, EscreveInt,Incrementa,MaiorIgual,Atribui; FROM InOut IMPORT WriteCard, WriteLn, WriteString, WriteInt; CONST TamBuffer = 10; TYPE TipoBuffer = ARRAY[0..TamBuffer-1] OF TipoMsg; VAR BufferIn,BufferOut : TipoBuffer; In,Out : INTEGER; Flag : BOOLEAN; Modula – Concorrência PROCEDURE InicializaBuffer; VAR I : CARDINAL; BEGIN BufferIn[0] := 'MENSAGEM BUFFERIZADA NUMERO 1'; BufferIn[1] := 'MENSAGEM BUFFERIZADA NUMERO 2'; .... BufferIn[10] := 'MENSAGEM BUFFERIZADA NUMERO 11'; FOR I := 0 TO (TamBuffer - 1) DO BufferOut[I] := ' '; END; (* FOR *) In := 0; Out := 0; END InicializaBuffer; Modula – Concorrência PROCEDURE PoeNoBuffer(Msg : TipoMsg); BEGIN EscreveFrase('VAI POR NO BUFFER'); EscreveFrase(Msg); EscreveInt(Out); Atribui(BufferOut[Out],Msg); Incrementa(Out); END PoeNoBuffer; O produtor e o Consumidor acessam Esses métodos de modo concorrente PROCEDURE TiraDoBuffer(VAR Msg : TipoMsg); BEGIN EscreveFrase('VAI TIRAR DO BUFFER'); EscreveInt(In); Atribui(Msg,BufferIn[In]); Incrementa(In); EscreveFrase(Msg); END TiraDoBuffer; Modula – Concorrência PROCEDURE Produtor; VAR Msg : TipoMsg; Flag : BOOLEAN; BEGIN EscreveFrase('ENTROU NO PRODUTOR'); LOOP TiraDoBuffer(Msg); EnviarMsg(Msg,'C1',Flag); IF MaiorIgual(In,TamBuffer) THEN DestruirProcesso(NemSempre,Flag); END; (* IF *) END; (* LOOP *); EscreveFrase('SAIU DO PRODUTOR'); END Produtor; O produtor é criado no inicio do programa se o buffer estiver cheio, ele é destruído Modula – Concorrência PROCEDURE Consumidor; VAR Msg : TipoMsg; Flag : BOOLEAN; BEGIN EscreveFrase('ENTROU NO CONSUMIDOR'); LOOP ReceberMsg(Msg,Flag); IF Flag THEN PoeNoBuffer(Msg); END; IF MaiorIgual(Out,TamBuffer) THEN DestruirProcesso(NemSempre,Flag); END; (* IF *) END; (* LOOP *) EscreveFrase('SAIU DO CONSUMIDOR'); END Consumidor;