167
PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA

PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

PROGRAMAÇÃO CONCORRENTE BASEADA

EM ACORDES PARA PLATAFORMA JAVA

Page 2: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 3: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

SÉRGIO VALE E PACE

PROGRAMAÇÃO CONCORRENTE BASEADA

EM ACORDES PARA PLATAFORMA JAVA

Dissertação apresentada ao Programa dePós-Graduação em Ciência da Computaçãodo Instituto de Ciências Exatas da Univer-sidade Federal de Minas Gerais como re-quisito parcial para a obtenção do grau deMestre em Ciência da Computação.

Orientador: Roberto da Silva Bigonha

Belo Horizonte

Julho de 2009

Page 4: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

c© 2009, Sérgio Vale e Pace.Todos os direitos reservados.

Pace, Sérgio Vale eP115p Programação Concorrente Baseada em Acordes

para Plataforma Java / Sérgio Vale e Pace. — BeloHorizonte, 2009

xxvi, 141 f. : il. ; 29cm

Dissertação (mestrado) — Universidade Federal deMinas Gerais

Orientador: Roberto da Silva Bigonha

1. Computação - Teses. 2. Programaçãoconcorrente - Teses. 3. Linguagens de programação decomputador - Teses. 4. JAVA (Linguagem deprogramação de computador) - Teses. I. Título.

CDU 519.6*33

Page 5: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 6: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

vi

Page 7: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Dedico este trabalho a pessoa que é, e sempre foi, um exemplo de fé inabalável,espírito inquebrável e amor incondicional. Minha avó Áurea.

vii

Page 8: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 9: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Agradecimentos

Agradeço ao professor Roberto Bigonha pela orientação, paciência e dedicação, queforam fundamentais para a realização desse trabalho.

Agradeço também à professora Mariza Bigonha, ao professor Osvaldo Carvalho eao professor Marco Túlio Valente pelos muitos comentários, revisões e sugestões.

Agradeço à minha mãe Áurea e ao meu pai Carlos, que sempre me proporcionaramquase tudo o que eu podia querer e absolutamente tudo o que eu precisei pra me tornarquem eu sou hoje.

Agradeço a meu grande amigo e irmão Ronaldo por todas as lições que me ensinou,mesmo sem querer.

Agradeço a todos os meus amigos e colegas da AAIS (ATAN) pelo companheirismo,apoio e amizade, sem os quais esse trabalho não seria o mesmo.

Por fim, mas não menos importante, agradeço à minha Aline. Pelas madrugadasde trabalho, pela atenção dividida, pelos planos postergados, mas principalmente porser a metade da minha laranja e o norte na minha bússola.

ix

Page 10: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 11: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

“Poor workers blame their tools.Good workers build better tools.The best workers get their tools

to do the work for them. ”(The Book of Cataclysm - Syndicate Wars)

xi

Page 12: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 13: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Resumo

Os principais mecanismos usados para expressar paralelismo e concorrência disponíveisnas principais linguagens de programação modernas são construções de baixo nível deabstração, inadequadas ao desenvolvimento de sistemas concorrentes de larga escala.Isso faz com que a tarefa de projetar, analisar, implementar, testar e depurar sistemasconcorrentes seja bastante árdua.

O acorde é uma construção de alto nível, baseada no cálculo de processos join-calculus, que permite expressar os relacionamentos de concorrência declarativamente,possibilitando coordenar as interações entre fluxos de execução paralelos de maneiraimplícita.

Propõe-se uma biblioteca para programação concorrente baseada em acordes naplataforma Java. Por meio dessa biblioteca busca-se permitir que sistemas paralelose concorrentes sejam desenvolvidos em um maior nível de abstração de forma maissimples, efetiva e menos propensa a erros. É utilizada uma implementação baseadaem anotações e instrumentação dinâmica de bytecodes que permite adaptar a sintaxee a semântica da linguagem, propiciando expressar os acordes de maneira natural semcomprometer o ambiente padrão Java de desenvolvimento e execução.

xiii

Page 14: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 15: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Sumário

Agradecimentos ix

Resumo xiii

Lista de Figuras xix

Lista de Tabelas xxi

Lista de Listagens xxiii

1 Introdução 11.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Programação Concorrente Baseada em Acordes . . . . . . . . . . . . . 51.3 Soluções Existentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.4 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.5 Organização do Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Fundamentos Teóricos 132.1 π-Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.2 Join-Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.3 Acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.4 Conclusões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3 Acordes em Java 353.1 Contexto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.1.1 Requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.1.2 Recursos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.1.3 Limitações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.2 Desenho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.2.1 Classes com Acordes . . . . . . . . . . . . . . . . . . . . . . . . 413.2.2 Métodos Assíncronos . . . . . . . . . . . . . . . . . . . . . . . . 42

xv

Page 16: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.2.3 Métodos Síncronos . . . . . . . . . . . . . . . . . . . . . . . . . 443.2.4 Métodos Acordes . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.3 Aplicação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463.3.1 Produtor/Consumidor . . . . . . . . . . . . . . . . . . . . . . . 463.3.2 Jantar dos Filósofos . . . . . . . . . . . . . . . . . . . . . . . . . 493.3.3 O Problema do Papai Noel . . . . . . . . . . . . . . . . . . . . . 54

3.4 Conclusões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

4 Implementação 594.1 Camadas de Atuação de JChords . . . . . . . . . . . . . . . . . . . . . 594.2 Camada de Desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . 604.3 Camada de Transformação . . . . . . . . . . . . . . . . . . . . . . . . . 62

4.3.1 AsyncTransformer . . . . . . . . . . . . . . . . . . . . . . . . . 654.3.2 JoinTransformer . . . . . . . . . . . . . . . . . . . . . . . . . . . 664.3.3 Transformação . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

4.4 Camada de Execução . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684.4.1 Chords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

4.5 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

5 Avaliação 735.1 Critérios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745.2 JChords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775.3 Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785.4 Join Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805.5 Cω . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815.6 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

6 Considerações Finais 856.1 Trabalhos Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

6.1.1 Otimização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866.1.2 Validação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876.1.3 Herança e Polimorfismo . . . . . . . . . . . . . . . . . . . . . . 876.1.4 Padrões Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886.1.5 Padrões de Sincronização . . . . . . . . . . . . . . . . . . . . . . 886.1.6 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

6.2 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

A Códigos Fonte 91A.1 Biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

xvi

Page 17: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2 Casos de Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109A.2.1 Métodos Assíncronos . . . . . . . . . . . . . . . . . . . . . . . . 109A.2.2 Jantar dos Filósofos . . . . . . . . . . . . . . . . . . . . . . . . . 112A.2.3 Produtor Consumidor . . . . . . . . . . . . . . . . . . . . . . . 119A.2.4 Papai Noel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125A.2.5 Buffer Simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

Referências Bibliográficas 139

xvii

Page 18: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 19: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Lista de Figuras

2.1 Uma reação na RCHAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2 Adição de um átomo na RCHAM . . . . . . . . . . . . . . . . . . . . . . . 182.3 Reação não-determinística da RCHAM . . . . . . . . . . . . . . . . . . . . 19

4.1 Camadas de atuação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594.2 Estrutura de uma solução em ASM . . . . . . . . . . . . . . . . . . . . . . 644.3 Casamento de padrões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704.4 Algoritmo de casamento de padrões . . . . . . . . . . . . . . . . . . . . . . 70

xix

Page 20: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 21: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Lista de Tabelas

2.1 Invocações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

5.1 Soluções em acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735.2 Sumário da avaliação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

xxi

Page 22: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 23: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Lista de Listagens

1.1 Acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.2 Buffer com acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.3 Uso do buffer com acordes . . . . . . . . . . . . . . . . . . . . . . . . . 62.1 Estrutura de um acorde . . . . . . . . . . . . . . . . . . . . . . . . . . 242.2 Fila de impressão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.3 Mutex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4 Semáforo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.5 Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.6 Barreira . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303.1 Pseudo-Código de buffer com acordes . . . . . . . . . . . . . . . . . . . 393.2 Buffer com acordes em JChords . . . . . . . . . . . . . . . . . . . . . . 403.3 Buffer com join em JChords . . . . . . . . . . . . . . . . . . . . . . . . 403.4 Buffer com JChords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403.5 Classe com acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413.6 Método assíncrono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.7 Exemplo de método assíncrono com JChords . . . . . . . . . . . . . . . 423.8 Exemplo de método assíncrono com threads . . . . . . . . . . . . . . . 433.9 Exemplo complexo de métodos assíncronos com JChords . . . . . . . . 433.10 Exemplo complexo de métodos assíncronos com threads . . . . . . . . . 433.11 Método síncrono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443.12 Método assíncrono com valor de retorno . . . . . . . . . . . . . . . . . 453.13 Métodos acordes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453.14 Descritor de fragmento de acordes . . . . . . . . . . . . . . . . . . . . . 453.15 Classe Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473.16 Classe Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483.17 Classe Waiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503.18 Classe Waiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513.19 Classe Phil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513.20 Classe Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

xxiii

Page 24: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.21 Classe SantaClaus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554.1 Anotações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604.2 Anotação @Chorded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614.3 Anotação @Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614.4 Classe Transformer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 624.5 Método assíncrono original . . . . . . . . . . . . . . . . . . . . . . . . . 654.6 Método assíncrono transformado . . . . . . . . . . . . . . . . . . . . . . 654.7 Classe Buffer original . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674.8 Classe Buffer transformada . . . . . . . . . . . . . . . . . . . . . . . . 674.9 Inicialização do gerenciador de acordes . . . . . . . . . . . . . . . . . . 695.1 Acorde composto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755.2 usecases/santaclaus/jchords/Group.java . . . . . . . . . . . . . . . . . . 775.3 Classe nway . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795.4 Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805.5 Classe nway . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81A.1 jchords/AsyncCall.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 91A.2 jchords/Call.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92A.3 jchords/Chords.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93A.4 jchords/JoinDescriptor.java . . . . . . . . . . . . . . . . . . . . . . . . 94A.5 jchords/JoinFragment.java . . . . . . . . . . . . . . . . . . . . . . . . . 95A.6 jchords/JoinPattern.java . . . . . . . . . . . . . . . . . . . . . . . . . . 96A.7 jchords/agents/AsyncTransformer.java . . . . . . . . . . . . . . . . . . 98A.8 jchords/agents/JoinTransformer.java . . . . . . . . . . . . . . . . . . . 100A.9 jchords/agents/Transformer.java . . . . . . . . . . . . . . . . . . . . . . 106A.10 jchords/annotations/Async.java . . . . . . . . . . . . . . . . . . . . . . 107A.11 jchords/annotations/Chorded.java . . . . . . . . . . . . . . . . . . . . . 107A.12 jchords/annotations/Join.java . . . . . . . . . . . . . . . . . . . . . . . 107A.13 jchords/annotations/Sync.java . . . . . . . . . . . . . . . . . . . . . . . 108A.14 jchords/util/Constants.java . . . . . . . . . . . . . . . . . . . . . . . . 108A.15 usecases/async/java/Example1.java . . . . . . . . . . . . . . . . . . . . 109A.16 usecases/async/java/Example2.java . . . . . . . . . . . . . . . . . . . . 109A.17 usecases/async/jchords/Example1.java . . . . . . . . . . . . . . . . . . 110A.18 usecases/async/jchords/Example2.java . . . . . . . . . . . . . . . . . . 111A.19 usecases/diningphilosophers/higienic/jchords/Fork.java . . . . . . . . . 112A.20 usecases/diningphilosophers/higienic/jchords/Phil.java . . . . . . . . . 112A.21 usecases/diningphilosophers/higienic/jchords/Runner.java . . . . . . . 113A.22 usecases/diningphilosophers/waiter/java/Fork.java . . . . . . . . . . . . 114

xxiv

Page 25: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.23 usecases/diningphilosophers/waiter/java/Phil.java . . . . . . . . . . . . 115A.24 usecases/diningphilosophers/waiter/java/Runner.java . . . . . . . . . . 116A.25 usecases/diningphilosophers/waiter/java/Waiter.java . . . . . . . . . . 116A.26 usecases/diningphilosophers/waiter/jchords/Fork.java . . . . . . . . . . 117A.27 usecases/diningphilosophers/waiter/jchords/Phil.java . . . . . . . . . . 117A.28 usecases/diningphilosophers/waiter/jchords/Runner.java . . . . . . . . 118A.29 usecases/diningphilosophers/waiter/jchords/Waiter.java . . . . . . . . . 119A.30 usecases/producerconsumer/java/Buffer.java . . . . . . . . . . . . . . . 119A.31 usecases/producerconsumer/java/Consumer.java . . . . . . . . . . . . . 120A.32 usecases/producerconsumer/java/Producer.java . . . . . . . . . . . . . 121A.33 usecases/producerconsumer/java/Runner.java . . . . . . . . . . . . . . 121A.34 usecases/producerconsumer/jchords/Buffer.java . . . . . . . . . . . . . 122A.35 usecases/producerconsumer/jchords/Consumer.java . . . . . . . . . . . 123A.36 usecases/producerconsumer/jchords/Producer.java . . . . . . . . . . . . 123A.37 usecases/producerconsumer/jchords/Runner.java . . . . . . . . . . . . . 124A.38 usecases/santaclaus/java/Elf.java . . . . . . . . . . . . . . . . . . . . . 125A.39 usecases/santaclaus/java/Group.java . . . . . . . . . . . . . . . . . . . 125A.40 usecases/santaclaus/java/Monitor.java . . . . . . . . . . . . . . . . . . 127A.41 usecases/santaclaus/java/Reindeer.java . . . . . . . . . . . . . . . . . . 129A.42 usecases/santaclaus/java/Runner.java . . . . . . . . . . . . . . . . . . . 130A.43 usecases/santaclaus/java/SantaClaus.java . . . . . . . . . . . . . . . . . 130A.44 usecases/santaclaus/jchords/Elf.java . . . . . . . . . . . . . . . . . . . 132A.45 usecases/santaclaus/jchords/Group.java . . . . . . . . . . . . . . . . . . 132A.46 usecases/santaclaus/jchords/Reindeer.java . . . . . . . . . . . . . . . . 133A.47 usecases/santaclaus/jchords/Runner.java . . . . . . . . . . . . . . . . . 134A.48 usecases/santaclaus/jchords/SantaClaus.java . . . . . . . . . . . . . . . 134A.49 usecases/simplebuffer/jchords/Buffer.java . . . . . . . . . . . . . . . . . 136A.50 usecases/simplebuffer/jchords/BufferClass.java . . . . . . . . . . . . . . 137

xxv

Page 26: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 27: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 1

Introdução

Programação paralela e concorrente é um componente importante para sistemas com-putacionais modernos. Com o advento da “revolução Multi-Core” [Sutter, 2005], essamodalidade de programação passa a desempenhar um papel ainda mais crucial na evo-lução da computação de forma geral. Entretanto, os mecanismos usados para expressarparalelismo e concorrência disponíveis nas principais linguagens de programação mo-dernas ainda são construções de baixo nível, baseadas em conceitos que evoluíram muitopouco nos últimos 30 anos, inadequadas ao desenvolvimento de sistemas concorrentesde larga escala [Itzstein, 2005].

Desde o início de 2003, devido a uma série de fatores técnicos e limites físicosfundamentais, os principais fabricantes de processadores passaram a utilizar, em largaescala, as arquiteturas multi-core. Nesse tipo de arquitetura, os processadores dispõemde dois ou mais núcleos de processamento independentes (cores). Busca-se assim,aumentar a capacidade de processamento pela execução simultânea de duas ou maisinstruções. Isso é diferente da estratégia adotada até então de aumentar a capacidadede processamento pela diminuição do tempo de execução individual de cada instrução.[Sutter, 2005].

As principais linguagens de programação modernas são fundamentalmente sequen-ciais. A thread é hoje a abstração mais usual e amplamente utilizada em linguagensde programação e sistemas operacionais para expressar concorrência e paralelismo. Deacordo com Lee [2006] muitas das arquiteturas paralelas de propósito geral em uso hojesão uma implementação direta em hardware da abstração de thread.

Normalmente, threads são implementadas como adições periféricas à sintaxe dalinguagem (Java, C#) ou como bibliotecas externas (C++ [Butenhof, 1997])[Lee, 2006],modeladas diretamente a partir das primitivas do sistema operacional [Benton et al.,2004]. A programação baseada em threads é complexa e propensa a erros graves edifíceis de detectar, uma vez que as threads introduzem não-determinismo implícito e

1

Page 28: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2 Capítulo 1. Introdução

irrestrito ao processo. Isso faz com que a tarefa de projetar, analisar, implementar,testar e debugar sistemas concorrentes seja bastante árdua [Benton et al., 2004].

Muito embora a programação baseada em threads seja a técnica dominante parao desenvolvimento de sistemas paralelos e concorrentes nas principais linguagens deprogramação modernas, novas técnicas têm sido propostas. Dentre as alternativastemos a programação baseada em acordes.

O acorde é uma construção de alto nível, baseada no cálculo de processos join-calculus, que permite expressar os relacionamentos de concorrência declarativamente,possibilitando que as interações entre fluxos de execução paralelos sejam coordenadosde maneira implícita [Petrounias et al., 2008].

Os acordes se ajustam muito bem às linguagens de programação imperativas ori-entadas a objetos. Dentre essas linguagens, uma das mais usadas atualmente é alinguagem Java [Gosling et al., 2005], que semanticamente se mostra bastante ade-quada à programação baseada em acordes. Contudo, são necessárias algumas adiçõessintáticas à linguagem Java para que os acordes possam ser usados confortavelmente.

Itzstein [2005] e Wood & Eisenbach [2004] implementam acordes em Java por meiode compiladores customizados. Essa abordagem restringe a aplicação prática dessassoluções, principalmente em ambientes de produção. Com isso o acesso à programaçãobaseada em acordes fica limitada a um grupo restrito de desenvolvedores Java.

Propõe-se nesse trabalho a criação de uma biblioteca de classes para programaçãobaseada em acordes na linguagem Java. Essa biblioteca é baseada em anotações emanipulações de bytecode. Essa abordagem possibilitará a utilização de acordes comferramental Java padrão. A essa biblioteca dar-se-á o nome JChords.

1.1 Threads

Threads são, essencialmente, processos sequenciais, que compartilham recursos entresi. Sintaticamente, acomodar o conceito de threads em uma linguagem sequencialnão requer muito esforço, seja por meio de primitivas da própria linguagem ou viabibliotecas externas. Talvez a isso se deva o sucesso da thread como abstração deconcorrência [Lee, 2006].

Contudo, semanticamente, as threads representam um desvio significativo dos con-ceitos fundamentais nos quais se baseiam a maior parte das linguagens de programaçãode propósito geral. A maioria das linguagens de programação busca ser compreensível,predizível e determinística. No paradigma sequencial, essas propriedades são obtidasenfatizando sequências de ações determinísticas, formando composições também deter-minísticas [Lee, 2006].

Page 29: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

1.1. Threads 3

Seja Bn uma sequência longa, porém finita, de dígitos binários que representamo estado completo de um dado sistema computacional em um dado instante n. Essasequência de dígitos engloba de maneira completa toda e qualquer informação de es-tado desse sistema, incluindo células de memória, registradores ou flags do processador,arquivos armazenados em disco, entre outros. Ou seja, o estado interno de cada sub-sistema pode ser mapeado em uma subsequência de Bn de modo que qualquer partedo sistema que seja mutável no tempo equivale a uma sequência de bits em Bn

Seja então P1 o processador desse computador, ou seja, o elemento ativo dessesistema. Nesse contexto, P1 é o único agente de mudança e, por consequência, o únicoresponsável pela transição de Bn para Bn+1. Dessa forma podemos dizer que Bn+1 é oproduto da ação de P1 sobre Bn, ou seja Bn+1 = P1(Bn) para um dado Bn qualquer:

B0P1−→ B1

P1−→ B2P1−→ · · · P1−→ Bn (1.1)

Podemos observar que nesse cenário existe um único caminho entre um estado Bn

qualquer e qualquer outro estado Bm, tal que m > n. A partir de um estado qualquer,sabemos a priori quais serão os estados futuros e quantos passos são necessários paraalcançá-los, ou seja, temos previsibilidade e determinismo.

Por sua vez, sistemas baseados em threads observam-se não-determinísticos pordefinição. Uma thread pode ser vista, dentro do modelo proposto acima, como umsegundo processador P2 atuando paralelamente em Bn. Dois processos independentesP1 e P2, atuando simultaneamente sobre um estado Bn irão produzir um estado Bn+1

dentre um número potencialmente ilimitado de possibilidades. Para enumerar algunstemos:

• As ações de P1 sobrescrevem completamente as ações de P2, logo Bn+1 = P1(Bn)

• Todas as ações de P1 sobre Bn ocorrem antes de P2, logo Bn+1 = P2(P1(Bn))

• As ações de P1 ocorrem simultaneamente as de P2, logo Bn+1 = P1|P2(Bn)

Dessa forma a transição de Bn para Bn+1 passa a ser não-determinística e conside-ravelmente menos previsível:

Page 30: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4 Capítulo 1. Introdução

B0P1|P2−−−→

P1(B0)

P1(P2(B0))

· · ·

P1|P2

· · ·

P2(P1(B0))

P2(B0)

Dessa forma, a introdução do conceito de threads em uma linguagem sequencialcompromete o determinismo desta e elimina as características mais significativas doparadigma sequencial.

Consequentemente, sistemas multithread requerem um nível de esforço e complexi-dade elevados em sua análise, desenvolvimento e manutenção. Isso porque se torna ne-cessário construir e manter um conjunto significativo de ferramentas, técnicas, padrõese construções que permitam ao desenvolvedor limitar o não-determinismo introduzidopelas threads.

Em essência, todas as construções de sincronização presentes hoje nas linguagens deprogramação de propósito geral: semáforos, monitores, exclusão mútua, locks, dentreoutras; servem principalmente para permitir ao desenvolvedor restringir os caminhosindesejáveis na computação multithread [Lee, 2006].

Contudo, para qualquer sistema paralelo não-trivial o número de interações inde-sejáveis entre threads é potencialmente infinito, e assim, mesmo dispondo dos meiospara controlar e sincronizar threads essa ainda é uma tarefa árdua e altamente sujeitaa erros, que normalmente são muito difíceis de detectar.

As threads são um importante bloco construtivo para a programação paralela econcorrente em linguagens de programação imperativas. Porém, como vimos nessaseção, são construções de baixo nível de abstração que produzem efeitos colateraisbastante significativos, que normalmente não são imediatamente claros. Segundo Lee[2006], threads não deveriam ser usadas explicitamente no desenvolvimento de sistemasconcorrentes, mas sim como base para construções com maior nível de abstração. Umaanalogia válida são os comandos de desvio de execução (goto) que, embora presentesem algum nível de abstração, não são explicitamente usados ou suportados na maiorparte das linguagens de programação modernas.

Page 31: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

1.2. Programação Concorrente Baseada em Acordes 5

1.2 Programação Concorrente Baseada em Acordes

A necessidade de abstrações adequadas a modelagem e orquestração de sistemas con-correntes levou a criação de diversas álgebras de processos dedicados a modelagemformal de sistemas concorrentes. Join-Calculus é um exemplo desse tipo de álgebra. Ojoin-calculus, proposto por Fournet & Gonthier [2000], foi desenvolvido para atenderàs necessidades de modelamento de sistemas distribuídos [Benton et al., 2004].

Baseado no join-calculus, Benton et al. [2002] e Itzstein & Kearney [2002] propuse-ram uma construção chamada Acorde (Chord no inglês). O Acorde se propõe a ser umaconstrução de elevado grau de abstração para expressar situações complexas de con-corrência e sincronização em linguagens imperativas baseadas no paradigma orientadopor objetos [Wood & Eisenbach, 2004].

Nos primórdios da programação orientada a objetos, particularmente em Smalltalk,a separação conceitual entre mensagem e método era bastante bem definida. Mensa-gens são sinais parametrizados que podem ser enviados a um objeto. Métodos sãoconjuntos de ações que devem ser executadas em momentos específicos. Normalmenteo recebimento de uma mensagem causa a execução de um método [Ingalls, 1981].

Esse relacionamento estreito entre mensagens e métodos fez com que a separaçãoentre esses dois elementos fosse ficando indistinta, à medida que foram surgindo novaslinguagens orientadas a objetos como C++, Java, C#, dentre outras. Em geral, nes-sas linguagens, o envio de uma mensagem corresponde a execução de exatamente ummétodo. O método específico que será executado irá depender do objeto que recebe amensagem, contudo somente um único método de um único objeto é executado em res-posta ao recebimento de uma mensagem. Isso muitas vezes cria a ilusão de identidadeentre esses dois elementos.

Em acordes, a distinção entre método e mensagem passa a ser relevante, pois aexecução de um método pode requerer o recebimento de mais de uma mensagem. Sin-taticamente, o acorde é construído por um conjunto de mensagens ligadas pelo operadorjoin (representado aqui pelo caractere &) e o corpo de um método. Respectivamentea assinatura e o corpo do acorde como ilustrado na Listagem 1.1 [Drossopoulou et al.,2006].

1 Mensagem1(parâmetro1) & Mensagem2(parâmetro2) {}

Listagem 1.1. Acordes

As mensagens que compõem a assinatura do acorde, também chamadas de frag-mentos do acorde, podem ser síncronas ou assíncronas. Um acorde possui, no máximo,uma única mensagem síncrona. Somente mensagens síncronas podem retornar valor.Por consequência, um acorde só pode retornar um único valor. Por sua vez, o corpo

Page 32: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

6 Capítulo 1. Introdução

do acorde tem acesso a todos os parâmetros de todas as mensagens que compõem aassinatura e, se necessário, deve prover o valor de retorno do acorde. [Drossopoulouet al., 2006].

O corpo de um acorde só é executado quando todas as mensagens da assinaturativerem sido recebidas. As mensagens assíncronas não interrompem o fluxo de execuçãoonde foram emitidas. As mensagens síncronas bloqueiam o fluxo de execução até queo corpo do acorde tenha sido executado [Benton et al., 2007].

1 public class Buffer {

2 public String get() & public async put(String s) {

3 return s;

4 }

5 }

Listagem 1.2. Buffer com acordes

No código de exemplo da Listagem 1.2, adaptado de Benton et al. [2007], temosuma classe Buffer que possui somente um acorde, que é composto pela mensagemsíncrona String get(), pela mensagem assíncrona put(String s), e por um métodoque retorna o parâmetro s de put(String s).

O envio de uma mensagem put(String s) para uma instância de Buffer não retornavalor, não bloqueia o fluxo de execução e, por si só, não causa a execução do corpo doacorde, ou seja, put(String s) é condição necessária, mas não suficiente para causar aexecução do corpo do acorde.

Em contrapartida, a emissão de uma mensagem get() para uma instância de Bufferirá retornar um valor do tipo String e irá bloquear o fluxo de execução do programaaté que o corpo do acorde tenha condições de ser executado, porém, por si só, tambémnão é capaz de causar essa execução [Benton et al., 2004].

1 Buffer buffer = new Buffer();

2 buffer.put(‘‘A’’);

3 buffer.put(‘‘B’’);

4

5 System.Console.WriteLine(buffer.get()); // imprime ‘‘B’’

6 System.Console.WriteLine(buffer.get()); // imprime ‘‘A’’

7 System.Console.WriteLine(buffer.get()); // bloqueia

Listagem 1.3. Uso do buffer com acordes

Como pode ser observado no exemplo da Listagem 1.2 e da Listagem 1.3, a as-sinatura de um acorde provê uma salvaguarda para a execução do corpo do mesmo,

Page 33: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

1.3. Soluções Existentes 7

promovendo uma declaração de condições necessárias para a execução deste [Petrouniaset al., 2008].

Vale ressaltar também que a gestão de recursos compartilhados, no caso a string“s”, deixa de ser uma responsabilidade do desenvolvedor e passa a ser responsabilidadeda implementação dos acordes[Itzstein, 2005].

O exemplo dado, apesar de bastante simples, por si só nos permite solucionar demaneira efetiva vários problemas do tipo Produtor-Consumidor. O acorde é uma cons-trução bastante poderosa que permite o modelamento de problemas mais complexosde concorrência de uma maneira efetiva e direta.

Threads introduzem um alto grau de não-determinismo nos sistemas paralelos. Paracontornar esse problema foram criadas mecanismos para permitir ao desenvolvedor res-tringir os possíveis caminhos de execução de um sistema paralelo. Pela utilização deacordes, adotou-se a abordagem oposta, ao invés de tentar inibir o conjunto potenci-almente infinito de computações indesejáveis, os acordes nos permitem expressar demaneira elegante e efetiva o conjunto potencialmente finito de computações desejá-veis, introduzindo o não determinismo apenas em pontos específicos e controlados dosistema.

1.3 Soluções Existentes

Acordes tem sido foco de diversos projetos de pesquisa e, consequentemente, têm sur-gido diversas iniciativas de implementar acordes em novas ou existentes linguagens deprogramação orientadas a objetos. Essas iniciativas variam em propósito, indo desdede iniciativas voltadas para o desenvolvimento formal da teoria de acordes, como Dros-sopoulou et al. [2006] e Petrounias et al. [2008], até soluções dedicadas a aplicaçãoimediata em ambiente produtivo como Russo [2006].

As primeiras implementações de acordes conhecidas foram feitas por Fournet et al.[2002], Benton et al. [2002] e Itzstein & Kearney [2002]. Esses trabalhos coopera-tivamente lançaram as bases semânticas e sintáticas para o desenvolvimento práticobaseado em acordes. Dentre essas, Benton et al. [2002] e Itzstein & Kearney [2002] fo-ram as primeira implementações baseadas em linguagens orientadas a objetos. Ambasforam construídas pela implementação de compiladores customizados para C# e Java,respectivamente.

No âmbito do desenvolvimento teórico, Drossopoulou et al. [2006] propôs uma novalinguagem inteiramente baseada em acordes. Essa iniciativa buscava um melhor en-tendimento dos acordes como construções de linguagem e procurou criar um conjuntomínimo de funcionalidades necessárias para obter uma linguagem imperativa orien-

Page 34: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

8 Capítulo 1. Introdução

tada a objetos com suporte a acordes. Posteriormente, em Petrounias et al. [2008],foi demonstrado que o suporte a variáveis membros (campos) de uma classe pode seremulados por meio de acordes, sugerindo aplicações mais amplas para os mesmos.

A partir de Benton et al. [2002], o esforço para disponibilizar acordes em C# conti-nuou em Benton [2003] e Benton et al. [2004]. Contudo, Chrysanthakopoulos & Singh[2005] e Russo [2006] observaram que, por mais promissor que seja a programação base-ada em acordes, os problemas envolvidos em utilizar um compilador customizado forade um ambiente estritamente experimental impede o acesso do “desenvolvedor comum”ao mundo dos acordes.

Por isso, Russo [2006] e Chrysanthakopoulos & Singh [2005] introduziram os acordesem C# por meio de uma biblioteca externa que poderia ser usada diretamente emum ambiente de desenvolvimento padrão. Liu [2008] tem progredido em iniciativasemelhante para C++.

Muito embora a implementação via biblioteca imponha diversas limitações tantono que se refere à sintaxe quanto à possibilidade de otimização, essa abordagem dispo-nibilizou a programação baseada em acordes a um público muito maior e viabilizou oseu uso mesmo em sistema legados.

Podemos destacar também o trabalho de Wood & Eisenbach [2004] no desenvol-vimento do suporte a acordes para Java. Interessantemente esse trabalho foi baseadoprincipalmente em Benton et al. [2002] e revisitou muitos dos conceitos vistos em Itzs-tein & Jasiunas [2003] sob uma nova ótica. Assim como Itzstein & Jasiunas [2003],essa solução também se baseou na criação de um compilador customizado para Javacom suporte a acordes.

Contudo, nos últimos anos o desenvolvimento de acordes em Java foi significati-vamente deixado de lado. Até o momento, nem Itzstein [2005] nem Wood & Eisen-bach [2004] disponibilizaram ao público os códigos fontes completos de seus trabalhos.Mesmo que esses códigos tivessem sido disponibilizados ambas as iniciativas são limi-tadas a ambientes experimentais, visto que a utilização de compiladores customizadosimpõe diversas limitações que não são aceitáveis para um universo considerável depotenciais desenvolvedores. Dentre elas podemos destacar:

• Suporte sub-ótimo à linguagem, em particular para funcionalidades menos utili-zadas.

• Incompatibilidades com o ferramental existente (IDEs, debugadores, etc)

• Performance inferior tanto do código gerado como do próprio compilador

• Dificuldade e demora na incorporação correções, evoluções e inovações

Page 35: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

1.4. Objetivos 9

Em princípio, mecanismos de concorrência podem ser implementados tanto comoparte de linguagem quanto como bibliotecas externas. O benefício de se implementartais mecanismos como parte da linguagem é a possibilidade dada ao compilador derealizar análises e otimizações mais aprofundadas [Benton et al., 2004], assim comodisponibilizar uma sintaxe mais bem adaptada à tarefa.

Por outro lado, os acordes são uma criação relativamente recente. A evolução na-tural dessa construção, obtida por meio da experimentação prática e pesquisa teórica,pode levar a incrementos e alterações da mesma. Experimentação essa que só serápossível se os acordes estiverem disponíveis a um público amplo e diversificado [Chry-santhakopoulos & Singh, 2005].

Ao contrário do que tem ocorrido em C#, a exemplo de Russo [2006], o desenvol-vimento com acordes para Java está indisponível ao desenvolvedor médio e inacessívela sistemas legados. Não existe um meio incremental de incorporar acordes na base desoftware existente e mesmo a experimentação com acordes em Java é dificultada, hajavista o limitado público com a capacidade técnica para propor modificações e correçõesem compiladores customizados.

1.4 Objetivos

Considerando o exposto acima, esse trabalho tem os objetivos de:

• Estudar o impacto da implementação de acordes via biblioteca na arquitetura dalinguagem Java

• Implementar acordes para Java por meio de uma biblioteca

• Implementar casos de uso práticos que utilizem essa biblioteca

• Avaliar a solução proposta considerando a base teórica de join-calculus

• Analisar comparativamente o uso de acordes em relação as primitivas de concor-rência existentes em Java

Como pode ser visto no exemplo apresentado anteriormente, acordes, quando im-plementados diretamente na linguagem, são construções simples e elegantes que seencaixam bastante naturalmente na sintaxe da linguagem. Contudo, uma implemen-tação de acordes via biblioteca traz diversos desafios que precisam ser superados.

Uma implementação de acordes, fundamentalmente, precisa possuir mecanismosque suportem a expressão de dois elementos chaves: métodos assíncronos e padrõesjoin [Benton et al., 2007].

Page 36: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

10 Capítulo 1. Introdução

Os métodos assíncronos devem exprimir as noções de paralelismo e ausência deretorno de valor. Em Itzstein [2005] esses conceitos foram introduzidos por meio dapalavra reservada signal que é usada como tipo de retorno para os métodos assíncronos(async em Benton et al. [2002]). Contudo, uma implementação de acordes via bibliotecanão dispõe da possibilidade de introduzir novas palavras reservadas na linguagem.

Os padrões join devem exprimir as noções de sincronização e gestão de recursos queefetivamente formam as bases para os acordes. É importante observar que, na sintaxepadrão da linguagem Java, assim como diversas outras linguagens imperativas orien-tadas por objetos, uma declaração de método é feita com exatamente uma assinaturae exatamente um corpo. Essa não é uma sintaxe viável para acordes onde existe umconjunto de assinaturas de métodos que se referem a um único corpo.

Tanto Itzstein [2005] quanto Benton et al. [2004] expressam os padrões join viao operador “&” usado para ligar os diversos fragmentos de um acorde. Novamente,a introdução de um novo operador na linguagem não é uma opção viável no casode uma implementação em biblioteca. Isso faz com que a sintaxe para declaração dosacordes seja uma construção não trivial nesse tipo de implementação, além de dificultaro binding dos parâmetros dos fragmentos do acorde que precisarão ser transportadospara o corpo do mesmo.

Por fim, uma implementação de acordes via biblioteca precisa mapear as construçõesdisponibilizadas nas primitivas de programação concorrentes disponíveis nativamente,tendo o cuidado de preservar as propriedades e características das abstrações de altonível.

1.5 Organização do Texto

O Capítulo 2 contém a revisão dos fundamentos teóricos nos quais os acordes se ba-seiam. Começando com π-Calculus, passando pelo Join-Calculus e conclui detalhandoo funcionamento básico dos Acordes propriamente ditos.

O Capítulo 3 apresenta a biblioteca JChords, desenvolvida nesse trabalho, quepermite a programação baseada em acordes em Java. São apresentados os fundamentosda biblioteca e seu desenho. Além disso é feita uma análise comparativa entre JChordse Java padrão para casos de uso selecionados.

O Capítulo 4 detalha a arquitetura e implementação da biblioteca JChords. Sãoanalisados os diversos componentes da biblioteca e sua interação para prover acordesem Java em um ambiente de desenvolvimento padrão.

O Capítulo 5 faz uma análise comparativa da solução proposta com as principaissoluções existentes.

Page 37: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

1.5. Organização do Texto 11

Por fim o Capítulo 6 faz um apanhado geral do trabalho realizado e apresentasugestões e desafios para trabalhos futuros.

Page 38: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 39: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 2

Fundamentos Teóricos

Nesse capítulo são apresentados os fundamentos teóricos que suportam o desenvolvi-mento de sistemas baseados em acordes. É feita uma revisão das álgebras de processos,π-calculus e join-calculus, com o objetivo de mostrar como esses formalismos podemser usados para prover abstrações elegantes para expressar paralelismo e concorrência.Por fim é formalizado o conceito de acorde e detalhadas as principais propriedadesdessa construção no contexto de linguagens imperativas orientadas a objetos.

O π-calculus é uma álgebra de processos madura que resistiu à prova do tempo emostra-se um formalismo robusto para expressar ou descrever o comportamento pa-ralelo de processos concorrentes [Pierce, 1995]. Contudo, apesar de suas qualidades,π-calculus é limitado para expressar situações onde o envio e o recebimento de mensa-gens ocorre de maneira assíncronas e distribuída Fournet & Gonthier [2000].

Join-Calculus por sua vez é uma formalismo mais recente, desenvolvido como umaderivação assíncrona do π-calculus. Com isso buscou-se reusar as qualidades do π-calculus e ainda permitir expressar cenários que envolvem comunicações assíncronasentre processos distribuídos [Fournet & Gonthier, 2000].

Formalismos como esses permitem analisar e estudar as propriedades de modelose mecanismos abstratos possibilitando criar um sólido entendimento de seu funciona-mento. Porém, para serem efetivos fora do ambiente teórico é necessário transportaresses formalismos para técnicas, ferramentas e construções em ambientes de desenvol-vimento.

Os acordes são construções adequadas à linguagens de programação imperativasorientadas a objetos, derivadas diretamente a partir do join-calculus. O acorde permiteusar as estruturas do join-calculus como um mecanismo de orquestração de processos,permitindo expressar as regras de interação entre processos declarativamente. Comisso é possível abstrair o gerenciamento explícito das interações entre fluxos paralelosde execução em favor de conjuntos de regras impostas implicitamente.

13

Page 40: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

14 Capítulo 2. Fundamentos Teóricos

2.1 π-Calculus

O π-calculus é uma álgebra de processos desenvolvido por Milner [1989] derivado deMilner [1980], Hoare [1985], entre outros. Trata-se de um modelo matemático paraprocessos dinâmicos onde as interconexões entre processos mudam a medida que essesinteragem entre si.

Em π-calculus cada expressão denota um processo, ou seja, uma atividade compu-tacional executando em paralelo com outras atividades. O elemento fundamental decomputação é a transmissão e recepção de mensagens através de canais de comunicação[Pierce, 1995].

Simplificadamente, π-calculus pode ser definido formalmente como:

Sintaxe

Nomes a, b, c, . . . , x, y, z Canais (2.1a)

Processos P,Q,R ≡ 0 Processo inerte (2.1b)

‖ ax.P Transmissão (2.1c)

‖ a(x).P Recepção (2.1d)

‖ P | Q Composição (2.1e)

‖ (γx)P Restrição (2.1f)

‖ !P Replicação (2.1g)

Congruência Estrutural

Composição (2.1e) P | 0 ≡ P (2.2a)

P | Q ≡ Q | P (2.2b)

(P | Q) | R ≡ P | (Q | R) (2.2c)

Restrição (2.1f) ((γx)P ) | Q ≡ (γx)(P | Q) (2.2d)

(γx)(γy)P ≡ (γy)(γx)P (2.2e)

(γx)0 ≡ 0 (2.2f)

Replicação (2.1g) !P ≡ P |!P (2.2g)

Page 41: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.1. π-Calculus 15

Semântica

ax.P | a(y).Q⇒ P | [x/y]Q (2.3a)

π-calculus opera sobre nomes (2.1a) que podem ser canais de comunicação ou men-sagens, sendo que canais podem ser usados como mensagens e vice-versa, ou seja, sãoapenas formas possíveis para a mesma entidade. Da mesma maneira, os nomes emsi não são relevantes exceto como forma de identificar uma mesma entidade dentroda expressão, ou seja, a expressão ax é equivalente a by, e possuem o mesmo valorsemântico.

A expressão 0 (2.1b) denota um processo inerte, podendo representar um processoinativo, ou ainda um processo sequencial sem nenhum comportamento concorrenteobservável [Pierce, 1995]. Sob essa perspectiva é interessante observar que π-calculusexiste fundamentalmente no nível de orquestração de processos, sem considerar asatividades sequenciais internas de cada um dos processos [Parrow, 2001].

As expressões ax.P (2.1c) e a(x).P (2.1d) denotam respectivamente processos quetransmitem e recebem uma mensagem x pelo canal a, e depois se comportam como P .Tanto na transmissão quanto na recepção, o processo é bloqueado até que a comuni-cação tenha sido concluída, ou seja, a comunicação é síncrona [Pierce, 1995].

A expressão P | Q (2.1e) denota a composição paralela de dois processos P e Q quesão avaliados simultaneamente, possivelmente trocando mensagens entre si. A com-posição é o principal mecanismo que permite expressar comportamentos concorrentesem π-calculus. Observa-se pela equação (2.2a) que processos inertes podem ser des-prezados sem comprometer o significado da expressão. Além disso a composição deprocessos é comutativa (2.2b) e associativa (2.2c).

A expressão de restrição (γx)P (2.1f) denota um processo que se comporta como Pem um contexto em que x é um novo canal, diferente de qualquer outro canal presenteem P . Essa expressão permite declarar explicitamente novos canais, independente daexistência de outro canal que porventura venha a ter o mesmo nome.

A restrição permite extrusão de escopo (2.2d), ou seja, uma expressão de restriçãopode ser movida para um escopo mais externo sem comprometer o significado da ex-pressão, desde que observadas eventuais colisões de nomes. Restrições são comutativas(2.2e), além disso, uma restrição pode ser descartada se estiver sendo aplicada somentea um processo inerte (2.2f), tendo em vista que o novo canal declarado nunca seriausado.

Page 42: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

16 Capítulo 2. Fundamentos Teóricos

Por fim, a expressão !P (2.1g) denota um processo que se comporta como P e, emseguida, se comporta como !P novamente, e assim por diante, indefinidamente. Comomostra (2.2g), uma replicação pode ser substituída por uma ocorrência do processoseguido pela própria replicação, efetivamente permitindo que uma expressão se estendainfinitamente quando necessário.

Como pode ser visto em (2.3a), semanticamente, toda a computação em π-calculusocorre pela transmissão de mensagens de um processo para o outro. O exemplo abaixoilustra um cenário produtor-consumidor:

ax.x(w).0 | a(y).yz.0 (2.4a)

x(w).0 | xz.0 (2.4b)

0 | 0 (2.4c)

Nesse exemplo um processo transmite x pelo canal a, aguarda uma mensagem w

pelo próprio canal x e então fica inerte. Enquanto isso, em paralelo, outro processoaguarda uma mensagem y pelo canal a, transmite z pelo canal y recebido e então ficainerte [Parrow, 2001].

No primeiro passo (2.4a) ocorre a transmissão de x de um processo para o outro,conforme a equação (2.3a). Com isso, no processo receptor, o canal y é substituído porx. Tanto a expressão de transmissão quanto a recepção são consumidas.

No segundo passo (2.4b) o canal x (originalmente chamado y) é usado para trans-mitir z para o outro processo que aguarda a recepção de w nesse canal. Assim w noprocesso receptor será substituído por z e tanto a expressão de transmissão quanto ade recepção são consumidas.

O que nos leva ao terceiro e último passo (2.4c) onde restam somente dois processosinertes, não restando mais nenhuma computação possível.

π-calculus, assim como outras álgebras de processo, busca prover ao campo da pro-gramação paralela e concorrente o mesmo tipo de rigor e formalismo que λ-calculusprovê à programação sequencial. Dispondo de um conjunto mínimo de construções,π-calculus permite o estudo formal das propriedades fundamentais de sistemas concor-rentes.

Vale destacar também que π-calculus tem o mesmo poder computacional de λ-calculus, ou seja, π-calculus é Turing completa e representa um modelo universal decomputação [Milner, 1992]. Além disso, há um extenso corpo de trabalho relacionadoa π-calculus sendo um modelo bastante utilizado e estudado.

Contudo, π-calculus se baseia em canais de comunicação síncronos, ou seja as ope-rações de envio e recebimento de uma mensagem encapsulam a transmissão, recepção,

Page 43: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.2. Join-Calculus 17

roteamento e sincronização dessa mensagem de maneira atômica [Fournet & Gonthier,1996].

Em um ambiente onde os elementos computacionais podem estar espacialmentedistantes, onde problemas de falhas e latências precisam ser considerados, garantiruma interação atômica entre transmissor e receptor pode não ser uma opção viável.Assim encapsular essa interação como uma operação atômica passa a ser indesejável.Muito embora isso possa ser tratado em π-calculus considerando o meio de transmissãocomo um processo, essa técnica pode aumentar a complexidade das equações.

2.2 Join-Calculus

Join-calculus foi desenvolvido como uma derivação assíncrona do π-calculus onde osconceitos de transmissão e sincronização estão desacoplados de modo que toda a sin-cronização possa ser feita localmente. Ou seja, trata-se de uma tentativa de proveruma álgebra de processos para comunicação assíncrona e distribuída, baseada em ummodelo formal bem definido e com propriedades conhecidas [Fournet & Gonthier, 2000].

O join-calculus é, em essência, a implementação algébrica de uma Máquina Abs-trata Química Reflexiva ou RCHAM (Reflexive CHemical Abstract Machine) [Wood &Eisenbach, 2004]. A RCHAM é um modelo de máquina abstrata proposto por Four-net & Gonthier [1996] que introduz os conceitos de localidade e reflexão na CHAM(CHemical Abstract Machine) proposta por Berry & Boudol [1992].

Esse modelo utiliza uma metáfora química para modelar processos concorrentes.Nessa metáfora, o estado do sistema é representado por uma solução química compostapor um multiconjunto de átomos em suspensão. Essa solução é governada por umconjunto de regras de reação que definem como os átomos irão interagir dentro dasolução [Berry & Boudol, 1992].

O conceito de átomo nesse modelo difere em alguns aspectos do seu conceito tradi-cional na química. A palavra átomo é usada aqui no sentido literal de uma partículaindivisível capaz de participar em reações químicas. Outras propriedades químicascomo estrutura atômica, valência ou conservação de massa não são relevantes para omodelo.

Considere como exemplo um dado sistema composto pelos átomos {A,B,C} e

Page 44: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

18 Capítulo 2. Fundamentos Teóricos

regido pelas regras:

R1 ≡ B & C . D,E (2.5a)

R2 ≡ X & E . F (2.5b)

R3 ≡ Y & A . G (2.5c)

R4 ≡ Y &D . H (2.5d)

Onde, informalmente, o operador & pode ser interpretado como “reage com” e ooperador . pode ser interpretado como “produz”. Dado nosso sistema exemplo, vemosque a solução possui todos os átomos necessários para reação R1 (2.5a). Desse modo,ao ser desencadeada, a reação R1 (2.5a) consome os átomos B e C, substituindo-ospelos átomos D e E. Essa reação é demonstrada na Figura 2.1.

A B C R1 A D E

Figura 2.1. Uma reação na RCHAM

Nesse ponto, podemos observar que não há mais nenhuma regra de reação que possaser aplicada. Dessa forma consideramos a solução inerte, e ela permanecerá assim atéque novos átomos sejam adicionados à mesma.

Introduz-se então na solução o átomo X. A introdução de X irá desencadear areação R2 que irá consumir os átomos E e X é ira produzir o átomo F . Essa reação édemonstrada na Figura 2.2.

A D E R2 A D F

X

Figura 2.2. Adição de um átomo na RCHAM

Novamente, a solução está em um estado inerte e permanecerá assim até que novosátomos sejam introduzidos.

Por fim, introduz-se o átomo Y . Como pode ser observado, a introdução do átomoY tem o potencial de desencadear duas reações distintas, R3 e R4. Conforme Fournet& Gonthier [2000], por definição, um átomo só pode ser consumido por uma única

Page 45: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.2. Join-Calculus 19

reação. A estratégia de escolha de qual reação deverá ocorrer não é parte do modelo eé deixado como uma decisão de implementação. Dessa forma, embora não seja possívelprever no nosso exemplo qual reação irá ocorrer, podemos afirmar que apenas uma dasduas reações possíveis irá ocorrer. Essa reação é demonstrada na Figura 2.3

D F G R3 A D F R4 A F H

Y

Figura 2.3. Reação não-determinística da RCHAM

Novamente, deixando a solução em um estado inerte.Uma expressão em join-calculus é composta por processos, padrões join e definições.

Como o π-calculus todos os valores são nomes. A notação x representa uma tuplax1, x2, x3, . . . , xn e o operador join é representado pelo símbolo &. Dessa forma Odersky[2000] define formalmente Join-Calculus como:

Sintaxe

Nomes a, b, c, . . . , x, y, z Canais (2.6a)

Processos P,Q,R ≡ x(v) Transmissão (2.6b)

‖ def D;P Definição (2.6c)

‖ P &Q Composição (2.6d)

Padrões join J,K ≡ x(v) Mensagem (2.6e)

‖ J &K Join (2.6f)

Definições D,E, F ≡ J = P Reação (2.6g)

‖ D,E Definição composta (2.6h)

Page 46: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

20 Capítulo 2. Fundamentos Teóricos

Congruência Estrutural

Definição (2.6c) def D; def E;P ≡ def D,E;P (2.7a)

(def D;P ) &Q ≡ def D;P &Q (2.7b)

Composição (2.6d) P &Q ≡ Q& P (2.7c)

P & (Q&R) ≡ (P &Q) &R (2.7d)

Definição composta (2.6h) D,E ≡ E,D (2.7e)

D, (E,F ) ≡ (D,E), F (2.7f)

Semântica

def J = P,D; J &Q⇒ def J = P,D;P &Q (2.8a)

Um processo pode ser a emissão de uma mensagem (2.6b), uma definição de um novopadrão join (2.6c) ou uma composição de processos (2.6d), sendo que a composição deprocessos é comutativa (2.7c) e associativa (2.7d).

A emissão de uma mensagem (2.6b) disponibiliza a mesma para reagir com ou-tras mensagens de acordo com as definições existentes na expressão. Uma mensagempermanece na expressão até que forme um padrão join.

Uma vez que os processos são compostos (2.6d) usando o operador join, temos comoefeito que o envio de uma mensagem não requer sua recepção imediata. É possívelcontinuar a avaliar a expressão mesmo que uma mensagem permaneça nesta expressãoindefinidamente. Dessa forma, a emissão de uma mensagem constitui uma operaçãoassíncrona dentro do join-calculus.

Em um processo, duas ou mais definições podem ser agregadas, formando uma únicadefinição composta (2.7a). Além disso as definições permitem extrusão de escopo (2.7b)de modo que o escopo da definição pode ser estendido dinamicamente para incorporaroutros elementos. Em ambos os casos devem ser observadas eventuais colisões denomes.

Um padrão join é formado por uma mensagem (2.6e) ou um conjunto de mensagensligadas pelo operador join (2.6f). Esse padrão descreve quais mensagens um processodeve emitir para desencadear uma reação (2.6g).

Por sua vez, uma definição, denota uma regra de reação (2.6g) ou uma composiçãode regras de reação (2.6h), sendo que essas definições compostas são comutativas (2.7e)

Page 47: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.2. Join-Calculus 21

e associativas (2.7f).Uma regra de reação (2.6g) descreve uma possível redução da expressão (2.8a).

Uma regra de reação é formada por um padrão join e um processo. Sempre que asmensagens presentes em uma expressão formem o padrão join de uma regra de reação,então essas mensagens podem ser substituídas pelo processo dessa regra. A avaliaçãode uma expressão em join-calculus se dá pela aplicação das regras de reação sobre ospossíveis padrões join presentes na mesma, sendo que as expressões não reagem atéque todas as mensagens de algum padrão join tenham sido emitidas [Itzstein, 2005].

Dada uma expressão qualquer, só existem duas reduções possíveis [Fournet &Gonthier, 2000]:

• Enviar uma mensagem por um canal

• Aplicar uma reação cujo padrão join esteja presente na expressão

Considere o exemplo de uma fila de impressão adaptado de Fournet & Gonthier[1996]:

Seja:

D ≡ ready(p) & job(j) = print(p, j) (2.9a)

E ≡ print(p, j) = ready(p) (2.9b)

São definidas acima duas regras de reação denominadas D (2.9a) e E (2.9b).A primeira regra é composta pelo padrão join ready(p) & job(j) e o processo

print(p, j) e denota que, sempre que as mensagens ready(p) e job(j) estiverem presen-tes na expressão, essas podem ser substituídas pela mensagem print(p, j). A mensagemready(p) indica que a impressora p está disponível para impressão, a mensagem job(j)

indica que existe um trabalho de impressão j a ser realizado e a mensagem print(p, j)

indica que o trabalho de impressão j será impresso pela impressora p. Dessa formaa regra D diz que sempre que houver uma impressora disponível e um trabalho deimpressão a ser realizado, então esse trabalho deve ser enviado para ser impresso nessaimpressora.

A segunda regra, composta pelo padrão join print(p, j) e pelo processo ready(p),diz que sempre que uma impressora p tiver realizado um trabalho de impressão j, oque é indicado pela existência de uma mensagem print(p, j) na expressão, então essa

Page 48: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

22 Capítulo 2. Fundamentos Teóricos

impressora deverá ser disponibilizada para novos trabalhos de impressão, por meio damensagem ready(p).

Assim considere um sistema de fila de impressão que possui as regras D e E, umaimpressora p1 e no qual existam 2 trabalhos de impressão a ser realizados, j1 e j2:

spooler ≡ def D; def E;ready(p1) & job(j1) & job(j2) [ por (2.7a) ] (2.10a)

≡ def D,E; ready(p1) & job(j1) & job(j2) [ por (2.9a) ] (2.10b)

≡ def D,E; print(p1, j1) & job(j2) [ por (2.9b) ] (2.10c)

≡ def D,E; ready(p1) & job(j2) [ por (2.9a) ] (2.10d)

≡ def D,E; print(p1, j2) [ por (2.9b) ] (2.10e)

≡ def D,E; ready(p1) (2.10f)

No primeiro passo as regras D e E são compostas em uma única regra compostaD,E apenas como uma forma de higienizar a expressão e deixá-la mais simples.

No próximo passo a regra D é aplicada sobre as mensagens ready(p1) e job(j1)substituindo-as pela mensagem print(p1, j1), o que efetivamente envia o trabalho deimpressão j1 para ser impresso na impressora p1.

O próximo passo aplica a regra E à mensagem print(p1, j1) emitida no passo anteriore a substitui pela mensagem ready(p1) o que re-disponibiliza a impressora p1 para novostrabalhos de impressão.

O próximo passo aplica novamente a regra D, dessa vez às mensagens ready(p1)

e job(j2) que são substituídas na expressão pela mensagem print(p1, j2) que envia otrabalho j2 para impressão em p1.

O próximo e último passo aplica novamente a regra E e re-disponibiliza p1 paranovos trabalhos de impressão pela emissão da mensagem ready(p1).

Vale relembrar que o join-calculus, assim como o π-calculus, opera no nível de or-questração de processos. Em uma implementação real a mensagem print(p, j) provavel-mente desencadearia um processo sequencial que faria acesso ao hardware da impressorae executaria a impressão propriamente dita.

É importante observar também que o mesmo conjunto de regras de reação é apli-cável para qualquer número de impressoras e trabalhos de impressão. Os recursoscompartilhados, no caso as impressoras e os trabalhos de impressão, são gerenciadospela própria estrutura de mensagens do join-calculus que garante a alocação apropri-ada dos mesmos de acordo com as regras de reação. Isso pode ser melhor observado

Page 49: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.2. Join-Calculus 23

no exemplo a seguir onde são utilizadas duas impressoras simultaneamente:

≡ def D,E; ready(p1) & ready(p2) & job(j1) & job(j2) [ por (2.7c) ] (2.11a)

& jobj3

≡ def D,E; ready(p1) & job(j1) & ready(p2) & job(j2) [ por 2 × (2.9a) ] (2.11b)

& jobj3

≡ def D,E; print(p1, j1) & print(p2, j2) & job(j3) [ por 2 × (2.9b) ] (2.11c)

≡ def D,E; ready(p1) & ready(p2) & job(j3) [ por (2.9a) ] (2.11d)

≡ def D,E; ready(p1) & print(p2, j3) [ por (2.9b) ] (2.11e)

≡ def D,E; ready(p1) & ready(p2) (2.11f)

Nota-se que tanto em (2.11b) quanto em (2.11c) existe a aplicação simultânea dasregras de reação. Apesar disso, em ambos os casos, a alocação dos recursos compar-tilhados, é feita de forma atômica. As mensagens que compõem um padrão join eos recursos que essas mensagens encapsulam são disponibilizados exclusivamente parauma única regra de reação.

Apesar de suas diferenças, o join-calculus é uma variação assíncrona do π-calculusque possui a mesma capacidade de expressão [Fournet & Gonthier, 2000]. Formalmenteo join-calculus conserva todas a propriedades do π-calculus, e acrescenta as seguintesrestrições:

• As construções para restrição de escopo, recepção e replicação são combinadasem uma única construção, a definição de regras;

• A comunicação só ocorre por meio de nomes definidos;

• para cada nome definido existe exatamente uma replicação.

Join-Calculus se apresenta como um formalismo expressivo e poderoso para ex-pressar computações paralelas e concorrentes. Sua estrutura dispõe fundamentalmentede processos que emitem mensagens. Essas mensagens são interpretadas e avaliadaspor regras de reação. Cada regra de reação, por sua vez, consome as mensagens quecompõem o seu padrão join, evitando assim que mais de uma regra seja aplicada si-multaneamente à mesma mensagem e garantindo que não haja o compartilhamentoindevido de recursos.

A analogia entre o join-calculus, composto por processos emitindo mensagens, eo paradigma orientado a objetos, onde toda a computação é realizada por meio de

Page 50: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

24 Capítulo 2. Fundamentos Teóricos

objetos emitindo mensagens, é bastante interessante. Adiciona-se a isso a pequenadiferença conceitual que separa a maneira como, no paradigma orientado a objetos, aemissão de uma mensagem desencadeia a execução de um método e, em join-calculus,a emissão de um conjunto de mensagens desencadeia uma regra de reação. Tudo issotorna o join-calculus um bom candidato para prover as bases para abstrações de altonível para programação concorrente em linguagens orientadas a objeto de propósitogeral [Itzstein, 2005].

2.3 Acordes

O acorde é uma construção de alto nível de abstração que permite modelar soluçõespara problemas de concorrência e sincronização em linguagens imperativas orientadasa objetos de uma maneira elegante e efetiva.

Acordes integram a estrutura conceitual do join-calculus ao paradigma imperativoorientado a objeto, permitindo expressar declarativamente por meio de padrões join osrelacionamentos de concorrência e as interações entre fluxos de execução paralelos.

Dessa forma as interações entre fluxos de execução paralelos são coordenados demaneira implícita, usando as regras de reação do join-calculus como mecanismo deorquestração de processos. Ou seja, sistemas baseados em acordes não requerem ogerenciamento explícito de fluxos de execução paralelos e de suas interações, sendo queinterações paralelas ocorrem sempre de acordo com as regras previamente declaradas.

Um sistema baseado em acordes consiste em um conjunto de classes dentre as quaisuma ou mais classes possuem pelo menos um acorde. Um acorde é composto por umaassinatura e um corpo. O corpo de um acorde é um bloco de código, composto por umconjunto de ações ou comandos. A assinatura de um acorde por sua vez consiste emum conjunto de fragmentos de acordes ligados pelo operador join. Um fragmento deacorde pode ser descrito como uma assinatura de método ou mensagem, sendo que umdado fragmento pode ser síncrono ou assíncrono [Petrounias et al., 2008].

Será utilizada a seguir uma sintaxe simplificada para acordes, derivada de Java,baseada no denominador comum de Benton et al. [2002] e Itzstein [2005]. Os mo-dificadores de acesso como public e private são omitidos. Fragmentos assíncronosnão possuem o tipo de retorno. O operador join será representado pelo símbolo “&”.Por convenção, os fragmentos assíncronos, se existirem, serão sempre os primeiros doacorde. Todas as demais construções mantêm seu significado usual.

Utilizando essa notação, uma classe que utiliza acordes pode ser descrita comomostra a Listagem 2.1

1 class ChordedClass {

Page 51: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.3. Acordes 25

2 int sync(int p1) & async1(int p2, int p3) & async2() {

3 return p1 + p2 + p3;

4 }

5 }

Listagem 2.1. Estrutura de um acorde

No exemplo acima temos a classe com acordes ChordedClass que possui um únicoacorde cuja assinatura é composta pelo fragmento síncrono sync(int p1) e os fragmen-tos assíncronos async1(int p2, int p3) e async2() e cujo corpo retorna a soma dosparâmetros p1,p2 e p3.

Uma instância de uma classe com acordes equivale a uma expressão em join-calculus.De maneira análoga um fragmento de acorde equivale a uma mensagem (2.6e) e ainvocação desse fragmento equivale ao envio dessa mensagem (2.6b). Cada acordeequivale a uma definição (2.6c) de uma regra de reação (2.6g), sendo que a assinaturado acorde equivale ao padrão join e o corpo equivale ao processo que a reação produz.

Um acorde possui no máximo um fragmento síncrono e quantos fragmentos assín-cronos quanto necessário. O tipo de retorno do fragmento síncrono determina o tipo dedado retornado pela execução do acorde. Fazem parte do escopo do corpo do acordetodos os parâmetros passados a cada um dos fragmentos do acorde [Wood & Eisenbach,2004].

Sempre que um fragmento de um acorde é invocado em uma dada instância daclasse que define esse acorde, considera-se que passa a existir uma invocação pendentepara aquele fragmento na referida instância. A execução de um acorde ocorre quandohá pelo menos uma invocação pendente para cada um dos fragmentos que compõem oacorde. Cada execução do acorde consome uma invocação pendente de cada um dosfragmentos daquele acorde [Petrounias et al., 2008].

A invocação de um fragmento assíncrono não retém o fluxo de execução que oinvoca. Por sua vez a invocação de um fragmento síncrono retém o fluxo de execução atéque uma execução de acorde consuma a invocação pendente desse fragmento síncrono[Wood & Eisenbach, 2004].

Seja x uma instância da classe ChordedClass apresentada na Listagem 2.1, considerea sequência de comandos apresentados na Tabela 2.1.

Nesse exemplo temos um total de sete invocações, sendo que a quarta e sétimainvocação causam a execução do acorde. Sempre que o acorde é executado é consumidauma invocação pendente de cada fragmento. No fim uma invocação é deixada pendente.Vale ressaltar que, assim como em join-calculus, não há uma regra definida para qualinvocação pendente a execução do acorde irá consumir, ou seja, a invocação pendenteno fim pode ser qualquer uma das três invocações a x.async2().

Page 52: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

26 Capítulo 2. Fundamentos Teóricos

Invocações Pendentes Executa

Comando sync async1 async2 Acordex.async2() 0 0 1 -x.async1(1,2) 0 1 1 -x.async1(3,4) 0 2 1 -x.sync(5) 0 1 0 simx.async2() 0 1 1 -x.async2() 0 1 2 -x.sync(6) 0 0 1 sim

Tabela 2.1. Invocações

Partindo dessas definições podemos revisitar o exemplo da fila de impressão vistoanteriormente. Temos um conjunto de impressoras representadas pela classe Printer.Temos um conjunto de trabalhos de impressão representados pela classe Job. Cadatrabalho de impressão deve ser impresso em uma das impressoras uma única vez e umaimpressora é capaz de realizar um único trabalho de impressão por vez. Será criada umafila de impressão, representada pela classe Spooler descrita na Listagem 2.2, responsávelpor gerenciar as interações entre impressoras e trabalhos de impressão.

1 class Spooler {

2 ready(Printer p) & job(Job j) {

3 print(p, j);

4 }

5

6 print(Printer p, Job j) {

7 ready{p};

8 }

9 }

10

11 Spooler spooler = new Spooler();

12 Printer p1 = new Printer();

13 Job j1 = new Job();

14 Job j2 = new Job();

15

16 spooler.ready(p1);

17 spooler.job(j1);

18 spooler.job(j2);

Listagem 2.2. Fila de impressão

A classe Spooler é composta por dois acordes. O primeiro acorde, cujo padrão join

Page 53: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.3. Acordes 27

é composto pelos fragmentos assíncronos ready(Printer) e job(Job), é responsável porenviar trabalhos de impressão para as impressoras disponíveis. O segundo, contendosomente o fragmento assíncrono print(Printer, Job), re-disponibiliza a impressorapara novos trabalhos.

Após a declaração da classe com acordes temos a instanciação de quatro objetos,um objeto da classe Spooler chamado spooler que representa a fila de impressão. Umobjeto da classe Printer chamado p1 que representa uma impressora. E por fim doisobjetos da classe Job chamados j1 e j2 que representam dois trabalhos de impressão.

Esse sistema realiza três invocações de fragmentos de acordes, ou seja, ele envia trêsmensagens para a fila de impressão. A primeira é uma mensagem assíncrona ready(p1),que disponibiliza a impressora p1 para a fila de impressão. Essa invocação não causa aexecução do acorde e, sendo assíncrona, não bloqueia o fluxo de execução do sistema.

A segunda mensagem, job(j1), requer a impressão do trabalho j1 e a terceiramensagem, job(j2), requer a impressão do trabalho j2. Sendo ambas assíncronas,nenhuma dessas mensagens retém o fluxo de execução do sistema.

Paralelamente ready(p1) e job(j1) causam a execução desse acorde definido na filade impressão que, por sua vez irá invocar print(p1, j1). Ou seja, j1 será enviadopara impressão em p1. Após a impressão, a mensagem ready(p1) será enviada nova-mente à própria fila de impressão, pelo acorde print(Printer, Job), disponibilizandoa impressora p1 para novos trabalhos.

Isso causa nova execução do acorde devido ao join com a mensagem job(j2) quehavia sido invocada no fim do fluxo principal do sistema. Assim j2 também seráenviado para impressão e em seguida, novamente, ready(p1) disponibilizará p1 parafuturas impressões.

O código da fila de impressão apresentado não possui nenhuma sincronização oupooling explícitos. É escalonável para qualquer número de impressoras e trabalhosde impressão. Nenhum trabalho de impressão é enviado a uma impressora ocupada,nenhum trabalho é impresso mais de uma vez e todos os trabalhos serão impressos sehouver impressoras disponíveis.

Os acordes permitem expressar relações concorrentes complexas de maneira simples,direta e declarativa. Isso facilita a criação de sistemas altamente paralelos de maneiraclara e objetiva sem a necessidade de gerenciar explicitamente todas as interaçõespossíveis entre os processos.

A programação baseada em acordes apresenta diversas semelhanças com váriasoutras técnicas e metodologias empregadas no desenvolvimento de sistemas paralelose concorrentes.

O acorde se assemelha, sob certos aspectos, a um conjunto de semáforos interliga-

Page 54: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

28 Capítulo 2. Fundamentos Teóricos

dos, ou ainda, a uma forma restrita de comandos guardados [Dijkstra, 1975]. Sendoque o acorde provê, adicionalmente, um mecanismo de gestão implícita de recursoscompartilhados.

O modelo estrutural de acordes apresenta também diversas semelhanças com mo-delos baseados em espaços de tuplas como Linda [Valente, 2002]. Sendo que acordes sedestina principalmente a coordenação de processos leves, ao passo que Linda se destinaprincipalmente a coordenação de processos pesados.

A programação baseada em acordes é um novo paradigma para o desenvolvimentode sistemas paralelos e concorrentes. É possível demonstrar que muitas das construçõesde sincronização normalmente usadas na programação baseada em threads pode sercodificada por meio de acordes.

A exclusão mútua ou mutex é uma construção ou algoritmo que impede que doisprocessos concorrentes executem uma dada porção de código. O mutex deve garantirque em um dado momento, somente um processo tenha acesso à região crítica. Mutexespodem ser implementados quase que diretamente usando acordes, como pode ser vistona Listagem 2.3.

1 class Mutex {

2 Mutex() {

3 unlock();

4 }

5

6 void lock() & unlock() {

7 criticalRegion();

8 unlock();

9 }

10 ...

11 }

Listagem 2.3. Mutex

Como pode ser observado na Listagem 2.3, a classe Mutex, ao ser instanciada, in-voca o fragmento assíncrono unlock(). A existência de uma chamada pendente a essefragmento indica que nenhum processo está executando a região crítica. O fragmentosíncrono lock() é invocado sempre que um determinado processo precisa executar aregião crítica.

Se existe uma chamada pendente à unlock() e um processo solicita a execução daregião crítica por meio do fragmento lock(), então o padrão join lock()& unlock() iráconsumir os dois fragmentos e causar a execução do acorde que irá executar a regiãocrítica e, em seguida, invocar novamente o fragmento unlock(). Por outro lado, a

Page 55: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.3. Acordes 29

inexistência de uma chamada pendente à unlock() fará com que qualquer processo queinvoque lock() seja bloqueado até que uma chamada a unlock() seja feita, o que, comojá foi citado, só ocorre no momento em que um processo deixa a região crítica.

Semáforos são, em essência, uma generalização dos mutexes. Enquanto um mutexpermite que um, e somente um, processo entre na região crítica, semáforos devempermitir que um certo número de processos acessem a região crítica simultaneamente.

A implementação de semáforos por meio de acordes, mostrada na Listagem 2.4, ébastante semelhante à implementação de mutexes exceto pelo fato que a instanciaçãode um semáforo irá invocar o fragmento unlock() tantas vezes quanto o número deprocessos que podem acessar simultaneamente a região crítica.

1 class Semaphore {

2 Semaphore(int n) {

3 for(int index = 0; index < n; ++index) {

4 unlock();

5 }

6 }

7

8 void lock() & unlock() {

9 criticalRegion();

10 unlock();

11 }

12 }

Listagem 2.4. Semáforo

Ao ser instanciado o semáforo invoca o fragmento assíncrono unlock(), n vezes. Onúmero de chamadas pendentes a esse fragmento indica quantos processos ainda podementrar na região crítica. Cada invocação ao fragmento síncrono lock() permite oubloqueia, de acordo com o padrão join lock()& unlock(), a um determinado processoo acesso à região crítica.

Hoare [1974] propôs monitores como forma de sincronização de processos que con-siste em estabelecer um token para cada recurso compartilhado sendo que somente oprocesso que detém o token para um determinado recurso poderá acessá-lo. Os moni-tores são hoje um dos principais mecanismos de sincronização adotados por linguagensde programação orientadas a objetos.

Em acordes o token pode ser representado por um fragmento assíncrono que énecessário para executar os acordes correspondentes ao recurso compartilhado.

1 class Monitor {

2 Monitor() {

Page 56: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

30 Capítulo 2. Fundamentos Teóricos

3 unlock();

4 }

5 method1() & unlock() {

6 runMethod1();

7 unlock();

8 }

9 method2() & unlock() {

10 runMethod2();

11 unlock();

12 }

13 ...

14 methodN() & unlock() {

15 runMethodN();

16 unlock();

17 }

18 }

Listagem 2.5. Monitor

No exemplo mostrado na Listagem 2.5 o fragmento unlock() representa o tokenpara as instâncias da classe Monitor. Ao ser instanciada, a classe Monitor invoca ofragmento unlock(), disponibilizando o token para qualquer processo que o requeira.Quando um processo invoca um dos métodos de Monitor o acorde relativo a esse métodoé executado, consumindo o token. Por consequência, qualquer outra invocação a umdos métodos de Monitor bloqueia o fluxo de execução até que uma nova chamada aunlock() seja realizada, o que deve ocorrer no fim da execução de cada um dos acordes.

Temos também a barreira, um mecanismo de sincronização que cria um “ponto deencontro” que sincroniza a execução de diversos processos. Cada processo que atinge abarreira deve ser bloqueado até que todos os processos, ou um subconjunto especificado,tenham atingido a barreira. Nesse momento todos os processos são desbloqueadossimultaneamente.

Em acordes, uma barreira pode ser implementada como mostra a Listagem 2.6.

1 class Barrier {

2 Barrier(int n) {

3 for(int index = 0; index < n; ++index)

4 {

5 process(index);

6 }

7 enter(n);

8 between();

Page 57: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.3. Acordes 31

9 leave(n);

10 }

11

12 async process() {

13 before();

14 ready();

15 after();

16 }

17

18 void enter(int n) {

19 expectEnter(n);

20 waitEnter();

21 }

22

23 void leave(int n) {

24 expectLeave(n);

25 waitLeave();

26 }

27

28 void ready() & expectEnter(int n) {

29 if (--n > 0) {

30 expectEnter(n);

31 } else {

32 allReady();

33 }

34 gone();

35 }

36

37 void gone() & expectLeave(int n){

38 if (--n > 0) {

39 expectLeave(n);

40 } else {

41 allGone();

42 }

43 }

44

45 void waitEnter() & allReady() {}

46 void waitLeave() & allGone() {}

47

48 }

Page 58: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

32 Capítulo 2. Fundamentos Teóricos

Listagem 2.6. Barreira

No exemplo da Listagem 2.6, cada processo é representado por uma chamada aométodo assíncrono process(int). Cada processo invoca o método before(), que éexecutado antes de atingir a barreira, seguido pelo fragmento síncrono ready(), querepresenta a barreira propriamente dita, seguido pelo método after(), que é executadoapós a barreira.

Ao ser instanciada a classe Barrier inicia cada um dos processos e, em seguidainvoca o método enter(int), especificando o número de processos que a barreira devereter. O método enter(int) invoca o fragmento síncrono waitEnter(), que bloqueiaaté que todos os processos tenham entrado na barreira.

Na sequência o método between() é executado, o que corresponde ao momento emque todos os processos estão bloqueados na barreira e antes de qualquer um deles serliberado para continuar a executar.

Por fim a chamada ao método leave(int) libera os processos para que continuemsua execução. Análogo ao método enter(int), leave(int) invoca o fragmento síncronowaitEnter() que bloqueia até que todos os processos tenham saído da barreira.

O acorde ready()& expectEnter(int) sincroniza a entrada dos processos na bar-reira, por meio do fragmento síncrono ready() e pelo número de processos especificadopelo fragmento assíncrono expectEnter(int). Quando todos os processos atingem abarreira esse acorde invoca o fragmento assíncrono allReady() que por sua vez permitea execução do acorde waitEnter()& allReady(), o que irá desbloquear a invocação aofragmento síncrono waitEnter() feita pelo método enter(int) na instanciação da classeBarrier.

De maneira análoga o acorde void gone()& expectLeave(int) sincroniza a saída dosprocessos da barreira por meio do fragmento síncrono gone() e pelo número de processosespecificado em expectLeave(int). Quando todos os processos saírem da barreira esseacorde invoca o fragmento assíncrono allGone() que permite a execução do acorde voidwaitLeave()& allGone() que desbloqueia o fragmento síncrono waitLeave() invocadopelo método leave(int) na instanciação da classe Barrier.

É importante destacar que, muito embora os mecanismos de sincronização tradi-cionais possam ser emulados por meio de acordes, este não é o uso mais adequadodessa técnica, uma vez que os acordes oferecem um repertório diversificado e flexível depadrões de sincronização que podem ser aplicados de maneira mais específica a cadasituação.

Em resumo, álgebras de processo como join-calculus são amplamente usadas paraanalisar, especificar e verificar sistemas paralelos e concorrentes [Pierce, 1995] Fournet

Page 59: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

2.4. Conclusões 33

& Gonthier [1996]. O acorde, sendo derivado diretamente do join-calculus, se bene-ficia amplamente dessa solidez conceitual e integra-se bem no paradigma imperativoorientado a objetos, oferecendo uma forma elegante e eficaz de solucionar uma gamade problemas práticos de concorrência e paralelismo.

2.4 Conclusões

Formalismos como π-calculus e join-calculus fornecem abstrações elegantes para ex-pressar paralelismo e concorrência. O π-calculus é uma álgebra de processos ampla-mente utilizada para descrever o comportamento paralelo de processos concorrentes[Pierce, 1995]. Join-Calculus por sua vez é uma derivação assíncrona do π-calculus queequivale ao π-calculus em termos de poder computacional e simplifica a expressão decenários que envolvem comunicações assíncronas entre processos distribuídos [Fournet& Gonthier, 1996].

O acorde é uma forma de implementar as construções do join-calculus em linguagensde programação imperativas orientadas a objetos, que busca transpor da esfera teóricapara a prática do desenvolvimento de software a elegância conceitual desta algebra deprocessos.

Os acordes fornecem um mecanismo de orquestração de processos que permite ex-pressar as regras de interação entre processos declarativamente. Os acordes especificampadrões join que descrevem padrões de mensagens necessárias à execução de determi-nadas seções de código, encapsulando assim o protocolo de execução dessas seções,assim como a gestão de recursos compartilhados.

Dessa forma o desenvolvimento de sistemas baseados em acorde encapsula sensivel-mente a complexidade normalmente presente em sistemas concorrentes, uma vez que épossível abstrair o gerenciamento explícito de interações e recursos entre fluxos parale-los de execução em favor de regras declaradas explicitamente e impostas implicitamentepela implementação de acordes.

Page 60: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 61: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 3

Acordes em Java

Nesse capítulo introduz-se a biblioteca para programação paralela e concorrente ba-seada em acordes chamada JChords. Essa biblioteca foi desenvolvida nesse trabalhocomo uma tentativa de introduzir a programação baseada em acordes na linguagemJava por meio de uma biblioteca externa e que, consequentemente, pudesse ser usadaem um ambiente Java padrão.

É analisado o contexto geral onde JChords está inserida. São estabelecidos osrequisitos da biblioteca de acordo com os objetivos que ela deve cumprir. É dada umavisão geral dos recursos e técnicas que serão utilizados para atender a esses requisitos.E também é feita uma avaliação das principais limitações que o desenho da soluçãoimpõe.

São apresentados os detalhes do desenho da biblioteca e detalhados os seus princi-pais conceitos e como estes interagem para suportar a programação baseada em acordespor meio de biblioteca em Java.

Por fim são analisados casos de uso selecionados que demonstram o uso prático dasprincipais funcionalidades de JChords assim como permite a análise comparativa entresistemas baseados em acordes e seus equivalentes baseados em threads.

3.1 Contexto

A programação baseada em acordes é uma técnica bastante nova e que provavelmenteirá amadurecer ao longo do tempo. A introdução de acordes no ecossistema Java,para ser efetiva, deve encorajar a experimentação e permitir refinamentos e evoluções.Além disso, deve prover um caminho migratório gradual, que permita a convivênciaharmoniosa com sistemas legados.

Propõe-se o desenvolvimento da biblioteca JChords. JChords disponibilizará osrecursos necessários para programação concorrente baseada em acordes em ambientes

35

Page 62: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

36 Capítulo 3. Acordes em Java

Java padrão. Dessa forma JChords deverá integrar harmoniosamente o ecossistemaJava existente e, da maneira menos intrusiva possível, prover um caminho de transiçãogradual da programação sequencial ou baseada em threads para programação baseadaem acordes.

3.1.1 Requisitos

A plataforma Java possui uma vasta base de código instalado, além de dispor de umaampla gama de ferramentas de desenvolvimento. Dessa forma JChords foi concebidabuscando introduzir o conceito de acordes em Java de maneira transparente, intera-gindo harmoniosamente com códigos e sistemas legados bem como ser compatível comos recursos e ferramentas de desenvolvimento atualmente disponíveis.

A Sun Microsystems é a criadora e, até hoje, principal mantenedora da linguagemJava. O conjunto de ferramentas de desenvolvimento Java (JDK) desenvolvido pelaSun é o padrão de-facto no que toca a forma, recursos e desempenho. Assim sendo,JChords foi desenvolvida como uma biblioteca compatível com JDK da Sun. Comisso, busca-se permitir que a programação concorrente baseada em acordes possa serexposta a um universo mais amplo de usuários e sistemas.

Como parte do JDK, temos a cadeia de ferramentas Java que é formada pelo con-junto fundamental de ferramentas necessárias para transformar o código fonte escritopelo desenvolvedor em uma aplicação executável. Isso inclui compiladores, otimizado-res, etc. Por ser uma peça fundamental no processo de produção de software, a cadeiade ferramentas Java precisa ser estável, robusta e madura. Qualquer componente in-troduzido nessa cadeia precisa manter o mesmo padrão de estabilidade e robustez, sobpena de comprometer toda a cadeia.

Portanto, a introdução de ferramentas experimentais e potencialmente instáveis nacadeia de ferramentas Java é desaconselhável de modo geral e inviável em ambientesde produção. Por isso, JChords foi desenvolvida para não utilizar pré-compiladoresou etapas adicionais na cadeia de ferramentas Java, podendo ser integrado de maneiratransparente com a infra-estrutura existente.

Além do conjunto fundamental de ferramentas, a plataforma Java dispõe de umavasta biblioteca de classes padrão e de um diversificado ecossistema de bibliotecasexternas, além de inúmeras ferramentas e ambientes de desenvolvimento. Deseja-seencorajar a incorporação gradual de acordes no ferramental conceitual dos desenvolve-dores. Permitindo aos mesmos optar por usar acordes quando estes forem apropriados,ou recorrer a outras opções quando, por quaisquer razões técnicas ou gerenciais, o usode acordes não for apropriado. Assim JChords deverá integrar e interagir com o fer-ramental Java existente de maneira transparente, incluindo o sistema tradicional de

Page 63: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.1. Contexto 37

Threads.Em suma, para atingir seus objetivos, JChords deve cumprir os seguintes requisitos:

• Compatibilidade com Java Development Kit (JDK) da Sun Microsystems.

• Não introduzir novas dependências na cadeia de ferramentas Java.

• Coexistir com recursos, ferramentas e bibliotecas existentes.

Como já foi observado, a programação baseada em acordes é um conceito relativa-mente novo. Uma eventual transição da programação sequencial ou baseada em threadspara programação baseada em acordes só será viável se for feita de forma gradual eintegrada, para isso JChords precisa ser tão não-intrusiva quanto possível tanto noâmbito do código fonte quanto da infra-estrutura de desenvolvimento, encorajando ouso, experimentação e a evolução de seus conceitos.

3.1.2 Recursos

A inclusão de acordes em Java impõe uma série de demandas sintáticas e semânticas.É necessário prover meios de expressar padrões join, métodos assíncronos e construçõesauxiliares dentro da sintaxe da linguagem. É necessário também ajustar a semânticada linguagem de modo a prover os significados apropriados aos acordes.

Atender a essas demandas cumprindo os requisitos apresentados, portanto semmodificar o compilador Java, e ainda mantendo um nível de conforto apropriado adesenvolvedores Java, requer uma abordagem diferenciada que demanda ferramentasavançadas e recursos recentes. Alguns somente disponíveis a partir de Java versão 5[Gosling et al., 2005]. Dentre os recursos utilizados em JChords, os mais significativossão:

• Anotações.

• Reflexão.

• Instrumentação.

• ASM: Biblioteca de Manipulação de Bytecode.

Anotações [Buckley, 2004][Sun Microsystems, 2007] é um dos recursos introduzidosna versão 5.0 da linguagem Java. As Anotações permitem associar meta-dados aos di-versos elementos da linguagem como classes, métodos, campos, e até outras anotações.

As anotações por si só não afetam a semântica de um programa. Contudo asanotações podem ser processadas por meio de processadores de anotações anexados

Page 64: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

38 Capítulo 3. Acordes em Java

ao compilador. Podem ainda ser armazenadas nas classes compiladas (bytecodes) einspecionadas via reflexão.

Em JChords as anotações são o principal meio pelo qual os elementos sintáticos ne-cessários a programação baseada em acordes são introduzidos no código. As anotaçõesmarcam os elementos chave do sistema e armazenam as informações complementaresque permitem a atuação dos demais componentes da biblioteca.

As anotações, assim como os demais componentes do programa são acessados deduas maneiras. A primeira delas é por meio da API de reflexão integrante da bibliotecapadrão Java [Sun Microsystems, 2007]. Essa API possibilita que um programa acesse,inspecione e manipule sua própria estrutura. Dessa forma, ela permite que os diversoscomponentes de tempo de execução de JChords obtenham acesso aos elementos do có-digo original e possam atuar sobre eles de maneira a prover o comportamento requeridopela biblioteca.

A outra maneira utilizada para acessar os componentes do programa é a manipu-lação de bytecode. Isso é possível por meio da API de instrumentação de aplicaçõesintroduzida na biblioteca padrão do Java 5 e da biblioteca de manipulação de bytecodeASM [Bruneton, 2007].

A API de instrumentação permite anexar agentes à máquina virtual Java. Dentreoutras funcionalidades, esses agentes são capazes de intervir no processo de leitura dosarquivos “.class” do dispositivo de armazenamento para a memória da JVM.

A biblioteca ASM por sua vez é capaz de interpretar as sequências de bytes quecompõem os arquivos “.class”, disponibilizados pela API de instrumentação e, utilizandoo padrão Visitor [Gamma et al., 1995], possibilita a manipulação dos bytecodes antesque esses sejam carregados na JVM.

O conjunto dessas funcionalidades provê um framework efetivo para a construçãodo suporte a acordes em Java sem a necessidade de alterar a linguagem ou o compi-lador. As anotações permitem estender a sintaxe ao passo que a reflexão possibilitaa criação de semânticas adaptáveis que podem ser implantadas dinamicamente viainstrumentação e manipulação de bytecodes.

3.1.3 Limitações

Apesar de bastante versátil, a metodologia proposta apresenta algumas limitações,inerentes a decisão de implementar acordes por meio de uma biblioteca. Contudo, éesperado que os benefícios dessa abordagem superem as limitações que ela impõe.

Uma dessas limitações é a necessidade de se adequar a sintaxe padrão Java. Muitoembora as anotações nos permitam anexar ao programa uma infinidade de atributospara os mais diversos usos, muito pouco pode ser feito em relação ao restante da

Page 65: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.2. Desenho 39

sintaxe. Um programa Java baseado em acordes precisa, antes de mais nada, ser umprograma Java padrão válido. Ainda que a manipulação de bytecodes nos confira umalto grau de liberdade quanto a semântica do sistema, essa liberdade de nada valeaté que o compilador tenha sido capaz de produzir classes compiladas que possam sermanipuladas. E isso só é possível a partir de códigos fonte sintaticamente válidos.

Outra limitação significativa é a impossibilidade de validar a priori a notação deacordes. Na maioria das linguagens de programação, uma das principais tarefas dointerpretador ou compilador é detectar e reportar erros que possam existir no programa.Apesar de reduzida, a notação necessária para o suporte a acordes em Java possui regrase diretrizes que devem ser obedecidas. Como foi visto anteriormente, anotações sãoelementos passivos, incapazes de ativamente detectar ou reportar erros na notação deacordes. Assim, JChords não dispõe, na implementação atual, de meios para detectaresses erros até o momento em que o modulo de manipulação de bytecodes seja acionado,o que só ocorre já em tempo de execução.

Em essência, as limitações expostas se traduzem, de modo geral, na necessidadede construções auxiliares que seriam desnecessárias em uma implementação nativa deacordes.

3.2 Desenho

Acordes são construções compostas por um padrão join, que é um conjunto de men-sagens ou fragmentos unidos pelo operador join (&), e um método ou corpo que de-clara quais ações estão associadas a esse padrão. Partindo da notação proposta naSeção 2.3 podemos descrever um buffer de inteiros utilizando acordes como mostra aListagem 3.1.

1 class Buffer {

2 int get() & put(int var) {

3 return var;

4 }

5 }

Listagem 3.1. Pseudo-Código de buffer com acordes

Muito embora a notação proposta já mantenha muitas semelhanças a um programaJava é necessário adaptar alguns dos elementos apresentados para conformar com asintaxe Java e para viabilizar o processamento por JChords.

Em JChords, toda classe que utiliza acordes deve ser marcada com a anotação@Chorded. Essa marcação permite à biblioteca identificar classes que precisam ser

Page 66: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

40 Capítulo 3. Acordes em Java

manipuladas para incorporar o sistema de acordes. Dessa forma a primeira linha doexemplo passa a ser igual à Listagem 3.2.

1 @Chorded class Buffer ...

Listagem 3.2. Buffer com acordes em JChords

Por sua vez o padrão join apresentado não representa um trecho de código válidona linguagem Java. Por isso, em JChords, os acordes propriamente ditos são métodosconvencionais, anotados com @Join. A anotação recebe como parâmetros as assinaturasdos fragmentos que irão compor o padrão join desse acorde. Esse será o métodochamado quando for detectado um padrão join completo nesse objeto. Assim podemosre-escrever nosso exemplo da seguinte forma:

1 @Chorded class Buffer {

2 @Join({ "int get()", "void put(int)" })

3 int get_put(int var) {

4 return var;

5 }

6 }

Listagem 3.3. Buffer com join em JChords

O exemplo re-escrito já é um programa Java sintaticamente válido. Contudo in-vocações como obj.put(0) para uma instancia obj da classe Buffer seriam inválidasvisto que, do ponto de vista do Java padrão a classe Buffer não declara um métodoput(int).

Assim faz-se necessário declarar os métodos representativos dos fragmentos doacorde dentro da classe Buffer de modo que as invocações dos fragmentos de acordessejam invocações válidas em Java padrão. Introduzir-se-a também os modificadores deacesso que estavam sendo omitidos até então. Assim re-escrevemos mais uma vez nossoexemplo como mostrado na Listagem 3.4.

1 @Chorded public class Buffer {

2 @Async public void put(int val) {}

3 @Sync public int get() { return Chords.result(int.class); }

4

5 @Join({ "int get()", "void put(int)" })

6 int public get_put(int var) {

7 return var;

8 }

9 }

Listagem 3.4. Buffer com JChords

Page 67: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.2. Desenho 41

Os métodos assíncronos são anotados com @Async. Eles servem para declarar osfragmentos assíncronos que poderão ser usados nos padrões join. Além disso, essesmétodos são executados fora do fluxo de execução de sua chamada. Métodos assíncro-nos são os elementos chave que provêm o caráter paralelo na programação baseada emacordes.

Os métodos síncronos são anotados por @Sync e servem para declarar os fragmentossíncronos que poderão compor os padrões join. Esses métodos, isoladamente, se com-portam de maneira idêntica a qualquer outro método em Java, ou seja, eles retém ofluxo de execução em que foram invocados até que sua execução tenha sido concluída.

Os métodos síncronos, ao contrário dos assíncronos que tem sempre o tipo de retornovoid, podem retornar valor. Contudo esse deve sempre ser o valor retornado pelo corpodo acorde. Assim o valor de retorno dos métodos síncronos será sempre dado por Chords.result().

Com isso temos a forma final da implementação de Buffer usando JChords.JChords implementa acordes em Java pela introdução de quatro elementos básicos,

cada um deles associado a uma anotação específica:

• @Chorded : Classes com Acordes

• @Async : Métodos Assíncronos

• @Sync : Métodos Síncronos

• @Join : Métodos Acordes

Um sistema baseado em acordes utilizando JChords compõe-se basicamente declasses com acordes que declaram métodos assíncronos e métodos síncronos que sãoempregados para compor os padrões join em métodos acordes.

3.2.1 Classes com Acordes

Classes com acordes são classes que suportam o uso de acordes. Adiciona-se o suportea acordes em uma classe pelo uso da anotação @Chorded, e somente classes anotadasdessa forma são instrumentadas para orquestrar acordes:

1 @Chorded public class ChordedClass {}

Listagem 3.5. Classe com acordes

As demais anotações não tem nenhum efeito prático se utilizadas em classes quenão tenham sido anotadas com @Chorded. Uma exceção são os métodos assíncronosque podem ser usados em classes com ou sem acordes, contudo, mesmo estes ficamdesprovidos de mecanismos de sincronização quando usados em classes sem acordes.

Page 68: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

42 Capítulo 3. Acordes em Java

Observe que nem todas as classes de um sistema concorrente baseado em acordesprecisam ser instrumentadas com suporte a acordes. Via de regra somente classes quepossuam pelo menos um método anotado com @Join deve ser anotada com @Chorded.

3.2.2 Métodos Assíncronos

Métodos assíncronos são métodos que são executados fora do fluxo de execução queos invocou. Da perspectiva do fluxo de execução que invoca o método assíncrono,esse método é instantâneo. Ou seja, ao contrário dos métodos normais, a chamada aométodo assíncrono marca a solicitação de sua execução e não a execução propriamentedita.

Os métodos assíncronos devem ser sempre, obrigatoriamente, do tipo void, ou seja,não devem possuir valor de retorno. Como visto anteriormente, a ligação entre ométodo assíncrono e o fluxo de execução que o invoca se encerra antes da execuçãodo método assíncrono. Com isso o método assíncrono simplesmente não tem a quemretornar um valor.

Um método poderá ser declarado assíncrono pela utilização da anotação @Async:

1 public class Example {

2 @Async public void foo() {}

3 }

Listagem 3.6. Método assíncrono

Vale ressaltar que os método assíncronos, por si só, podem substituir alguns dosusos mais simples de threads. O exemplo da Listagem 3.7 utiliza @Async para criar oequivalente a 5 threads paralelas:

1 public class Example {

2 @Async public void foo() {...}

3

4 public static void main(String[] args) {

5 Example example = new Example();

6 for (int index = 0; index < 5; ++index) {

7 example.foo();

8 }

9 System.out.println("fim");

10 }

11 }

Listagem 3.7. Exemplo de método assíncrono com JChords

Page 69: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.2. Desenho 43

Supondo que uma chamada a foo() requer 1 segundo para ser completada, seomitíssemos a anotação @Async esse programa demoraria 5 segundos antes de exibira mensagem fim na tela. Contudo, se executarmos o programa com a anotação, amensagem fim será exibida quase imediatamente, sendo que a execução do programasó terminará efetivamente alguns segundos depois.

A título de comparação a Listagem 3.8 mostra um programa equivalente usandothreads.

1 public class Example extends Thread {

2 public void run() {...}

3

4 public static void main(String[] args) {

5 for (int index = 0; index < 5; ++index) {

6 new Example().start();

7 }

8 System.out.println("fim");

9 }

10 }

Listagem 3.8. Exemplo de método assíncrono com threads

Para esse exemplo trivial, observe que a sintaxe usando threads ou métodos assín-cronos é bastante semelhante. Contudo para os casos onde houver mais de um métodoassíncrono, ou a necessidade de executá-los usando um único objeto a sintaxe de th-reads se torna menos prática. Isso pode ser visto comparando a Listagem 3.9 com aListagem 3.10.

1 public class AsyncExample {

2 @Async public void foo() {...}

3 @Async public void bar() {...}

4

5 public static void main(String[] args) {

6 AsyncExample example = new AsyncExample();

7 for (int index = 0; index < 5; ++index) {

8 example.foo();

9 example.bar();

10 }

11 }

12 }

Listagem 3.9. Exemplo complexo de métodos assíncronos com JChords

Page 70: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

44 Capítulo 3. Acordes em Java

1 public class ThreadExample {

2 public void foo() {...}

3 public void bar() {...}

4

5 public static void main(String[] args) {

6 final ThreadExample example = new ThreadExample();

7 for (int index = 0; index < 5; ++index) {

8 new Thread() {

9 public void run() { example.foo(); }

10 }.start();

11 new Thread() {

12 public void run() { example.bar(); }

13 }.start();

14 }

15 }

16 }

Listagem 3.10. Exemplo complexo de métodos assíncronos com threads

Vale ressaltar que os métodos assíncronos em JChords podem ser usados de maneiraindependente do restante da biblioteca. Observe que os exemplos acima não utilizamnenhum dos outros elementos disponibilizados pela biblioteca, apenas @Async.

Isoladamente, os métodos assíncronos já proporcionam uma alternativa interessantepara casos em que a sintaxe de threads é pouco prática. Contudo deve ser observadoque, por si só, os métodos assíncronos não possuem ferramentas de sincronização econtrole. Essa lacuna é preenchida pelos demais elementos da arquitetura. Em acordes,os métodos assíncronos são os elementos chave que desencadeiam o caráter paralelo dosistema.

3.2.3 Métodos Síncronos

Métodos síncronos são os meios pelos quais um sistema baseado em acordes poderecuperar os resultados de uma computação ou estabelecer os pontos de sincronizaçãodo sistema. Um método pode ser declarado síncrono pelo uso da anotação @Sync, comomostrado na Listagem 3.11.

1 @Chorded public class SyncExample {

2 @Sync public void foo() {}

3 }

Listagem 3.11. Método síncrono

Page 71: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.2. Desenho 45

De modo geral, é delegada aos métodos síncronos a tarefa de recuperar o resultadoda execução do acorde, por isso JChords deve prover meios de materializar esse resul-tado dentro do corpo do método síncrono. O método estático Chords.result(Class<T>)

provê o mecanismo para recuperar esse resultado. Ele recebe como parâmetro o objetoClass do tipo de resultado esperado. Via de regra, recuperar o resultado do acorde éa única operação que deve ser realizada em um método síncrono, visto que a lógica doacorde deve ficar no corpo do acorde e não nos fragmentos que o compõem.

1 @Chorded public class SyncExample {

2 @Sync public int bar() { return Chords.result(int.class); }

3 }

Listagem 3.12. Método assíncrono com valor de retorno

Os métodos síncronos possuem um caráter principalmente declarativo e em geralapenas declaram estruturas de código que serão utilizadas por outros elementos.

3.2.4 Métodos Acordes

Os métodos acordes são a construção fundamental de JChords. Eles são o meio peloqual os acordes são declarados e definidos em um sistema baseado em acordes. Nelesos padrões join são definidos e associados a um corpo de execução.

Os métodos acordes são anotados com @Join. Ao contrário das demais anotaçõesusadas até agora, @Join requer um arranjo de @strings como parâmetro. Cada umadas @strings é um descritor para um dos fragmentos de acorde que compõem o padrãojoin:

1 @Chorded public class Buffer {

2 ...

3 @Join({ "int get()", "void put(int)" })

4 public int get_put(int var) {

5 return var;

6 }

7 }

Listagem 3.13. Métodos acordes

O descritor de um fragmento é uma versão estilizada da assinatura do método.Ele é composto pelo tipo de retorno, o nome e uma lista separada por virgulas e entreparênteses dos tipos de dados dos parâmetros do método. Não são necessários os nomesdos parâmetros:

1 "Tipo NomeDoMetodo(Tipo1,Tipo2, ..., TipoN)"

Page 72: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

46 Capítulo 3. Acordes em Java

Listagem 3.14. Descritor de fragmento de acordes

A assinatura do método acorde deve respeitar algumas regras para que JChordspossa acessar corretamente o método acorde. É importante não confundir a assinaturado acorde com a assinatura do método acorde que o representa. A assinatura do acordeé dada pela anotação @Join e é composta pelos descritores dos fragmentos do acorde. Aassinatura do método acorde é a assinatura do método Java que será invocado quandoo padrão join daquele acorde for detectado.

O nome do método acorde é irrelevante, pode ser qualquer nome válido para um mé-todo. Por convenção, usa-se nesse trabalho a concatenação dos nomes dos fragmentosseparados por “_”.

O método acorde deve obrigatoriamente ser público, caso contrário JChords nãoserá capaz de invocá-lo via reflexão.

O tipo de retorno do método deve ser igual ao tipo de retorno do fragmento assín-crono se este existir, caso contrário deverá ser @void.

A lista de parâmetros do método acorde deve ser composta por todos os parâmetrosde todos os fragmentos do acorde na ordem em que são declarados. Os nomes dosparâmetros não são relevantes. O binding será feito levando em consideração o tipo ea ordem dos parâmetros.

3.3 Aplicação

Em geral, problemas em programação paralela e concorrente se referem a conjuntos deregras de interação que regem conjuntos de entidades que interagem entre si e compar-tilham recursos. Os acordes permitem a representação direta das regras de interaçãoassim como fornece formas seguras e efetivas de gerenciar os recursos compartilhados.

Assim, apresenta-se a seguir uma pequena seleção de problemas de programaçãoparalela e concorrente assim como soluções baseadas em acordes para os mesmos, uti-lizando JChords. Dessa forma busca-se explorar as capacidades da biblioteca assimcomo introduzir as noções básicas de desenvolvimento usando JChords.

3.3.1 Produtor/Consumidor

O problema do produtor-consumidor é um problema clássico de sincronização de pro-cessos. O problema consiste em sincronizar dois grupos de processos, produtores econsumidores, por meio de um buffer de tamanho finito.

Page 73: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 47

Os produtores produzem continuamente um determinado recurso que deve ser dis-ponibilizado aos consumidores por meio do buffer. Um produtor deve ser bloqueadoao tentar adicionar um recurso ao buffer enquanto este estiver cheio.

Os consumidores por sua vez consomem continuamente os recursos disponibilizadosno buffer. Um consumidor deve ser bloqueado ao tentar extrair um recurso do bufferenquanto este estiver vazio.

A implementação dos produtores e consumidores é bastante semelhante. Ambosconsistem em um laço que irá continuamente produzir um recurso e armazená-lo nobuffer ou extrair um recurso do buffer e consumí-lo.

Usando JChords podemos implementar a classe Buffer como mostrado na Lista-gem 3.15.

1 package usecases.producerconsumer.jchords;

2

3 import jchords.Chords;

4 import jchords.annotations.*;

5

6 @Chorded public class Buffer {

7 @Async public void value(int val) {}

8 @Async public void free() {}

9 @Sync public void put(int val) {}

10 @Sync public int get() { return Chords.result(int.class); }

11

12 public Buffer() {

13 for(int index = 0 ; index < Runner.BUFFER_SIZE; ++index) {

14 free();

15 }

16 }

17

18 @Join({"int get()", "void value(int)"}) public int get_value(int res) {

19 free();

20 return res;

21 }

22

23 @Join({"void put(int)", "void free()"}) public void put_free(int res) {

24 value(res);

25 }

26 }

Listagem 3.15. Classe Buffer

Page 74: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

48 Capítulo 3. Acordes em Java

O acorde get()& value(int) é responsável pela extração de elementos. Analo-gamente, o acorde put(int)& free() é responsável pela inclusão de elementos. Ofragmento free() representa um espaço livre no buffer, ao passo que o fragmentovalue(int) representa um espaço ocupado.

Instâncias de Buffer são inicializadas com tantas chamadas a free() quanto o nú-mero de elementos que o buffer deve comportar. A qualquer tempo, haverá no buffertantas chamadas pendentes ao fragmento free() quanto houver espaços livres e tantaschamadas pendentes ao fragmento value(int) quanto houver elementos armazenados,sendo que a soma de chamadas pendentes desses fragmentos será sempre igual à ca-pacidade do buffer. Isso porque o acorde que consome as chamadas a free() sempreinvoca value(int) e vice-versa.

Sempre que um consumidor deseja extrair elementos do buffer ele invoca o frag-mento get(). Existindo uma chamada pendente à value(int), então o acorde get()&

value(int) será executado. Caso contrário a chamada ao fragmento get(), que é umfragmento síncrono, irá bloquear o fluxo de execução até que value(int) seja chamado.

A execução do acorde get()& value(int) consome uma chamada pendente a get

() e uma a value(int). Esse acorde invoca free() que disponibiliza um espaço livreno buffer e retorna ao código que invocou o fragmento get() o valor passado comoparâmetro ao fragmento value(int).

Analogamente, sempre que um produtor deseja incluir elementos no buffer ele in-voca o fragmento put(int). Se houver uma chamada pendente à free() o acordeput(int)& free() é executado. Caso contrário put(int) bloqueia o fluxo de execuçãoaté uma chamada a free().

A execução do acorde put(int)& free() consome, pelo padrão join, uma chamadapendente a put(int) e uma a free(). Por fim, invoca o fragmento value(int) usandoo parâmetro passado ao fragmento put(int).

A título de comparação a Listagem 3.16 mostra a classe Buffer implementada emJava usando threads.

1 package usecases.producerconsumer.java;

2

3 public class Buffer {

4 private int count = 0;

5 private int[] resources = new int[Runner.BUFFER_SIZE];

6

7 public synchronized void put(int res) throws InterruptedException {

8 while (count == resources.length) {

9 wait();

10 }

Page 75: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 49

11 resources[count++] = res;

12 notifyAll();

13 }

14

15 public synchronized int get() throws InterruptedException {

16 while (count == 0) {

17 wait();

18 }

19 int res = resources[--count];

20 notifyAll();

21 return res;

22 }

23 }

Listagem 3.16. Classe Buffer

Vale observar que a implementação usando acordes abstrai o desenvolvedor do ge-renciamento de threads, notadamente o trio wait()/notify()/notifyAll(), e permitefocar nas regras do problema. De fato, os acordes são, em essência, traduções diretadas regras do problema:

• get()& value(int): Elementos só podem ser extraídos do buffer se houver ele-mentos no buffer, caso contrário bloqueia.

• put(int)& free(): Elementos só podem ser incluídos no buffer se houver espaçoslivres no buffer, caso contrário bloqueia.

Além disso os recursos compartilhados, no caso os recursos sendo produzidos econsumidos, ficam verdadeiramente protegidos, estando acessíveis somente às entidadesapropriadas, nos momentos e escopos apropriados.

3.3.2 Jantar dos Filósofos

O jantar dos filósofos é um problema clássico de concorrência. O problema consiste emcinco filósofos sentados ao redor de uma mesa. Sobre a mesa existem cinco garfos demodo que cada filósofo dispõe de dois garfos, cada garfo compartilhado com um de seusvizinhos. A vida de um filósofo se resume a pensar e comer macarrão. Cada filósofopensa por algum tempo, pega um garfo, depois o outro, come macarrão, devolve osgarfos e volta a pensar.

Apresentam-se duas soluções para o problema do jantar dos filósofos. A primeiraé a solução do garçom que consiste em criar um elemento central de controle que irá

Page 76: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

50 Capítulo 3. Acordes em Java

gerenciar os recursos. A segunda é uma solução totalmente distribuída proposta porChandy & Misra [1984], chamada solução higiênica.

3.3.2.1 A Solução do Garçom

A solução do garçom consiste em criar a figura de um garçom. Todos os filósofos pedempermissão ao garçom antes de pegar os garfos e informam ao mesmo quando devolvemos garfos. O garçom, tendo uma visão global do processo, pode coordenar os filósofosde maneira adequada.

A estratégia de gerenciamento adotada aqui para o garçom foi a de limitar o númeromáximo de filósofos disputando os recursos a quatro filósofos, ou seja, o total de filósofosmenos um.

Dessa forma, implementa-se o garçom por meio da classe Waiter apresentada naListagem 3.17.

1 package usecases.diningphilosophers.waiter.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Waiter {

6 @Sync public void enter() {}

7 @Async public void leave() {}

8

9 public Waiter() {

10 for (int index = 0; index < Runner.SEATS - 1; ++index) {

11 leave();

12 }

13 }

14

15 @Join({"void enter()", "void leave()"}) public void enter_leave() {}

16 }

Listagem 3.17. Classe Waiter

As instâncias da classe Waiter são inicializadas com quatro chamadas ao fragmentoleave(), ou seja, o número de filósofos menos um. O fragmento leave() representauma permissão para um filósofo pegar os garfos.

O acorde enter()& leave() simplesmente irá bloquear qualquer chamada a enter

() até que haja uma chamada pendente a leave(), dessa forma somente os quatroprimeiros filósofos que tentarem comer serão autorizados a tentar. O último filósofoserá obrigado a esperar até que um dos demais tenha terminado.

Page 77: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 51

Novamente a título de comparação a Listagem 3.18 mostra a classe Waiter imple-mentada em Java com threads.

1 package usecases.diningphilosophers.waiter.java;

2

3 public class Waiter {

4 private int count = Runner.SEATS - 1;

5

6 public synchronized void enter() throws InterruptedException {

7 while(count > 0) {

8 wait();

9 }

10 --count;

11 }

12

13 public synchronized void leave() {

14 ++count;

15 notifyAll();

16 }

17 }

Listagem 3.18. Classe Waiter

3.3.2.2 A Solução Higiênica

A solução higiênica para o problema do jantar dos filósofos foi proposta por Chandy& Misra [1984]. Nessa solução, cada garfo pode estar sujo ou limpo. Sempre que umfilósofo usa o garfo esse fica sujo. Um filósofo sempre limpa o garfo antes de emprestá-loa um vizinho, daí o nome solução higiênica. Sempre que tem fome um filósofo pedeemprestado aos vizinhos os garfos que não possua. Um filósofo não atende a pedidosde empréstimo de garfos enquanto estiver comendo.

Em relação a solução do garçom, a solução higiênica apresenta a significativa van-tagem de não depender de uma figura central de controle, consequentemente ela podeser aplicada em ambientes distribuídos. Além disso, exceto pela inicialização, ela ésimétrica, ou seja, assim como a solução do garçom, todos os filósofos são instânciasda mesma classe e compartilham a mesma implementação.

Assim, implementamos os filósofos por meio da classe Phil apresentada na Lista-gem 3.19:

1 package usecases.diningphilosophers.higienic.jchords;

2

Page 78: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

52 Capítulo 3. Acordes em Java

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.*;

5

6 @Chorded public class Phil {

7 private static int seed = 0;

8 public final int id = ++seed;

9

10 @Async public void requires(Phil phil) {}

11 @Async public void clean(Fork fork) {}

12 @Async public void dirty(Fork fork) {}

13 @Async public void request(Phil phil) {}

14 @Async public void hungry() {}

15 @Sync public void eating() {}

16

17 @Join({"void eating()", "void hungry()",

18 "void clean(usecases.diningphilosophers.higienic.jchords.Fork)",

19 "void clean(usecases.diningphilosophers.higienic.jchords.Fork)"})

20 public void eat_hungry(Fork left, Fork right) {

21 left.grab();

22 right.grab();

23 eat();

24 left.release();

25 right.release();

26 dirty(left);

27 dirty(right);

28 }

29

30 @Join({"void hungry()",

31 "void requires(usecases.diningphilosophers.higienic.jchords.Phil)"})

32 public void hungry_requires(Phil phil) {

33 hungry();

34 phil.request(this);

35 }

36

37 @Join({"void request(usecases.diningphilosophers.higienic.jchords.Phil)",

38 "void dirty(usecases.diningphilosophers.higienic.jchords.Fork)"})

39 public void request_dirty(Phil phil, Fork fork) {

40 requires(phil);

41 phil.clean(fork);

42 }

Page 79: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 53

43

44 @Async public void execute() {

45 while (true) {

46 think();

47 hungry();

48 eating();

49 }

50 }

51

52 private void eat() {

53 delay(5000, "Filósofo " + id + " comendo");

54 }

55

56 private void think() {

57 delay(1000, "Filósofo " + id + " pensando");

58 }

59 }

Listagem 3.19. Classe Phil

O ciclo de vida do filósofo consiste em invocar os métodos ou fragmentos think

(), hungry() e eating(). Desses, o fragmento assíncrono hungry() é responsável porestimular o filósofo a iniciar as ações necessárias para que este possa comer. Por suavez o fragmento síncrono eating() irá reter o fluxo de execução do filósofo até que eletenha todas as condições necessárias para comer.

O acorde eating()& hungry()& clean(Fork)& clean(Fork) será executado quandoo filósofo dispuser de todas as condições necessárias para comer. Ou seja, o filósofodeve estar com fome (hungry()), deve estar aguardando para comer (eating()) e deveter dois garfos disponíveis (clean(Fork) duas vezes). Ao executar esse acorde os doisgarfos usados ficam sujos, o que será sinalizado pela invocação dupla do fragmentodirty(Fork).

Vale ressaltar que a solução de Chandy & Misra [1984] não requer a disponibilidadede garfos limpos. Essa restrição foi usada apenas para simplificar o exemplo. Umaimplementação completa deve conter acordes para tratar casos onde haja um ou doisgarfos sujos.

Uma vez que o filósofo esteja com fome, mas não possua algum dos garfos, o acordehungry()& requires(Phil) emitirá solicitações aos filósofos para os quais este tenhaemprestado garfos. Uma solicitação é feita enviando o fragmento request(Phil) para ofilósofo recebido como parâmero ao fragmento requires(Phil). Além disso, é necessárioreinvocar o fragmento hungry() que foi consumido por esse acorde de modo que ele fique

Page 80: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

54 Capítulo 3. Acordes em Java

disponível para compor mais padrões join.Por fim, o acorde request(Phil)& dirty(Fork) é responsável por enviar o garfo a

algum filósofo solicitante, se o garfo estiver disponível. Esse acorde também registrapara qual filósofo o garfo está sendo emprestado invocando o fragmento assíncronorequires(Phil). Desse modo é possível solicitar o garfo de volta quando necessário.Além disso o garfo passa a estar limpo antes de ser enviado. Isso é feito pelo fragmentoclean(Fork) enviado ao filósofo requisitante.

Os garfos sujos e limpos criam uma ordem de precedência para o empréstimo dosgarfos. Isso evita que um filósofo empreste um garfo que ele tenha acabado de obter,evitando assim que ele fique indefinidamente com fome [Chandy & Misra, 1984].

3.3.3 O Problema do Papai Noel

O problema do Papai Noel foi proposto por Trono [1994] como um exercício não-trivialem programação concorrente. O problema é composto por dez elfos, nove renas e peloPapai Noel. A vida do Papai Noel se resume a dormir até que ele seja acordado pelasnove renas ou por um grupo de três elfos. Caso seja acordado pelas renas o Papai Noelamarra-as ao trenó, distribui brinquedos, desamarra-as e volta a dormir. Caso sejaacordado pelos duendes, o Papai Noel discute projetos de brinquedos com os elfos evolta a dormir. A vida de uma rena se resume a entregar presentes e tirar férias atéo próximo ano. A vida de um elfo se resume a fabricar brinquedos e se reunir com oPapai Noel.

A solução apresentada se baseia em Benton [2003]. Inicialmente definimos umgrupo, ou NWay na solução original, representado pela classe com acorde Group.

1 package usecases.santaclaus.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Group {

6 @Sync public void entry() {}

7 @Async public void tokens(int n) {}

8 @Sync public void waitt() {}

9 @Async public void allgone() {}

10

11 public void accept(int n) {

12 tokens(n);

13 waitt();

14 }

15

Page 81: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 55

16 @Join({"void entry()", "void tokens(int)"})

17 public void entry_tokens(int n) {

18 if (--n == 0) {

19 allgone();

20 } else {

21 tokens(n);

22 }

23 }

24

25 @Join({"void waitt()", "void allgone()"}) public void wait_allgone() {}

26 }

Listagem 3.20. Classe Group

Um grupo aceita o método accept(int n) que define que este grupo estará completoquanto tiver n elementos inscritos. Esse método retém o fluxo de execução até que ogrupo esteja completo. Um elemento se inscreve no grupo chamando o método entry

que por sua vez também retém o fluxo de execução até que o grupo esteja completo.O grupo é essencialmente uma barreira que irá reter um grupo de elementos até quetodos eles estejam prontos.

1 package usecases.santaclaus.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class SantaClaus {

6 public static final int REIN_TEAM = 9;

7 public static final int ELF_TEAM = 3;

8 public static SantaClaus INSTANCE = new SantaClaus();

9

10 public final Group harness = new Group();

11 public final Group unharness = new Group();

12 public final Group roomin = new Group();

13 public final Group roomout = new Group();

14

15 private SantaClaus() {

16 elves(0);

17 reins(0);

18 elvesfirst();

19 sleep();

20 }

Page 82: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

56 Capítulo 3. Acordes em Java

21

22 @Async public void sleep() {

23 System.out.println("Papai Noel dormindo");

24 }

25 @Async public void elf() {}

26 @Async public void elves(int e) {}

27 @Async public void elvesready() {}

28 @Async public void elvesfirst() {}

29 @Async public void rein() {}

30 @Async public void reins(int i) {}

31 @Async public void reinsready() {}

32 @Async public void reinsfirst() {}

33

34 @Join({"void reinsfirst()", "void elvesfirst()"})

35 public void reinfirst_elvesfirst() {}

36

37 @Join({"void elf()", "void elves(int)"}) public void elf_elves(int e) {

38 if (++e == ELF_TEAM) {

39 elvesready();

40 } else {

41 elves(e);

42 }

43 }

44

45 @Join({"void rein()", "void reins(int)"}) public void rein_reins(int r) {

46 if (++r == REIN_TEAM) {

47 reinsfirst();

48 reinsready();

49 } else {

50 reins(r);

51 }

52 }

53

54 @Join({"void sleep()", "void reinsready()"})

55 public void sleep_reinsready() {

56 harness.accept(REIN_TEAM);

57 elvesfirst();

58 reins(0);

59 delivering();

60 unharness.accept(REIN_TEAM);

Page 83: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

3.3. Aplicação 57

61 sleep();

62 }

63

64 @Join({"void sleep()", "void elvesready()", "void elvesfirst()"})

65 public void sleep_elvesready() {

66 elvesfirst();

67 roomin.accept(ELF_TEAM);

68 elves(0);

69 consulting();

70 roomout.accept(ELF_TEAM);

71 sleep();

72 }

73

74 private void consulting() {

75 System.out.println("Papai Noel consultando");

76 }

77

78 private void delivering() {

79 System.out.println("Papai Noel entregando brinquedos");

80 }

81 }

Listagem 3.21. Classe SantaClaus

O Papai Noel possui quatro grupos. Renas amarradas, renas desamarradas, elfosentrando na reunião e elfos saindo da reunião. Além disso, os parâmetros dos frag-mentos assíncronos reins(int r) e elves(int r) mantém controle de quantos elfos erenas, respectivamente, estão aguardando a atenção do Papai Noel.

Sempre que uma nova rena volta de férias ela invoca o fragmento rein() e entãoinvoca o fragmento síncrono entry() do grupo de renas amarradas, o que retém suaexecução até que o grupo de renas amarradas esteja completo. Por sua vez sempre queum elfo deseja se reunir com o Papai Noel ele invoca o fragmento assíncrono elf() eentão invoca o fragmento síncrono entry() do grupo de elfos entrando na reunião, oque também retém seu fluxo de execução até que o grupo elfos entrando na reuniãoesteja completo.

Invocações aos fragmentos rein() e elf() causam a execução dos acordesrein_reins(int r) e elf_elves(int e) que atualizam o número de renas e elfos aguar-dando a atenção do Papai Noel. Quando o número de renas ou elfos atingem o valor de-sejado, isso causa a invocação dos fragmentos reinsready() ou elvesready(). Estes porsua vez podem causar a execução dos acordes sleep_reinsready() ou sleep_elvesready

Page 84: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

58 Capítulo 3. Acordes em Java

() que executam uma viagem de entrega de brinquedos ou uma reunião com os elfos,respectivamente.

Os fragmentos reinsfirst() e elvesfirst(), e o acorde reinfirst_elvesfirst()

nos permitem priorizar as renas, garantindo que o acorde sleep_elvesready() só seráexecutado se o fragmento elvesfirst() estiver presente.

3.4 Conclusões

JChords disponibiliza a programação concorrente baseada em acordes em Java por meiode uma biblioteca externa. Assim é possível integrar os acordes de maneira gradual aoferramental Java existente e incentivar a experimentação e evolução.

Para isso foram desenvolvidos mecanismos que exploram os novos recursos do Java5 para viabilizar a descrição e implementação de soluções baseadas em acordes semdemandar alterações na linguagem.

Apesar das limitações que essa abordagem impõe, JChords se mostrou uma ferra-menta efetiva na solução de um conjunto de problemas de sincronização, concorrênciae paralelismo. Permitindo expressar soluções de maneira clara e direta.

A biblioteca JChords não é capaz de resolver por si só todos os problemas envolvidosna criação de sistemas paralelos. Sua principal contribuição está em permitir quesistemas paralelos e concorrentes sejam especificados em um maior nível de abstraçãode uma forma mais simples, efetiva e menos propensa a erros. Toda solução em JChordspode ser mapeada para uma solução equivalente usando as construções usuais em Java.

JChords busca liberar o desenvolvedor do gerenciamento de threads, permitindoque o foco seja mantido nas demandas do sistema em si, e não nas possíveis interaçõesadversas entre fluxos paralelos de execução.

Page 85: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 4

Implementação

Nesse capítulo detalha-se a implementação de JChords. Apresenta-se uma visão geraldos componentes básicos da biblioteca. São exploradas as interações entre esses com-ponentes e como eles colaboram para especificar, transformar e executar programasbaseados em acordes a partir de sistemas Java convencionais.

Posteriormente cada um desses componentes é analisado em detalhes. Sendo apre-sentada a estrutura interna de cada um deles assim como os detalhes de implementaçãoe decisões de projeto mais importantes.

4.1 Camadas de Atuação de JChords

A biblioteca JChords é composta por três camadas de atuação. A camada de desen-volvimento, a camada de transformação e a camada de execução. Cada uma dessascamadas atua em um momento específico do ciclo de vida de um sistema Java e dispo-nibiliza um conjunto de recursos para as camadas seguintes. A Figura 4.1 ilustra essaestrutura.

Desenvolvedor

Desenvo

lvim

ento

javac

Tran

sformação

java

Execução

Usuário

Figura 4.1. Camadas de atuação

59

Page 86: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

60 Capítulo 4. Implementação

A camada de desenvolvimento atua durante a codificação do sistema concorrentebaseado em acordes. Nela são disponibilizadas as anotações que permitem ao desen-volvedor anexar as meta-informações necessárias ao código. Com isso permitindo acodificação dos acordes e estruturas de apoio junto ao código fonte Java convencional.

A camada de transformação atua junto à máquina virtual Java no momento em queesta carrega as classes compiladas em bytecode do dispositivo de armazenamento e antesdo início da execução do sistema. Essa camada é formada por uma sequência encadeadade filtros ou agentes de transformação. Cada um desses filtros monitora o fluxo debytecodes em busca das anotações disponibilizadas pela camada de desenvolvimento,manipulando as sequências de instruções quando necessário. Dessa forma essa camadainstrumenta as classes com os elementos necessários para suportar acordes durante aexecução do sistema.

Por fim, a camada de execução provê a infraestrutura que irá suportar o sistemabaseado em acordes durante sua execução. Nessa camada o subsistema de casamentode padrões monitora as chamadas aos fragmentos síncronos e assíncronos, coordena aformação e sincronização dos padrões join resultantes e invoca a execução dos acordes.

A associação entre anotações em código e instrumentação de classes via manipula-ção de bytecodes usada em JChords é uma técnica bastante poderosa para adição denovas funcionalidades à linguagem sem a necessidade de modificar o compilador ou aprópria linguagem. Essa técnica permite à biblioteca reusar a sintaxe convencional dalinguagem, modificando a semântica de certas construções em condições específicas docódigo compilado.

4.2 Camada de Desenvolvimento

A camada de desenvolvimento é a parte do sistema que fica visível ao desenvolvedor.Ela provê as construções usadas durante a elaboração dos arquivos fonte que descrevemo sistema concorrente baseado em acordes. Essa camada é composta primariamentepor anotações. Essas anotações permitem anexar ao código fonte, meta-informaçõesque especificam as classes, fragmentos e acordes que compõem o sistema baseado emacordes.

Em Java, uma anotação é especificada utilizando uma sintaxe semelhante a usadapara especificar interfaces:

1 public @interface AnnotationName {}

Listagem 4.1. Anotações

Page 87: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.2. Camada de Desenvolvimento 61

Um declaração de anotação, assim como diversas outras construções em Java, po-dem ser anotadas. A biblioteca padrão Java provê as anotações @Target e @Retention

que permitem especificar, respectivamente, o conjunto de elementos aos quais umaanotação se aplica e até que ponto da vida útil do sistema essa anotação deve serpreservada.

Assim, a anotação @Chorded é definida da seguinte forma:

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.TYPE)

7 public @interface Chorded {}

Listagem 4.2. Anotação @Chorded

@Chorded é aplicável a tipos, ou seja, classes, interfaces, enumerações e anotações.Contudo JChords somente irá instrumentar classes anotados com @Chorded, os demaistipos serão ignorados. Além disso @Chorded é uma anotação que deve ser preservadaaté o tempo de execução, ou seja, ela irá compor os bytecodes dos arquivos compiladose poderá ser inspecionada em tempo de execução por meio de reflexão. Consequente-mente, essa anotação estará disponível para a camada de transformação em tempo decarga.

As anotações @Async e @Sync são definidas de maneira análoga. Ambas também sãodisponibilizadas em tempo de execução. Porém elas são aplicáveis somente a métodos.

Além das políticas de aplicação e retenção, uma anotação pode possuir propri-edades. Essas propriedades permitem ao desenvolvedor detalhar e complementar aanotação com trechos específicos de dados. A anotação @Join utiliza esse mecanismopara permitir que seja especificado o arranjo de descritores de fragmentos de acordesque irão compor o padrão join de um método acorde:

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.METHOD)

7 public @interface Join {

8 String[] value();

9 }

Page 88: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

62 Capítulo 4. Implementação

Listagem 4.3. Anotação @Join

Em @Join, a propriedade value() contém o arranjo de strings que é usado paraespecificar o padrão join em tempo de desenvolvimento. O valor dessa propriedadeserá armazenado nas classes compiladas e será usado para alimentar o subsistema decasamento de padrões.

As anotações são, por definição, elementos passivos no código. Não há uma açãoou execução associado a uma anotação. Seu objetivo é prover subsídios para outrasferramentas ou componentes do sistema. Da mesma forma as anotações disponibili-zadas pela camada de desenvolvimento irão apenas fornecer subsídios para as demaiscamadas de atuação de JChords.

4.3 Camada de Transformação

A camada de transformação é responsável por instrumentar as classes com acordes,provendo a infraestrutura necessária para seu funcionamento. Essa camada atua nomomento entre a carga das classes do dispositivo de armazenamento e o início da exe-cução do sistema. Essa camada se sustenta sobre duas outras tecnologias. A primeiraé a API de instrumentação Java, disponibilizada pela Sun a partir da versão 5 do Java.A outra é a biblioteca de manipulação de bytecodes ASM da ObjectWeb [Bruneton,2007].

A API de instrumentação Java possibilita anexar agentes de transformação à JVM.Esses agentes devem disponibilizar o método estático premain que, como o próprionome indica, é invocado antes do método estático main, que inicia a execução de umsistema Java. Mais importante ele é executado antes que as demais classes do sistemasejam carregadas pela JVM, o que permite intervir nesse processo de carga.

A interface ClassFileTransformer é uma das interfaces disponibilizadas pela APIde instrumentação. Ela permite inspecionar e transformar um arranjo de bytecodes queintegram as classes. A classe Transformer descrita na Listagem 4.4 implementa essainterface.

1 package jchords.agents;

2

3 import static java.lang.Boolean.parseBoolean;

4 import static java.lang.System.getProperty;

5 import static org.objectweb.asm.ClassReader.*;

6 import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;

7 import java.io.PrintWriter;

Page 89: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.3. Camada de Transformação 63

8 import java.lang.instrument.*;

9 import java.security.ProtectionDomain;

10 import org.objectweb.asm.*;

11 import org.objectweb.asm.util.*;

12

13 public class Transformer implements ClassFileTransformer {

14 public static final boolean SHOW_BYTECODE = parseBoolean(

15 getProperty("jchords.showbytecode")

16 );

17

18 public byte[] transform(ClassLoader loader, String name, Class cls,

19 ProtectionDomain domain, byte[] bytes) {

20 ClassReader reader = new ClassReader(bytes);

21 ClassWriter writer = new ClassWriter(reader, COMPUTE_FRAMES);

22 try {

23 reader.accept(adapt(writer), SKIP_FRAMES);

24 } catch (Throwable ex) {

25 ex.printStackTrace();

26 }

27 return writer.toByteArray();

28 }

29

30 private ClassVisitor adapt(ClassVisitor cv) {

31 if (SHOW_BYTECODE) {

32 cv = new TraceClassVisitor(cv, new PrintWriter(System.out));

33 }

34 cv = new CheckClassAdapter(cv);

35 cv = new AsyncTransformer(cv);

36 cv = new JoinTransformer(cv);

37 return cv;

38 }

39

40 public static void premain(String args, Instrumentation instrumentation) {

41 instrumentation.addTransformer(new Transformer());

42 }

43 }

Listagem 4.4. Classe Transformer

A classe Transformer responde por duas funções básicas. A primeira é realizadapelo método estático premain e consiste em anexar uma instância de si próprio ao

Page 90: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

64 Capítulo 4. Implementação

conjunto de ClassFileTransformer da API de instrumentação. A outra é aplicar acadeia de agentes de transformação aos bytecodes das classes.

A biblioteca ASM utiliza o padrão visitor e o padrão adapter para permitir ainspeção e manipulação dos bytecodes de uma classe. A Figura 4.2 ilustra a estruturabásica de uma solução utilizando ASM.

:Transformer :ClassReader :ClassAdapter* :ClassWriter

bytecode[]visit()

visit()

visitXxx()visitXxx()

métodos, campos, anotações, . . .métodos, campos, anotações, . . .

visitEnd()visitEnd()

toByteArray()bytecode[]

Figura 4.2. Estrutura de uma solução em ASM

A classe ClassReader recebe como parâmetros um arranjo de bytes contendo osbytecodes que definem a classe, é uma implementação da interface ClassVisitor.ClassReader irá interpretar o arranjo de bytes e invocar em sequência os métodos devisita, do tipo visitXxx(...), de ClassVisitor. Cada método de visita reflete algumaestrutura ou comando encontrado nos bytecodes como visitMethod(...) para métodos,visitField(...) para campos de dados ou visitAnnotation(...) para anotações.

Analogamente, temos a classe ClassWriter, que implementa ClassVisitor e realizaa função oposta de ClassReader. ClassWriter recebe uma sequência de chamadas aos

Page 91: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.3. Camada de Transformação 65

seus métodos visitXxx(...) e gera um arranjo de bytes que definem uma classe namáquina virtual Java.

Por fim, ASM provê a classe auxiliar ClassAdapter que simplesmente redirecionaas chamadas dos métodos de visita a outra realização de ClassVisitor. Com isso,podemos criar um encadeamento de filtros, começando pelo ClassReader, passandopor várias subclasses de ClassAdapter e terminando em ClassWriter. Cada filtro,sobrescreve um conjunto de métodos de visita de interesse e repassa as chamadas aopróximo filtro da cadeia.

Utilizando essa técnica, JChords define os filtros, ou agentes de transformação,AsyncTransformer JoinTransformer. Sendo que JoinTransformer por sua vez é com-posto pelos agentes ManagerMethod, SyncMethod e AsyncMethod.

4.3.1 AsyncTransformer

O agente de transformação AsyncTransformer é responsável por transformar os métodosanotados com @Async, que em Java convencional são síncronos, em métodos assíncronos,ou seja, métodos que são executados fora do fluxo de execução que os invocou.

Vale ressaltar que AsyncTransformer serve unicamente para proporcionar a execu-ção concorrente de um método. Ela não realiza nenhuma transformação relacionadaao casamento de padrões join ou invocação de acordes. Uma das vantagens da ar-quitetura de encadeamento de agentes de transformação é que pode-se criar agentescompletamente independentes, que se complementam em determinado contexto, masque podem ser utilizados separadamente.

Para transformar métodos convencionais em métodos assíncronos, são necessáriasduas operações. A primeira é renomear o método original e torná-lo privado. A segundaopção é criar um novo método com a mesma assinatura do método original e inserir ocódigo de invocação assíncrona, que utiliza uma nova threads para invocar o métodooriginal renomeado. Assim, o exemplo do código na Listagem 4.5.

1 public class Example {

2 @Async public void foo(int x, String y) {

3 // Corpo do método

4 }

5 }

Listagem 4.5. Método assíncrono original

será transformado em algo semelhante ao código da Listagem 4.6.

1 public class Example {

2 private void Async$foo(int x, String y) {

Page 92: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

66 Capítulo 4. Implementação

3 // Corpo do método

4 }

5 public void foo(final int x, final String y) {

6 new Thread() {

7 public void run() {

8 Async$foo(x,y);

9 }

10 }.start();

11 }

12 }

Listagem 4.6. Método assíncrono transformado

Na prática JChords, delega a chamada assíncrona à classe @AsyncCall. Essa classerealiza algumas adaptações internas, devido ao modo como classes anônimas são trata-das na JVM, e invoca o método original via reflexão. Contudo o efeito final é equivalenteao da Listagem 4.6.

4.3.2 JoinTransformer

O JoinTransformer por si só, é responsável unicamente por identificar as classes ano-tadas com @Chorded. Quando uma classe com acordes é detectada, três outros agentesde transformação são acionados para efetivamente instrumentar a classe. São elesManagerMethod, SyncMethod e AsyncMethod.

O agente ManagerMethod é responsável por adicionar à classe os mecanismos neces-sários para instanciar e acessar o gerenciador de acordes. O gerenciador de acordes é apeça central da camada de execução de JChords. Além disso, esse agente é responsávelpor coletar todos os padrões join declarados pela anotação @Join e registrá-los juntoao gerenciador de acordes.

AsyncMethod é responsável por instrumentar os métodos assíncronos de modo a noti-ficar o gerenciador de acordes sempre que esses métodos forem invocados. É importanteressaltar que AsyncMethod exerce uma função complementar porém bastante distintado AsyncTransformer visto anteriormente. O trabalho do AsyncTransformer é provermeios para que um dado método seja executado concorrentemente ao fluxo principal.Por sua vez, AsyncMethod é responsável por garantir que esses métodos integrem aarquitetura de acordes e componham o casamento de padrões join.

Por fim o agente AsyncMethod instrumenta os métodos síncronos para notificar ogerenciador de acordes e para buscar junto a esse o resultado da execução do acorde.Em essência esse agente substitui a chamada a Chords.result() pela chamada ao

Page 93: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.3. Camada de Transformação 67

gerenciador de acordes. Essa chamada é inserida no fim do método no caso de ele nãoretornar valores.

4.3.3 Transformação

O produto final da camada de transformação é uma classe Java devidamente instru-mentada para operar com acordes. Cada um dos agentes trata de uma transformaçãoespecífica, e em conjunto eles produzem uma classe baseada em acordes que será carre-gada e executada em uma máquina virtual Java padrão. No fim do processo completode transformação, a classe Buffer mostrada na Listagem 4.7.

1 package usecases.simplebuffer.jchords;

2

3 import jchords.Chords;

4 import jchords.annotations.*;

5

6 @Chorded public class Buffer {

7 @Async public void put(int var) {}

8 @Sync public int get() { return Chords.result(int.class); }

9 @Join({"int get()", "void put(int)"}) public int get_put(int var) {

10 return var;

11 }

12 }

Listagem 4.7. Classe Buffer original

seria transformada de modo a produzir uma classe semelhante a da Listagem 4.8.

1 package usecases.simplebuffer.jchords;

2

3 import jchords.*;

4 import jchords.annotations.*;

5 import jchords.annotations.Join;

6

7 @Chorded class BufferClass {

8 public BufferClass() {

9 $initChordManager$();

10 }

11

12 @Async public void Async$put(int value) {

13 $ChordManager$.addAsync("void put(int)", value);

14 }

Page 94: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

68 Capítulo 4. Implementação

15

16 public void put(int value) {

17 AsyncCall.invoke(BufferClass.class, "Async$put",

18 new Class<?>[] {int.class}, this, new Object[] {value});

19 }

20

21 @Sync public int get() {

22 return (Integer)$ChordManager$.addSync("int get()");

23 }

24

25 @Join({ "get()", "put(int)"}) public int get_put(int value) {

26 return value;

27 }

28

29 protected Chords $ChordManager$;

30

31 protected void $initChordManager$() {

32 $ChordManager$ = new Chords(this,

33 new JoinDescriptor("int get_put(int)", "int get()","void put(int)")

34 );

35 }

36 }

Listagem 4.8. Classe Buffer transformada

É importante observar que não é possível expressar uma tradução exata do processode transformação em um código na linguagem Java, tendo em vista que algumas dasmanipulações de bytecode realizadas não são passíveis de serem expressas diretamentena linguagem Java.

4.4 Camada de Execução

A camada de execução, atua durante a execução do sistema baseado em acordes. Ela éresponsável por prover a infraestrutura que será utilizada pelas classes instrumentadasna camada de transformação. Ela provê os componentes que irão monitorar e registrara invocação de fragmentos dos acordes, detectar os padrões join, coordenar, sincronizare executar os acordes.

Essa camada é composta de um único componente principal que encapsula umpequeno conjunto de componentes auxiliares. O componente principal dessa camada éo gerenciador de acordes, implementado pela classe Chords. Essa é a mesma classe que

Page 95: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.4. Camada de Execução 69

provê o método estático Chords.result(), usado para obter o resultado de um acorde.A camada de transformação garante que cada instância de uma classe com acordespossua um membro protegido do tipo Chords.

4.4.1 Chords

A principal tarefa do gerenciador de acordes é realizar o casamento de padrões join.Como vimos na camada de transformação, ao ser inicializado, o gerenciador de

acordes recebe um conjunto de instâncias da classe JoinDescriptor. Cada instânciade JoinDescriptor é composta pelos descritores de fragmentos atribuídos a um dadométodo acorde pela anotação @Join, precedido pelo descritor do próprio método acorde:

1 new Chords(this,

2 new JoinDescriptor("int get_put(int)", "int get()","void put(int)")

3 );

Listagem 4.9. Inicialização do gerenciador de acordes

JChords usa um sistema de casamento de padrões em árvore baseado no sistemaproposto por Itzstein [2005]. Dessa forma, ao ser inicializado, o gerenciador de acordesirá utilizar o conjunto de JoinDescriptor para construir a árvore de casamento depadrões que será usada pela instancia da classe com acordes.

A árvore de casamento de padrões, a rigor, não é uma árvore, mas um grafo dirigido.Esse grafo possui três níveis, sendo que a raiz desse grafo e o próprio gerenciador deacordes.

O segundo nível é formado pelo conjunto de padrões join. Cada acorde na classe dáorigem a um padrão join, implementado como uma instância da classe JoinPattern.

O terceiro nível é formado pelo conjunto de filas de invocações de fragmentos. Cadafragmento na classe dá origem a uma fila de invocações daquele fragmento, implemen-tada como instâncias da classe JoinFragment.

A estrutura básica do módulo de casamento de padrões pode ser visto na Figura 4.3.O Chords dispõe do conjunto de JoinFragment e o conjunto de JoinPattern da

classe. JoinPattern dispõe do conjunto de JoinFragment necessários a sua execução.Por sua vez, cada JoinFragment dispõe do conjunto de todos os JoinPattern que elepode compor. Assim, o algoritmo básico para o casamento de padrões pode ser vistoem Figura 4.4

Toda vez que um fragmento de acorde é chamado, o gerenciador de acordes busca afila de invocações de fragmentos específica daquele fragmento e enfileira os parâmetrosda chamada. Então, para cada padrão join em que o fragmento chamado pode partici-par, é verificado se o padrão está completo, ou seja, se há pelo menos um elemento nas

Page 96: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

70 Capítulo 4. Implementação

Chords

A&B B&C

A B CJoinFragment

JoinPattern

Chords

Figura 4.3. Casamento de padrões

Input: Invocação de fragmentoinício

obtém(JoinFragment em Chords);enfileira(Invocação em JoinFragment);para cada JoinPattern de JoinFragment faça

se completo(JoinPattern) entãopara cada JoinFragment de JoinPattern faça

desenfileira(JoinFragment);fimexecuta(JoinPattern);retorna;

fimfim

fim

Figura 4.4. Algoritmo de casamento de padrões

filas de todos os seus fragmentos. Se houver, os parâmetros de cada um dos fragmentossão desenfileirados de suas respectivas filas e passados ao padrão join que irá usá-lospara executar o método acorde correspondente à aquele padrão.

Utilizando a Figura 4.3 e a Figura 4.4, considere a situação inicialmente de todasas filas vazias, então:

1. Ocorre uma chamada ao fragmento A. O gerenciador de acordes localiza a fila Ae adiciona essa chamada. A fila A só faz parte do padrão A&B, portanto somenteesse padrão é verificado. Esse padrão depende do fragmento B, e a fila B estávazia, o processo termina.

2. Ocorre uma chamada ao fragmento C. O gerenciador de acordes localiza a filaC e adiciona essa chamada. A fila C só faz parte do padrão B&C, portanto

Page 97: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

4.5. Conclusão 71

somente esse padrão é verificado. Como esse padrão depende do fragmento B, ea fila B está vazia, o processo termina.

3. Ocorre a chamada ao fragmento B. O gerenciador de acordes localiza a fila B eadiciona essa chamada. A fila B faz parte dos padrões A&B e B&C, portantoambos os padrões são verificados. Ambos os padrões estão completos contudosomente um deles será executado. A implementação atual usa a ordem de de-claração dos acordes como método de desempate, contudo sistemas baseados emJChords não devem pressupor esse critério. Supondo a execução do padrão A&B,então são extraídos elementos das filas A e B, ficando ambas vazias, e o métodoacorde relacionado a esse padrão será executado.

4.5 Conclusão

A implementação de JChords utiliza diversas camadas de atuação que se complemen-tam para integrar acordes em uma plataforma Java padrão. Cada camada atua em ummomento do ciclo de vida do sistema Java e disponibiliza recursos específicos para ascamadas seguintes.

Anotações em código e instrumentação de bytecodes fornecem uma técnica pode-rosa que permite à biblioteca adaptar a sintaxe e a semântica da linguagem paraimplementar novas funcionalidades ao Java sem comprometer o ambiente padrão dedesenvolvimento e execução. Essa técnica possibilita manipular um sistema por meiodo próprio sistema sem alterar significativamente o desenvolvimento normal deste.

A camada de desenvolvimento disponibiliza anotações por meio das quais o desen-volvedor descreve os acordes e estruturas de apoio junto ao código fonte Java conven-cional.

A camada de transformação aplica uma sequência encadeada de filtros ou agentesde transformação que atuam diretamente sobre os bytecodes, e utilizam as anotaçõesdisponibilizadas pela camada de desenvolvimento e instrumentam as classes com osuporte a acordes.

Por fim, a camada de execução provê a infraestrutura para suportar as classesinstrumentadas produzidas na etapa anterior, incluindo o mecanismo de casamento depadrões que coordena a formação de joins e a execução dos acordes.

O esforço conjunto de todas as camadas de atuação proporciona uma implementaçãode acordes por meio de uma biblioteca externa mantendo uma sintaxe apropriada paraa estrutura de acordes e com a estrutura sintática de um código Java convencional.

Page 98: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 99: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 5

Avaliação

Dentre as principais soluções para o uso de acordes nas principais linguagens imperati-vas orientadas a objetos, JChords ocupa um nicho que anteriormente não era suportadopor nenhuma outra solução, ou seja, uma solução baseada em biblioteca para a pla-taforma Java. Considerando as duas principais linguagens de programação modernasorientadas a objetos, Java e C#, e ainda as duas principais estratégias para implemen-tar acordes nessas linguagens, via biblioteca externa ou via compilador customizado,observa-se a seguinte conformação:

Biblioteca Compilador

Java JChords Join JavaC# Joins Cω

Tabela 5.1. Soluções em acordes

Do ponto de vista funcional, excetuando-se os aspectos relacionadas a plataformae implementação, todas as soluções apresentadas desempenham exatamente o mesmopapel e todas elas desempenham esse papel disponibilizando essencialmente os mesmoselementos básicos. Ou seja, todas elas disponibilizam os recursos necessários a pro-gramação baseada em acordes. Os meios usados por cada solução para disponibilizaresses recursos varia de acordo com a plataforma, com a estratégia de implementaçãoadotada e com o desenho da solução. Contudo todas as soluções disponibilizam meiospara a criação de fragmentos síncronos e assíncronos e para a especificação de padrõesjoin e acordes, além de prover a infraestrutura necessária para gerenciar e executaracordes.

Cada uma das soluções analisadas serve a um cenário de uso específico e atendeaos requisitos desse cenário. Dessa forma não é objetivo dessa análise demonstrar asuperioridade absoluta de uma solução em relação a outra mas sim demonstrar os

73

Page 100: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

74 Capítulo 5. Avaliação

diferenciais significativos de desenho, implementação e plataforma de cada uma dassoluções. O objetivo dessa análise é estabelecer critérios para seleção de uma soluções,baseada nos requisitos de um cenário de uso específico. Além disso essa análise objetivamostrar os cenários e situações em que JChords se apresenta como a solução maisadequada.

Tendo esses objetivos em vista foram selecionados os seguintes critérios de análise:

• Funcionamento em ambiente de desenvolvimento padrão

• Funcionamento em ambiente de execução padrão

• Permite acordes compostos

• Priorização de acordes

• Validação em tempo de compilação

• Otimização em tempo de compilação

• Acordes como métodos

• Multiplataforma

• Não requer declaração de fragmentos síncronos

• Não requer declaração de fragmentos assíncronos

• Não requer inicialização dos fragmentos

A análise que se segue não considera o desempenho em tempo de execução dassoluções analisadas. Isso se deve principalmente pela impossibilidade de compararobjetivamente o desempenho de sistemas concorrentes em plataformas distintas, vistoque quaisquer diferenças podem ser atribuídas tanto a solução quanto a plataforma.

5.1 Critérios

“Funcionamento em ambiente de desenvolvimento padrão” se refere a capacidade dasolução em ser usada em um ambiente de desenvolvimento suportado por grandes em-presas ou comunidades, normalmente ambientes homologados pelo próprio provedor daplataforma escolhida. Na indústria de software há um volume considerável de tempo,dinheiro e recursos investidos na criação e manutenção de sistemas. O uso de ferra-mentas de desenvolvimento não padronizadas representa um risco a esse investimento,seja devido as potenciais deficiências ou ineficiências dessas ferramentas ou pelo risco

Page 101: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

5.1. Critérios 75

de interrupção súbita no suporte e manutenção das mesmas. Dessa forma, o uso deambientes não padronizados tende a ser rejeitado em um ambiente de produção e porconsequência, ferramentas capazes de operar em ambientes de desenvolvimento padrãopodem ser as únicas opções nesses casos.

De maneira análoga, “funcionamento em ambiente de execução padrão” se referea capacidade da solução de ser executada em um ambiente de execução suportado ehomologado por grandes empresas ou comunidades. Esse critério se baseia nos mesmosprincípios do critério anterior, “funciona em ambiente de desenvolvimento padrão”,contudo este critério é ainda mais importante. A adoção de um ambiente de execuçãocustomizado que apresente alguma deficiência ou incompatibilidade pode comprometera estabilidade do servidor de aplicações e por consequência comprometer não só aaplicação que utiliza o ambiente customizado, mas também todas as demais aplicaçõesdaquele servidor. Dessa forma, novamente, o uso de ambientes não padronizados tendea não ser aceito em ambientes de produção.

O critério “permite acordes compostos”, se refere à capacidade de uma solução emexpressar os padrões join de maneira composta, ou seja, reusando parte assíncrona dopadrão para declarar mais de um acorde. Esse recurso permite agrupar os acordes demodo a melhorar sua organização no código:

1 public int get() & positive(int n) {

2 return n;

3 } & negative(int n) {

4 return -n;

5 }

Listagem 5.1. Acorde composto

Nesse exemplo temos os padrões get()& positive(int) e get()& negative(int)

sendo ambos descritos por meio de uma única declaração do fragmento síncrono get().“Priorização de acordes” descreve a capacidade da solução em favorecer a execução

de certos acordes quando houver a possibilidade de executar mais de um acorde. O join-calculus estabelece que havendo dois padrões join possíveis em uma dada expressão umdeles deve ser escolhido não-deterministicamente, deixando o critério de escolha a cargoda implementação específica. Nesse critério é considerada a capacidade da solução empermitir declarar qual acorde deve ser executado quando houver a possibilidade deexecutar mais de um acorde. Vale ressaltar que, como já foi demonstrado na soluçãodo problema do Papai Noel na Subseção 3.3.3, a priorização de acordes sempre podeser feita por meio da inclusão de acordes auxiliares, sendo que o recurso de priorizaçãode acordes representa apenas uma facilidade ao desenvolvedor.

No critério “validação em tempo de compilação” avalia-se a capacidade da solução

Page 102: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

76 Capítulo 5. Avaliação

em detectar erros durante a compilação. Todas as soluções apresentadas aprimoram dealguma forma sua linguagem base, e com isso passam a existir novas regras de validaçãode estrutura e de sintaxe as quais as violações precisam ser identificadas. Esse critérioavalia se a solução é capaz de indicar a presença de erros sem a necessidade de executare testar o sistema. Não está sendo considerado aqui quão efetiva é a detecção de errosda solução, apenas se ela é possível.

O critério “otimização em tempo de compilação” descreve a capacidade da soluçãoem analisar e aprimorar o código criado pelo desenvolvedor de modo a melhorar odesempenho do sistema durante a execução. Vale observar que não é considerado aquiquão efetiva é a otimização, apenas se ela é possível. Além disso está sendo levadoem consideração somente a possibilidade de otimizar a execução dos acordes e não dalinguagem base como um todo.

“Acordes como métodos” avalia o quão natural é a técnica de integração de acordescom a linguagem base. No paradigma orientado a objetos, toda computação se dá pelatroca de mensagens entre objetos. Dessa forma considera-se natural que os acordessejam implementados como uma abstração da troca de mensagens normal do para-digma orientado a objetos. Soluções que não seguem esse critério tendem a demandarum esforço mental maior de um desenvolvedor devido a necessidade de se adequar oparadigma.

O critério “Multiplataforma” define a capacidade de um sistema funcionar em di-versas combinações de hardware e sistemas operacionais sem demandar mudanças nocódigo fonte, específicas a cada plataforma. Devido a fatores econômicos e tecnoló-gicos, frequentemente é necessário desenvolver sistemas capazes de executar em umapopulação heterogênea de dispositivos computacionais. Esse critério avalia a capaci-dade da solução de viabilizar seu uso em ambientes computacionais heterogêneos semdemandar mudanças no código fonte do sistema.

“Não requer declaração de fragmentos síncronos” e “não requer declaração de frag-mentos assíncronos” descrevem a capacidade de uma solução em identificar, por meiodas assinaturas dos acordes, os fragmentos síncronos e assíncronos necessários, semque haja a necessidade de declará-los explicitamente. Em geral, soluções que requeremmenos declarações explícitas tendem a ser mais simples de usar pois demandam menosesforço do desenvolvedor e poluem menos o código fonte.

Por fim, o critério “não requer inicialização dos fragmentos” identifica soluções ondenão é necessário executar nenhum mecanismo ou rotina de inicialização explícita parahabilitar o uso de acordes. Esse critério identifica soluções para as quais além dadeclaração vista nos critérios anteriores, ainda requerem algum tipo de inicialização dosfragmentos. Novamente soluções que requerem menos inicializações explícitas tendem

Page 103: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

5.2. JChords 77

a permitir códigos mais simples e menos poluídos.

5.2 JChords

Como já foi visto anteriormente, JChords implementa acordes em Java por meio deuma biblioteca externa. JChords foi desenvolvida para ser usada em um ambiente Javapadrão tanto em tempo de desenvolvimento quanto em tempo de execução. São usadasanotações para incorporar a classes e métodos os elementos necessários ao desenvolvi-mento com acordes e para declarar os padrões join.

Sendo uma biblioteca externa, desenvolvida sobre a própria plataforma Java,JChords poderá, em teoria, ser usada com qualquer versão futura do ferramental Javaalém de se beneficiar de melhorias e aprimoramentos que vierem a ser disponibilizadosna plataforma. Além disso, por ser possível utilizá-la com um ambiente de desenvolvi-mento padrão, JChords pode ser prontamente utilizada em ambientes de produção.

A sintaxe de JChords já foi examinada no Capítulo 3. A Listagem 3.20 exibe, porconveniência, a classe Group usada na solução do problema do Papai Noel:

1 package usecases.santaclaus.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Group {

6 @Sync public void entry() {}

7 @Async public void tokens(int n) {}

8 @Sync public void waitt() {}

9 @Async public void allgone() {}

10

11 public void accept(int n) {

12 tokens(n);

13 waitt();

14 }

15

16 @Join({"void entry()", "void tokens(int)"})

17 public void entry_tokens(int n) {

18 if (--n == 0) {

19 allgone();

20 } else {

21 tokens(n);

22 }

Page 104: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

78 Capítulo 5. Avaliação

23 }

24

25 @Join({"void waitt()", "void allgone()"}) public void wait_allgone() {}

26 }

Listagem 5.2. usecases/santaclaus/jchords/Group.java

Classe Group

Em JChords, fragmentos síncronos e assíncronos precisam ser declarados explici-tamente. Isso é necessário de modo a garantir que a invocação de um fragmento sejauma invocação de método válida no código. Embora isso possa aumentar o volume decódigo necessário, essa característica possibilita a adição de trechos auxiliares de códigonos fragmentos. Apesar de normalmente esses códigos auxiliares não serem necessários,eles podem ser úteis para controle e monitoramento dos acordes. Além disso, as decla-rações dos fragmentos podem ser usadas como breakpoints nos depuradores disponíveisno ecossistema Java.

Os padrões join são declarados em JChords pela anotação @Join. Essa anotaçãorecebe como parâmetro um arranjo de strings, sendo que cada elemento desse arranjodescreve um dos fragmentos que compõem o padrão. O uso de strings para descreverum fragmento possibilita a introdução de erros de digitação que não são detectados emtempo de compilação. Além disso, ferramentas de refatoração, via de regra, não são ca-pazes de ajustar os descritores de fragmentos adequadamente, requerendo a intervençãomanual do desenvolvedor.

Por fim, sendo Java uma ferramenta multiplataforma, ou seja, capaz de executarem ambientes computacionais diversos, ferramentas baseadas em Java herdam essahabilidade, o que amplia o universo potencial de aplicações para JChords.

5.3 Joins

A biblioteca Joins proposta por Russo [2006], assim como JChords, implementa acordespor meio de uma biblioteca externa. Diferentemente de JChords, Joins implementaacordes para C# na plataforma .NET padrão.

Joins provê uma interface onde os elementos necessários ao desenvolvimento comacordes são objetos. Ou seja, os fragmentos, padrões join e acordes são represen-tados por instâncias de classes específicas, configurados em tempo de execução paradesempenhar os papéis das construções para acordes.

O trecho de código da Listagem 5.3 foi adaptado do conjunto de exemplos dadistribuição de Joins. A classe apresentada equivale a classe Group, chamada aqui denway:

Page 105: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

5.3. Joins 79

1 public class nway {

2 private readonly Asynchronous.Channel<int> tokens;

3 public readonly Synchronous.Channel entry;

4 private readonly Asynchronous.Channel allgone;

5 private readonly Synchronous.Channel wait;

6

7 public void acceptn(int n) {

8 tokens(n);

9 wait();

10 }

11

12 public nway(){

13 Join j = Join.Create();

14

15 j.Initialize(out tokens);

16 j.Initialize(out entry);

17 j.Initialize(out allgone);

18 j.Initialize(out wait);

19

20 j.When(entry).And(tokens).Do(delegate(int n){

21 if (n==1) {

22 allgone();

23 } else {

24 tokens(n-1);

25 }

26 });

27

28 j.When(wait).And(allgone).Do(delegate(){});

29 }

30 }

Listagem 5.3. Classe nway

Joins requer que os fragmentos síncronos e assíncronos sejam declarados. É neces-sário também inicializar esses fragmentos antes que eles possam ser usados, uma vezque se tratam de objetos.

Além disso, os fragmentos só podem receber no máximo um parâmetro. Isso se deveà impossibilidade de tratar classes genéricas com número variável de tipos. Contudoisso pode ser contornado pela utilização de tuplas ou arranjos.

Vale observar que a biblioteca utiliza amplamente os delegates disponíveis em C#

Page 106: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

80 Capítulo 5. Avaliação

para simplificar diversos pontos da sintaxe. Esse não é um recurso que existe em Java.Os padrões join são declarados invocando métodos encadeados na classe Join. Essa

sintaxe, associada à sintaxe para declarar e inicializar fragmentos, pode ser confusa ediluir a solução do problema. Contudo, pela utilização de objetos e classes genéricas,Joins garante a validade dos nomes e tipos dos fragmentos em tempo de compilação.

Como pode ser constatado, sendo uma implementação por biblioteca externa Joinscompartilha muitas das características de JChords. A principal diferença entre as duasbibliotecas, além da plataforma, é a opção por utilizar anotações ou objectificação, oque resulta na diferença na abordagem sintática das bibliotecas.

5.4 Join Java

Join Java, proposto por Itzstein [2005], é uma das primeira implementações de acordesem linguagens imperativas orientadas a objetos. Assim como JChords, Join Java sebaseia na plataforma Java. Ao contrário de JChords, Join Java foi implementado comoum compilador customizado.

As principais desvantagens da implementação via compilador customizado é o altorisco de obsolência. A menos que haja um esforço de sincronização efetivo, compiladorescustomizados tendem a apresentar incompatibilidades e a não incorporar melhoriase aprimoramentos implementados no ferramental de desenvolvimento padrão. Alémdisso, evoluções da linguagem podem demandar um grande esforço para atualizar ocompilador, mesmo não havendo qualquer mudança na estrutura de acordes em si.

Por outro lado, Join Java apresenta a sintaxe mais limpa e direta dentre as soluçõesanalisadas. Uma classe com acorde em Join Java não requer declaração ou inicializaçãode fragmentos. Os padrões join são declarados diretamente nas assinaturas dos acordese todos os fragmentos necessários são inferidos por meio dessas assinaturas. A Lista-gem 5.4 mostra a mesma classe Group pra o problema do Papai Noel, implementadaem Join Java:

1 final public class Group {

2 public void accept(int n) {

3 tokens(n);

4 waitt();

5 }

6

7 public void entry() & tokens(int n) {

8 if (--n == 0) {

9 allgone();

10 } else {

Page 107: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

5.5. Cω 81

11 tokens(n);

12 }

13 }

14

15 public void waitt() & allgone() {}

16 }

Listagem 5.4. Group

São introduzidas as palavras chave signal e ordered. signal serve como tipo deretorno para acordes que não possuem fragmentos síncronos. ordered permite declararclasses onde a ordem em que os acordes aparecem determina a prioridade dos mesmos,ou seja, dado dois padrões join possíveis, será executado aquele que tiver sido declaradoprimeiro no corpo da classe.

Sendo uma solução baseada em compilador, toda a verificação e validação da sintaxeé feita em tempo de compilação. Além disso, uma vez que o compilador tem uma visãoglobal do sistema, é possível aplicar otimizações mais agressivas aos bytecodes gerados.

Apesar de exigir um ambiente de desenvolvimento customizado, Join Java gerabytecodes de acordo com a especificação padrão da máquina virtual Java e, por con-sequência, classes compiladas com Join Java operam em ambientes de execução padrão.

Sintaticamente, Join Java é uma implementação mais limpa e direta de acordes.Em contrapartida o uso de compiladores customizados pode inviabilizar o uso de JoinJava em situações onde JChords pode ser aplicado sem restrições.

5.5 Cω

Cω proposto por Benton et al. [2004] é uma evolução do Polyphonic C# proposto porBenton et al. [2002] e implementa acordes em C# por meio de um compilador custo-mizado. Assim como Join Java, Cω é suceptível as dificuldades em utilizar ferramentascustomizadas em ambientes produtivos. Por outro lado possui uma sintaxe mais limpae direta que implementações por biblioteca, assim como dispõe de melhores recursospara validação e otimização em tempo de compilação.

A Listagem 5.5 ilustra a classe nway, equivalente a Group na solução do problema doPapai Noel. O trecho de código mostrado foi adaptado dos exemplos que acompanhama distribuição de Cω:

1 public class nway {

2 async tokens(int n);

3 async allgone();

4

Page 108: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

82 Capítulo 5. Avaliação

5 public void acceptn(int n) {

6 tokens(n);

7 wait();

8 }

9

10 public void entry() & tokens(int n) {

11 if (n==1) {

12 allgone();

13 } else {

14 tokens(n-1);

15 }

16 }

17

18 void wait() & allgone() {}

19 }

Listagem 5.5. Classe nway

A linguagem base é aprimorada pela inclusão da palavra reservada async usadacomo tipo de retorno para a declaração dos fragmento assíncronos. Os padrões join sãodeclarados diretamente na assinatura do acorde, sendo que existe o suporte a acordescompostos.

Ao contrário de Join Java e à semelhança de Joins e JChords, Cω requer a declaraçãodos fragmentos assíncronos. Os fragmentos síncronos não precisam ser declarados.

Cω incorpora diversos outros recursos além de acordes. Do ponto de vista da imple-mentação de acordes Cω equivale a Join Java em quase todos os aspectos. Consequen-temente, excetuando-se a plataforma, Cω se compara a JChords da mesma maneiraque Join Java.

5.6 Conclusão

As principais características de cada uma das soluções analisadas é sumarizada naTabela 5.2.

As soluções baseadas em compiladores customizados se destacam quanto a sintaxee robustez, uma vez que a sintaxe da linguagem base foi explicitamente modificadapara acomodar os acordes.

Por outro lado, as inconveniências associadas ao uso de compiladores customizadospodem inviabilizar o uso dessas soluções em ambientes não experimentais. Nesse casoas soluções baseadas em biblioteca demandam um custo adicional na sintaxe em troca

Page 109: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

5.6. Conclusão 83

JChords Joins Join Java Cω

Ambiente de desenvolvimento padrão X X

Ambiente de execução padrão X X X X

Acordes compostos X

Priorização de acordes X X

Validação em tempo de compilação X X X

Otimização em tempo de compilação X X

Acordes como métodos X X X

Multiplataforma X X

Não declara fragmentos síncronos X X

Não declara fragmentos assíncronos X

Não inicializa fragmentos X X X

Tabela 5.2. Sumário da avaliação

de serem aptas a funcionarem em ambientes padrão.JChords se destaca por oferecer uma sintaxe razoavelmente semelhante às soluções

baseadas em compiladores customizados, porém implementada como uma bibliotecaexterna. Além de ocupar o nicho, anteriormente vazio, das bibliotecas para acordes naplataforma JAVA.

Page 110: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 111: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Capítulo 6

Considerações Finais

Desenvolver sistemas capazes de operar paralelamente, que possam ser facilmente es-calonados entre muitos processadores de forma efetiva é um dos grandes desafios dacomputação moderna. Contudo, os principais mecanismos usados para expressar para-lelismo e concorrência nas principais linguagens de programação se mostram inadequa-dos à tarefa que se apresenta, tendo em vista o alto grau de dificuldade normalmenteassociado ao desenvolvimento de sistemas concorrentes.

Sistemas concorrentes se mostram, ainda hoje, complexos de projetar e construir,susceptíveis a erros grosseiros mas que se manifestam de maneira sutil e intermitente.Difíceis de serem detectados e corrigidos com o ferramental técnico disponível.

As threads, hoje a principal construção para expressar concorrência nas linguagensde programação imperativas, são construções de baixo nível de abstração que nãodeveriam ser usadas diretamente, mas sim servindo como base para construções demais alto nível. Isso segue a tendência das principais linguagens modernas, que buscampoupar o desenvolvedor do encargo de micro-gerenciar os recursos do sistema.

Os acordes oferecem um mecanismo de alto nível de abstração para expressar sis-temas concorrentes. Eles integram com sucesso a solidez conceitual da álgebra deprocesso join-calculus ao paradigma imperativo orientado a objetos, oferecendo umaforma elegante, prática e segura de expressar soluções para problemas de concorrênciae paralelismo.

Diversas soluções tem sido propostas para implementar acordes nas principais lin-guagens de programação, em especial C# e Java. A implementação de acordes geral-mente é feita pela criação de compiladores customizados ou pela criação de bibliotecasexternas. A implementação por meio de compiladores customizados, em tese, é maisadequada a técnicas maduras e estáveis, onde não se esperam grandes desenvolvimen-tos ou evoluções. Por outro lado, a implementação por biblioteca é mais adequada atécnicas novas e em evolução.

85

Page 112: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

86 Capítulo 6. Considerações Finais

Dessa forma, nesse trabalho mostrou-se o projeto, a implementação e aplicaçãode JChords, uma iniciativa para prover acordes em Java por meio de uma bibliotecaexterna. Almejou-se com esse esforço preencher o espaço atualmente vazio de acordesvia biblioteca em Java, e integrar os acordes ao ecossistema e ao ferramental Java demaneira gradual e flexível. Encorajando a experimentação e evolução.

A biblioteca JChords permite expressar as soluções para problemas de concorrênciaem um nível mais alto de abstração, de modo mais simples, direto e seguro. Liberandoo desenvolvedor do gerenciamento de threads e permitindo que ele se concentre nasdemandas do problema em si. Apesar das limitações que uma implementação porbiblioteca impôs, JChords apresentou resultados bastante satisfatórios em termos deestrutura e expressividade. Mostrando-se adequado para substituir as threads na mai-oria das situações estudadas.

A tarefa de implementar acordes em Java via biblioteca demandou mecanismos queexploram os novos recursos do Java 5 que viabilizaram a descrição e implementação desoluções baseadas em acordes sem demandar alterações na linguagem.

A implementação de JChords foi realizada de forma modular, utilizando três ca-madas de atuação que se complementam para integrar o resultado final. A camada dedesenvolvimento baseada em anotações, a camada de transformação baseada na instru-mentação e manipulação das classes compiladas, e a camada de execução baseada emreflexão. A atuação em conjunto dessas camadas proporciona a anexação da sintaxese semânticas necessárias para o desenvolvimento de sistemas baseados em acordes semdemandar alterações na plataforma Java padrão.

6.1 Trabalhos Futuros

O presente trabalho é mais um passo para um suporte efetivo à programação baseadaem acordes na plataforma Java. Há ainda uma grande variedade de oportunidades detrabalhos tanto internos quanto externos à JChords.

Nesse primeiro momento, JChords é principalmente uma prova de conceito de umaimplementação de acordes baseada em biblioteca. O principal foco até o momentofoi a usabilidade das construções que suportam acordes e a arquitetura para viabili-zar as intervenções necessárias. Assim, muitos aspectos da implementação podem serotimizados e aperfeiçoados.

6.1.1 Otimização

Um ponto de otimização bastante relevante é o mecanismo de casamento de padrões.Como já foi visto, JChords implementa a mesma estratégia de casamento de padrões

Page 113: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

6.1. Trabalhos Futuros 87

proposta por Itzstein [2005]. Por ser central ao funcionamento da biblioteca, melhoriasnesse mecanismo seriam bastante benéficas ao sistema como um todo.

Outro ponto significativo diz respeito a mecânica de invocação de métodos as-síncronos. Os métodos assíncronos representam uma grande parcela das mensagenstransportadas em JChords. É possível que haja ganhos de desempenho significativospela substituição da mecânica de invocação por reflexão em favor do acesso direto viamanipulação de bytecode.

6.1.2 Validação

Um outro aspecto de JChords que pode ser aprimorado é a validação das regras deacordes em tempo de compilação. Como foi visto, devido a maneira como a bibliotecafoi concebida, erros na composição dos padrões join ou outras violações das regras dabiblioteca só são detectados em tempo de carga. O uso de processadores de anotaçõespode fornecer os meios para detectar esses erros em tempo de compilação.

A versão 5 do Java disponibiliza, junto ao suporte a anotações, uma ferramenta quepermite anexar processadores de anotações ao compilador Java. Esses processadoresnão possibilitam manipular ou alterar as classes geradas, consequentemente eles não sãoadequados como mecanismos de transformação de JChords. Contudo os processadoresde anotações podem inspecionar as classes em tempo de compilação e com isso podemser usados para verificar e validar os acordes em tempo de compilação, emitindo avisosde erros se necessário.

6.1.3 Herança e Polimorfismo

Um outro aspecto significativo para a integração de acordes em linguagens orientadasa objetos é o suporte a herança. Na atual encarnação de JChords não são feitasprovisões para o tratamento de hierarquias de classes com acordes. A herança entreclasses com acordes é permitida, contudo não há suporte para herança de fragmentosou padrões join, nem suporte à sobrescrita ou polimorfismo de fragmentos ou acordes.Ou seja a herança é suportada desde que os elementos baseados em acordes não sejamcompartilhados entre as classes.

Itzstein [2005] optou por não permitir a herança com classes com acordes ao passoque Benton et al. [2004] optou por permitir herança e tratar as anomalias resultantesda integração da herança e acordes [Matsuoka & Yonezawa, 1993]. A experimentaçãocom o suporte a hierarquias permitiria uma análise mais refinada dos meios e métodospara implementá-lo efetivamente em JChords.

Page 114: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

88 Capítulo 6. Considerações Finais

6.1.4 Padrões Join

Sob muitos aspectos, podemos considerar os padrões join como expressões lógicas con-juntivas. O padrão A()& B() requer que exista uma invocação do fragmento A() e umainvocação do fragmento B() para permitir a execução do acorde.

Usando apenas adições sintáticas à biblioteca, talvez seja possível permitir padrõesdisjuntivos do tipo A()| B(), ou seja, um padrão que requer o fragmento A() ou ofragmento B(). Ou ainda podemos compor padrões por negação do tipo A()& ~B()

para possibilitar a execução de um acorde somente na ausência de um determinadofragmento.

Essas adições podem simplificar certos padrões que de outra maneira exigiriam doisou mais acordes para serem descritos.

6.1.5 Padrões de Sincronização

Durante o desenvolvimento dos casos de uso de acordes, foram percebidos alguns pa-drões de sincronização recorrentes. O estudo e catalogação desses padrões devem per-mitir estabelecer o repertório de melhores práticas no desenvolvimento de sistemasbaseados em acordes.

6.1.6 Performance

Mensurar o desempenho de sistemas concorrentes é uma tarefa complexa. A mediçãodireta de throughput em um equipamento mono-processado não é efetiva uma vez quedevem ser consideradas as relações entre a capacidade de processamento do hardware,a qualidade da implementação do software e a capacidade do sistema em escalonar-segraciosamente no maior número possível de unidades de processamento.

Em teoria, um sistema perfeito desenvolvido utilizando threads será sempre maisrápido que um outro sistema igualmente perfeito desenvolvido usando acordes, uma vezque o sistema baseado em acordes dispende esforço na gestão de fluxos de execução.

Contudo, na prática, é difícil desenvolver sistemas concorrentes de larga escalautilizando threads que exibam uma implementação perfeita. Conjectura-se que sistemasbaseados em acordes sejam mais simples de desenvolver e implementam uma gestãomais efetiva de fluxos paralelos de execução. Por consequência, supõe-se que sistemasbaseados em acordes demandem menor tempo de desenvolvimento, uma vez superada acurva de aprendizado, e exibam maior paralelismo que os sistemas baseados em threads.

Dessa forma, a realização de testes de campo comparativos empregando gruposde desenvolvedores utilizando threads e acordes na solução de problemas práticos deve

Page 115: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

6.2. Conclusão 89

prover uma medida do real impacto da aplicação de acordes no desempenho de sistemasparalelos e concorrentes.

6.2 Conclusão

Considera-se que esse trabalho cumpriu seus objetivos demonstrando a necessidadee a viabilidade de construções de alto nível para programação concorrente em Javamantendo a arquitetura padrão da plataforma. A programação baseada em acordes éuma técnica relativamente recente porém mostra grande potencial para ser mais umpasso em direção a um arcabouço efetivo para o desenvolvimento de sistemas paralelos.

Page 116: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa
Page 117: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Apêndice A

Códigos Fonte

A.1 Biblioteca

1 package jchords;

2

3 import java.lang.reflect.Method;

4

5 public class AsyncCall {

6 private class Call extends Thread {

7 private final Object object;

8 private final Object[] args;

9

10 Call(Object object, Object... args) {

11 this.object = object;

12 this.args = args;

13 }

14

15 public void run() {

16 try {

17

18 method.invoke(object, args);

19 } catch (Exception ex) {

20 throw new RuntimeException(ex);

21 }

22 }

23 }

24

25 private final Method method;

91

Page 118: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

92 Apêndice A. Códigos Fonte

26

27 public AsyncCall(Class<?> cls, String name, Class<?>... args) {

28 try {

29 method = cls.getDeclaredMethod(name, args);

30 method.setAccessible(true);

31 } catch (NoSuchMethodException ex) {

32 throw new RuntimeException(ex);

33 }

34 }

35

36 public void invoke(Object target, Object... args) {

37 new Call(target, args).start();

38 }

39

40 public static void invoke(

41 Class<?> clazz, String name, Class<?>[] args, Object object, Object[]

values

42 ) {

43 new AsyncCall(clazz, name, args).invoke(object, values);

44 }

45 }

Listagem A.1. jchords/AsyncCall.java

1 package jchords;

2

3 import org.objectweb.asm.commons.Method;

4

5 public class Call {

6 Method method;

7 Object[] args;

8 Object result = null;

9 boolean ready = false;

10

11 public Call(Method method, Object[] args) {

12 this.method = method;

13 this.args = args;

14 }

15 }

Listagem A.2. jchords/Call.java

Page 119: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 93

1 package jchords;

2

3 import static jchords.asm.MethodUtils.getMethod;

4 import java.util.*;

5 import jchords.exceptions.UnpreparedChordedClass;

6 import org.objectweb.asm.commons.Method;

7

8 public class Chords {

9 private final Object object;

10 private Map<Method, JoinFragment> fragments =

11 new HashMap<Method, JoinFragment>();

12

13 public Chords(Object object, JoinDescriptor... joins) {

14 this.object = object;

15 for (JoinDescriptor join : joins) {

16 JoinPattern pattern = providePattern(join.method);

17 for (Method method : join.fragments) {

18 JoinFragment fragment = provideFragment(method);

19 fragment.patterns.add(pattern);

20 pattern.fragments.add(fragment);

21 }

22 }

23 }

24

25 private JoinPattern providePattern(Method method) {

26 try {

27 return new JoinPattern(object, getMethod(object.getClass(), method));

28 } catch(Exception ex) {

29 throw new RuntimeException(ex);

30 }

31 }

32

33 private JoinFragment provideFragment(Method method) {

34 JoinFragment fragment = fragments.get(method);

35 if(fragment == null) {

36 fragment = new JoinFragment(method);

37 fragments.put(method, fragment);

38 }

39 return fragment;

Page 120: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

94 Apêndice A. Códigos Fonte

40 }

41

42 private Call add(String desc, Object... args) {

43 return add(Method.getMethod(desc), args);

44 }

45

46 private Call add(Method method, Object... args) {

47 try {

48 return fragments.containsKey(method) ?

49 fragments.get(method).add(args) : null;

50 } finally {

51 notifyAll();

52 }

53 }

54

55 public synchronized void addAsync(String desc, Object... args) {

56 add(desc, args);

57 }

58

59 public synchronized Object addSync(String desc, Object... args) {

60 Call call = add(desc, args);

61 while (call.ready != true) {

62 try {

63 wait();

64 } catch (java.lang.InterruptedException ex) {

65 throw new RuntimeException(ex);

66 }

67 }

68 return call.result;

69 }

70

71 public static <T> T result(Class<T> cls) {

72 throw new UnpreparedChordedClass();

73 }

74 }

Listagem A.3. jchords/Chords.java

1 package jchords;

2

3 import java.util.Collection;

Page 121: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 95

4 import org.objectweb.asm.commons.Method;

5

6 public class JoinDescriptor {

7 public final Method method;

8 public final Method[] fragments;

9

10 public JoinDescriptor(Method method, Method... fragments) {

11 this.method = method;

12 this.fragments = fragments;

13 }

14

15 public JoinDescriptor(Method method, Collection<Method> fragments) {

16 this(method, fragments.toArray(new Method[fragments.size()]));

17 }

18

19 public JoinDescriptor(String method, String... fragments) {

20 this.method = Method.getMethod(method);

21

22 this.fragments = new Method[fragments.length];

23 for(int index = 0; index < fragments.length; ++index)

24 {

25 this.fragments[index] = Method.getMethod(fragments[index]);

26 }

27 }

28

29 }

Listagem A.4. jchords/JoinDescriptor.java

1 package jchords;

2 import java.util.*;

3 import org.objectweb.asm.commons.Method;

4

5 public class JoinFragment {

6 public final Method method;

7 public final Deque<Call> calls = new LinkedList<Call>();

8 public final List<JoinPattern> patterns = new ArrayList<JoinPattern>();

9

10 public JoinFragment(Method method) {

11 this.method = method;

12 }

Page 122: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

96 Apêndice A. Códigos Fonte

13

14 public Call add(Object[] args) {

15 Call call = new Call(method, args);

16 calls.addLast(call);

17 broadcast();

18 return call;

19 }

20

21 public void broadcast() {

22 for(JoinPattern pattern : patterns) {

23 pattern.brodcast();

24 }

25 }

26

27 public boolean isReady(int times) {

28 return calls.size() >= times;

29 }

30

31 public Call pop() {

32 return calls.removeFirst();

33 }

34 }

Listagem A.5. jchords/JoinFragment.java

1 package jchords;

2

3 import java.lang.reflect.Method;

4 import java.util.*;

5 import jchords.util.Utils;

6

7 public class JoinPattern {

8 public final Object object;

9 public final Method method;

10 public final List<JoinFragment> fragments = new ArrayList<JoinFragment>();

11

12 public JoinPattern(Object object, Method method) {

13 this.object = object;

14 this.method = method;

15 }

16

Page 123: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 97

17 public void brodcast() {

18 if(isReady()) { execute(); }

19 }

20

21 private void execute() {

22 List<Call> calls = popFragments();

23 broadcast(calls, invoke(getArguments(calls)));

24 }

25

26 private void broadcast(List<Call> calls, Object result) {

27 for(Call call : calls) {

28 call.result = result;

29 call.ready = true;

30 }

31 }

32

33 private List<Object> getArguments(List<Call> calls) {

34 List<Object> args = new LinkedList<Object>();

35 for(Call call : calls)

36 {

37 Collections.addAll(args, call.args);

38 }

39 return args;

40 }

41

42 private List<Call> popFragments() {

43 List<Call> calls = new LinkedList<Call>();

44 for(JoinFragment fragment : fragments)

45 {

46 calls.add(fragment.pop());

47 }

48 return calls;

49 }

50

51 private Object invoke(List<Object> args) {

52 try {

53 return method.invoke(object, args.toArray(new Object[args.size()]));

54 } catch(Exception ex) {

55 throw new RuntimeException(ex);

56 }

Page 124: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

98 Apêndice A. Códigos Fonte

57 }

58

59 private boolean isReady() {

60 Map<JoinFragment, Integer> counts = new HashMap<JoinFragment, Integer>();

61 for(JoinFragment fragment : fragments) {

62 int count = Utils.safe(counts.get(fragment), 0) + 1;

63 counts.put(fragment, count);

64 if(!fragment.isReady(count)) {

65 return false;

66 }

67 }

68 return true;

69 }

70

71 }

Listagem A.6. jchords/JoinPattern.java

1 package jchords.agents;

2

3 import static jchords.util.Utils.cast;

4 import java.util.*;

5 import jchords.annotations.Async;

6 import jchords.asm.ClassEnhancer;

7 import jchords.util.Constants;

8 import org.objectweb.asm.*;

9 import org.objectweb.asm.commons.*;

10 import org.objectweb.asm.tree.*;

11

12 public class AsyncTransformer extends ClassEnhancer implements Constants {

13

14 private class MethodTransformer extends MethodNode {

15 private static final String ASYNC_PREFIX = "Async$";

16

17 public MethodTransformer(int access, String name, String desc,

18 String signature, String[] exceptions) {

19 super(access, name, desc, signature, exceptions);

20 }

21

22 public void createAsyncMethod() {

23 GeneratorAdapter mg = new GeneratorAdapter(

Page 125: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 99

24 access, getMethod(), signature, getExceptions(), cv

25 );

26 mg.visitCode();

27 mg.push(type);

28 mg.push(name = ASYNC_PREFIX + name);

29 loadArgTypeArray(mg);

30 mg.loadThis();

31 mg.loadArgArray();

32 mg.invokeStatic(ASYNCCALL_TYPE, ASYNCCALL_STATIC_INVOKE);

33 mg.returnValue();

34 mg.endMethod();

35 }

36

37 private void loadArgTypeArray(GeneratorAdapter mg) {

38 Type[] args = Type.getArgumentTypes(desc);

39 mg.push(args.length);

40 mg.newArray(CLASS_TYPE);

41 for (int index = 0; index < args.length; ++index) {

42 mg.dup();

43 mg.push(index);

44 mg.push(args[index]);

45 mg.arrayStore(CLASS_TYPE);

46 }

47 }

48

49 private Method getMethod() {

50 return new Method(name, desc);

51 }

52

53 private Type[] getExceptions() {

54 List<Type> list = new LinkedList<Type>();

55 for (Object type : exceptions) {

56 list.add(Type.getObjectType(type.toString()));

57 }

58 return list.toArray(new Type[list.size()]);

59 }

60

61 AnnotationNode getAnnotation(Class<?> clazz) {

62 for (AnnotationNode annotation :

63 cast(AnnotationNode.class, this.visibleAnnotations)

Page 126: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

100 Apêndice A. Códigos Fonte

64 ) {

65 if(annotation.desc.equals(Type.getDescriptor(clazz))) {

66 return annotation;

67 }

68 }

69 return null;

70 }

71

72 @Override

73 public void visitEnd() {

74 if(getAnnotation(Async.class) != null) { createAsyncMethod(); }

75 accept(cv);

76 }

77 }

78

79 public AsyncTransformer(ClassVisitor visitor) {

80 super(visitor);

81 }

82

83 @Override public MethodVisitor visitMethod(

84 int access, String name, String desc, String sig, String[] exceptions

85 ) {

86 return new MethodTransformer(access, name, desc, sig, exceptions);

87 }

88 }

Listagem A.7. jchords/agents/AsyncTransformer.java

1 package jchords.agents;

2

3 import java.util.*;

4 import jchords.JoinDescriptor;

5 import jchords.asm.*;

6 import jchords.util.Constants;

7 import org.objectweb.asm.*;

8 import org.objectweb.asm.commons.*;

9

10 public class JoinTransformer extends ClassEnhancer implements Constants {

11 protected List<JoinDescriptor> joins = new LinkedList<JoinDescriptor>();

12

13 class ManagerMethod extends MethodEnhacer {

Page 127: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 101

14

15 protected ManagerMethod(

16 MethodVisitor mv, int access, String name, String desc

17 ) {

18 super(mv, access, name, desc);

19 active = isConstructor(method);

20 }

21

22 @Override protected void onMethodEnter() {

23 if(active) {

24 loadThis();

25 invokeVirtual(type, CHORDS_INIT);

26 super.onMethodEnter();

27 }

28 }

29 }

30

31 class SyncMethod extends MethodEnhacer {

32 private boolean enhanced = false;

33

34 protected SyncMethod(MethodVisitor mv, int access, String name, String

desc) {

35 super(mv, access, name, desc);

36 }

37

38 @Override public AnnotationVisitor visitAnnotation(String desc, boolean

visible) {

39 if(desc.equals(SYNC_TYPE.getDescriptor()))

40 {

41 active = true;

42 }

43 return super.visitAnnotation(desc, visible);

44 }

45

46 @Override public void visitMethodInsn(

47 int opcode, String owner, String name, String desc) {

48 if(

49 active &&

50 opcode == INVOKESTATIC &&

51 owner.equals(CHORDS_TYPE.getInternalName()) &&

Page 128: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

102 Apêndice A. Códigos Fonte

52 name.equals(CHORDS_RESULT.getName()) &&

53 desc.equals(CHORDS_RESULT.getDescriptor())

54 ) {

55 pop();

56 dispatch();

57 enhanced = true;

58 }

59 else

60 {

61 super.visitMethodInsn(opcode, owner, name, desc);

62 }

63 }

64

65 @Override protected void onMethodExit(int opcode) {

66 if(active && opcode != ATHROW && !enhanced) {

67 dispatch();

68 pop();

69 }

70 super.onMethodExit(opcode);

71 }

72

73 private void dispatch() {

74 loadThis();

75 getField(type, MANAGER_FIELD_NAME, CHORDS_TYPE);

76 push(getDecl(method));

77 loadArgArray();

78 invokeVirtual(CHORDS_TYPE, CHORDS_ADD_SYNC);

79 }

80 };

81

82 class AsyncMethod extends MethodEnhacer {

83 protected AsyncMethod(MethodVisitor mv, int access, String name, String

desc) {

84 super(mv, access, name, desc);

85 }

86

87 @Override public AnnotationVisitor visitAnnotation(String desc, boolean

visible) {

88 if(desc.equals(ASYNC_TYPE.getDescriptor())) {

89 active = true;

Page 129: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 103

90 }

91 return super.visitAnnotation(desc, visible);

92 }

93

94 @Override protected void onMethodExit(int opcode) {

95

96 if(active && opcode != ATHROW) {

97 loadThis();

98 getField(type, MANAGER_FIELD_NAME, CHORDS_TYPE);

99 push(getDecl(method));

100 loadArgArray();

101 invokeVirtual(CHORDS_TYPE, CHORDS_ADD_ASYNC);

102 }

103 super.onMethodExit(opcode);

104 }

105 };

106

107 class JoinMethod extends MethodEnhacer {

108 class JoinAnnotation extends AnnotationAdapter {

109 List<Method> fragments = new LinkedList<Method>();

110

111 public JoinAnnotation(AnnotationVisitor av) { super(av); }

112

113 public AnnotationVisitor visitArray(String name) {

114 AnnotationVisitor av = super.visitArray(name);

115 if(name.equals("value"))

116 {

117 av = new AnnotationAdapter(av) {

118 public void visit(String name, Object value) {

119 fragments.add(Method.getMethod(value.toString()));

120 super.visit(name, value);

121 }

122 };

123 }

124 return av;

125 }

126

127 public void visitEnd() {

128 joins.add(new JoinDescriptor(method, fragments));

129 super.visitEnd();

Page 130: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

104 Apêndice A. Códigos Fonte

130 }

131 };

132

133 public JoinMethod(MethodVisitor mv, int access, String name, String desc)

{

134 super(mv, access, name, desc);

135 }

136

137 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

138 AnnotationVisitor av = super.visitAnnotation(desc, visible);

139 if(desc.equals(JOIN_TYPE.getDescriptor())) {

140 av = new JoinAnnotation(av);

141 }

142 return av;

143 }

144 };

145

146 public JoinTransformer(ClassVisitor cv) { super(cv); }

147

148 public AnnotationVisitor visitAnnotation(String name, boolean visible) {

149 if(name.equals(CHORDED_TYPE.getDescriptor())) {

150 this.active = true;

151 }

152 return super.visitAnnotation(name, visible);

153 }

154

155 public MethodVisitor visitMethod(

156 int access, String name, String desc, String sig, String[] exceptions

157 ) {

158 MethodVisitor mv = super.visitMethod(access, name, desc, sig, exceptions)

;

159 if(active) {

160 mv = new ManagerMethod(mv, access, name, desc);

161 mv = new AsyncMethod(mv, access, name, desc);

162 mv = new SyncMethod(mv, access, name, desc);

163 mv = new JoinMethod(mv, access, name, desc);

164 }

165 return mv;

166 }

167

Page 131: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 105

168 public void visitEnd() {

169 if(active) { createManager(); }

170 super.visitEnd();

171 }

172

173 private void createManager() {

174 FieldVisitor fv = visitField(ACC_PROTECTED, MANAGER_FIELD_NAME,

CHORDS_TYPE.getDescriptor(), null, null);

175 fv.visitEnd();

176

177 GeneratorAdapter mg = new GeneratorAdapter(

178 ACC_PROTECTED, CHORDS_INIT, null, null, cv

179 );

180 mg.visitCode();

181 mg.loadThis();

182 mg.newInstance(CHORDS_TYPE);

183 mg.dup();

184 mg.loadThis();

185 mg.push(joins.size());

186 mg.newArray(JOINDESCRIPTOR_TYPE);

187 for(int idx = 0; idx < joins.size(); ++idx) {

188 JoinDescriptor pattern = joins.get(idx);

189 mg.dup();

190 mg.push(idx);

191 mg.newInstance(JOINDESCRIPTOR_TYPE);

192 mg.dup();

193 mg.push(MethodEnhacer.getDecl(pattern.method));

194 mg.push(pattern.fragments.length);

195 mg.newArray(STRING_TYPE);

196 for(int index = 0; index < pattern.fragments.length; ++index) {

197 mg.dup();

198 mg.push(index);

199 mg.push(MethodEnhacer.getDecl(pattern.fragments[index]));

200 mg.arrayStore(STRING_TYPE);

201 }

202 mg.invokeConstructor(JOINDESCRIPTOR_TYPE, JOINDESCRIPTOR_CTOR);

203 mg.arrayStore(JOINDESCRIPTOR_TYPE);

204 }

205 mg.invokeConstructor(CHORDS_TYPE, CHORDS_CTOR);

206 mg.putField(type, MANAGER_FIELD_NAME, CHORDS_TYPE);

Page 132: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

106 Apêndice A. Códigos Fonte

207 mg.returnValue();

208 mg.endMethod();

209 }

210 }

Listagem A.8. jchords/agents/JoinTransformer.java

1 package jchords.agents;

2

3 import static java.lang.Boolean.parseBoolean;

4 import static java.lang.System.getProperty;

5 import static org.objectweb.asm.ClassReader.*;

6 import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;

7 import java.io.PrintWriter;

8 import java.lang.instrument.*;

9 import java.security.ProtectionDomain;

10 import org.objectweb.asm.*;

11 import org.objectweb.asm.util.*;

12

13 public class Transformer implements ClassFileTransformer {

14 public static final boolean SHOW_BYTECODE = parseBoolean(

15 getProperty("jchords.showbytecode")

16 );

17

18 public byte[] transform(ClassLoader loader, String name, Class cls,

19 ProtectionDomain domain, byte[] bytes) {

20 ClassReader reader = new ClassReader(bytes);

21 ClassWriter writer = new ClassWriter(reader, COMPUTE_FRAMES);

22 try {

23 reader.accept(adapt(writer), SKIP_FRAMES);

24 } catch (Throwable ex) {

25 ex.printStackTrace();

26 }

27 return writer.toByteArray();

28 }

29

30 private ClassVisitor adapt(ClassVisitor cv) {

31 if (SHOW_BYTECODE) {

32 cv = new TraceClassVisitor(cv, new PrintWriter(System.out));

33 }

34 cv = new CheckClassAdapter(cv);

Page 133: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.1. Biblioteca 107

35 cv = new AsyncTransformer(cv);

36 cv = new JoinTransformer(cv);

37 return cv;

38 }

39

40 public static void premain(String args, Instrumentation instrumentation) {

41 instrumentation.addTransformer(new Transformer());

42 }

43 }

Listagem A.9. jchords/agents/Transformer.java

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.METHOD)

7 public @interface Async {}

Listagem A.10. jchords/annotations/Async.java

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.TYPE)

7 public @interface Chorded {}

Listagem A.11. jchords/annotations/Chorded.java

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.METHOD)

7 public @interface Join {

8 String[] value();

9 }

Listagem A.12. jchords/annotations/Join.java

Page 134: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

108 Apêndice A. Códigos Fonte

1 package jchords.annotations;

2

3 import java.lang.annotation.*;

4

5 @Retention(RetentionPolicy.RUNTIME)

6 @Target(ElementType.METHOD)

7 public @interface Sync {}

Listagem A.13. jchords/annotations/Sync.java

1 package jchords.util;

2

3 import jchords.*;

4 import jchords.annotations.*;

5 import jchords.annotations.Join;

6 import org.objectweb.asm.*;

7 import org.objectweb.asm.commons.Method;

8

9 public interface Constants extends Opcodes {

10 Type STRING_TYPE = Type.getType(String.class);

11 Type CLASS_TYPE = Type.getType(Class.class);

12 Type OBJECT_TYPE = Type.getType(Object.class);

13

14 Type JOIN_TYPE = Type.getType(Join.class);

15 Type SYNC_TYPE = Type.getType(Sync.class);

16 Type ASYNC_TYPE = Type.getType(Async.class);

17 Type ASYNCCALL_TYPE = Type.getType(AsyncCall.class);

18 Type CHORDED_TYPE = Type.getType(Chorded.class);

19 Type CHORDS_TYPE = Type.getType(Chords.class);

20 Type JOINPATTERN_TYPE = Type.getType(JoinPattern.class);

21 Type JOINDESCRIPTOR_TYPE = Type.getType(JoinDescriptor.class);

22

23 Method ASYNCCALL_STATIC_INVOKE = Method.getMethod(

24 "void invoke(Class, String, Class[], Object, Object[])"

25 );

26 Method JOINDESCRIPTOR_CTOR = Method.getMethod(

27 "void <init>(String, String[])"

28 );

29 Method CHORDS_CTOR = Method.getMethod(

30 "void <init>(Object,jchords.JoinDescriptor[])"

Page 135: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 109

31 );

32 Method CHORDS_INIT = Method.getMethod("void $initChordManager$()");

33 Method CHORDS_ADD_ASYNC = Method.getMethod("void addAsync(String, Object[])

");

34 Method CHORDS_ADD_SYNC = Method.getMethod("Object addSync(String, Object[])

");

35 Method CHORDS_RESULT = Method.getMethod("Object result(Class)");

36

37 String MANAGER_FIELD_NAME = "$ChordManager$";

38 }

Listagem A.14. jchords/util/Constants.java

A.2 Casos de Uso

A.2.1 Métodos Assíncronos

1 package usecases.async.java;

2

3 import static jchords.util.Utils.delay;

4

5 public class Example1 extends Thread {

6 public void run() {

7 delay(1000, "run");

8 }

9

10 public static void main(String[] args) {

11 System.out.println("inicio");

12 for (int index = 0; index < 5; ++index) {

13 new Example1().start();

14 }

15 System.out.println("fim");

16 }

17 }

Listagem A.15. usecases/async/java/Example1.java

1 package usecases.async.java;

2

3 import static jchords.util.Utils.delay;

Page 136: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

110 Apêndice A. Códigos Fonte

4

5 public class Example2 {

6 public void foo(int x) {

7 delay(1000, "foo " + x);

8 }

9

10 public void bar() {

11 delay(1000, "bar");

12 }

13

14 public static void main(String[] args) {

15 System.out.println("inicio");

16 final Example2 example = new Example2();

17 for (int index = 0; index < 5; ++index) {

18 final int local = index;

19 new Thread() {

20 public void run() {

21 example.foo(local);

22 }

23 }.start();

24 new Thread() {

25 public void run() {

26 example.bar();

27 }

28 }.start();

29 }

30 System.out.println("fim");

31 }

32 }

Listagem A.16. usecases/async/java/Example2.java

1 package usecases.async.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Example1 {

7 @Async public void foo() {

8 delay(1000, "foo");

9 }

Page 137: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 111

10

11 public static void main(String[] args) {

12 System.out.println("inicio");

13 Example1 example = new Example1();

14 for (int index = 0; index < 5; ++index) {

15 example.foo();

16 }

17 System.out.println("fim");

18 }

19 }

Listagem A.17. usecases/async/jchords/Example1.java

1 package usecases.async.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Example2 {

7 @Async public void foo(int x) {

8 delay(1000, "foo " + x);

9 }

10

11 @Async public void bar() {

12 delay(1000, "bar");

13 }

14

15 public static void main(String[] args) {

16 System.out.println("inicio");

17 Example2 example = new Example2();

18 for (int index = 0; index < 5; ++index) {

19 example.foo(index);

20 example.bar();

21 }

22 System.out.println("fim");

23 }

24 }

Listagem A.18. usecases/async/jchords/Example2.java

Page 138: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

112 Apêndice A. Códigos Fonte

A.2.2 Jantar dos Filósofos

1 package usecases.diningphilosophers.higienic.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Fork {

6 @Sync public void grab() {}

7 @Async public void release() {}

8

9 public Fork() {

10 release();

11 }

12

13 @Join({"void grab()", "void release()"}) public void grab_release() {}

14 }

Listagem A.19. usecases/diningphilosophers/higienic/jchords/Fork.java

1 package usecases.diningphilosophers.higienic.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.*;

5

6 @Chorded public class Phil {

7 private static int seed = 0;

8 public final int id = ++seed;

9

10 @Async public void requires(Phil phil) {}

11 @Async public void clean(Fork fork) {}

12 @Async public void dirty(Fork fork) {}

13 @Async public void request(Phil phil) {}

14 @Async public void hungry() {}

15 @Sync public void eating() {}

16

17 @Join({"void eating()", "void hungry()",

18 "void clean(usecases.diningphilosophers.higienic.jchords.Fork)",

19 "void clean(usecases.diningphilosophers.higienic.jchords.Fork)"})

20 public void eat_hungry(Fork left, Fork right) {

21 left.grab();

22 right.grab();

Page 139: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 113

23 eat();

24 left.release();

25 right.release();

26 dirty(left);

27 dirty(right);

28 }

29

30 @Join({"void hungry()",

31 "void requires(usecases.diningphilosophers.higienic.jchords.Phil)"})

32 public void hungry_requires(Phil phil) {

33 hungry();

34 phil.request(this);

35 }

36

37 @Join({"void request(usecases.diningphilosophers.higienic.jchords.Phil)",

38 "void dirty(usecases.diningphilosophers.higienic.jchords.Fork)"})

39 public void request_dirty(Phil phil, Fork fork) {

40 requires(phil);

41 phil.clean(fork);

42 }

43

44 @Async public void execute() {

45 while (true) {

46 think();

47 hungry();

48 eating();

49 }

50 }

51

52 private void eat() {

53 delay(5000, "Filósofo " + id + " comendo");

54 }

55

56 private void think() {

57 delay(1000, "Filósofo " + id + " pensando");

58 }

59 }

Listagem A.20. usecases/diningphilosophers/higienic/jchords/Phil.java

1 package usecases.diningphilosophers.higienic.jchords;

Page 140: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

114 Apêndice A. Códigos Fonte

2

3 public class Runner {

4 private static final int SEATS = 5;

5

6 public static void main(String[] args) throws InterruptedException {

7 System.out.println("inicio");

8 Phil[] phils = new Phil[SEATS];

9

10 for(int index = 0; index < SEATS; ++index) {

11 phils[index] = new Phil();

12 if(index != 0) {

13 phils[index].requires(phils[index-1]);

14 } else {

15 phils[index].dirty(new Fork());

16 }

17 if(index != SEATS - 1) {

18 phils[index].dirty(new Fork());

19 } else {

20 phils[index].requires(phils[0]);

21 }

22 }

23 for(int index = 0; index < SEATS; ++index) {

24 phils[index].execute();

25 }

26 System.out.println("fim");

27 }

28 }

Listagem A.21. usecases/diningphilosophers/higienic/jchords/Runner.java

1 package usecases.diningphilosophers.waiter.java;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Fork {

6 @Sync public void grab() {}

7 @Async public void release() {}

8

9 public Fork() {

10 release();

11 }

Page 141: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 115

12

13 @Join({"void grab()", "void release()"}) public void grab_release() {}

14 }

Listagem A.22. usecases/diningphilosophers/waiter/java/Fork.java

1 package usecases.diningphilosophers.waiter.java;

2

3 import static jchords.util.Utils.delay;

4

5 public class Phil extends Thread {

6 private static int seed = 0;

7 public final int id = ++seed;

8 private final Waiter waiter;

9 private final Fork left;

10 private final Fork right;

11

12 public Phil(Waiter waiter, Fork left, Fork right) {

13 this.waiter = waiter;

14 this.left = left;

15 this.right = right;

16 }

17

18 public void run() {

19 try {

20 while (true) {

21 think();

22 waiter.enter();

23 left.grab();

24 right.grab();

25 eat();

26 left.release();

27 right.release();

28 waiter.leave();

29 }

30 } catch (InterruptedException ex) {

31 ex.printStackTrace();

32 }

33 }

34

35 private void eat() {

Page 142: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

116 Apêndice A. Códigos Fonte

36 delay(1000, "Filósofo " + id + " comendo");

37 }

38

39 private void think() {

40 delay(5000, "Filósofo " + id + " pensando");

41 }

42 }

Listagem A.23. usecases/diningphilosophers/waiter/java/Phil.java

1 package usecases.diningphilosophers.waiter.java;

2

3 public class Runner {

4 public static final int SEATS = 5;

5

6 public static void main(String[] args) throws InterruptedException {

7 System.out.println("inicio");

8 Waiter waiter = new Waiter();

9 Fork[] forks = new Fork[SEATS];

10 for(int index = 0; index < SEATS; ++index) {

11 forks[index] = new Fork();

12 }

13 for(int index = 0; index < SEATS; ++index) {

14 new Phil(waiter, forks[index], forks[(index + 1) % SEATS]).start();

15 }

16 System.out.println("fim");

17 }

18 }

Listagem A.24. usecases/diningphilosophers/waiter/java/Runner.java

1 package usecases.diningphilosophers.waiter.java;

2

3 public class Waiter {

4 private int count = Runner.SEATS - 1;

5

6 public synchronized void enter() throws InterruptedException {

7 while(count > 0) {

8 wait();

9 }

10 --count;

Page 143: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 117

11 }

12

13 public synchronized void leave() {

14 ++count;

15 notifyAll();

16 }

17 }

Listagem A.25. usecases/diningphilosophers/waiter/java/Waiter.java

1 package usecases.diningphilosophers.waiter.jchords;

2

3 import jchords.annotations.*;

4

5 public class Fork {

6 @Sync public void grab() {}

7 @Async public void release() {}

8

9 public Fork() {

10 release();

11 }

12

13 @Join({"void grab()", "void release()"}) public void grab_release() {}

14 }

Listagem A.26. usecases/diningphilosophers/waiter/jchords/Fork.java

1 package usecases.diningphilosophers.waiter.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Phil {

7 private static int seed = 0;

8 public final int id = ++seed;

9 private final Waiter waiter;

10 private final Fork left;

11 private final Fork right;

12

13 public Phil(Waiter waiter, Fork left, Fork right) {

14 this.waiter = waiter;

Page 144: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

118 Apêndice A. Códigos Fonte

15 this.left = left;

16 this.right = right;

17 }

18

19 @Async public void execute() {

20 while (true) {

21 think();

22 waiter.enter();

23 left.grab();

24 right.grab();

25 eat();

26 left.release();

27 right.release();

28 waiter.leave();

29 }

30 }

31

32 private void eat() {

33 delay(1000, "Filósofo " + id + " comendo");

34 }

35

36 private void think() {

37 delay(5000, "Filósofo " + id + " pensando");

38 }

39 }

Listagem A.27. usecases/diningphilosophers/waiter/jchords/Phil.java

1 package usecases.diningphilosophers.waiter.jchords;

2

3 public class Runner {

4 public static final int SEATS = 5;

5

6 public static void main(String[] args) throws InterruptedException {

7 System.out.println("inicio");

8 Waiter waiter = new Waiter();

9 Fork[] forks = new Fork[SEATS];

10 for(int index = 0; index < SEATS; ++index) {

11 forks[index] = new Fork();

12 }

13 for(int index = 0; index < SEATS; ++index) {

Page 145: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 119

14 new Phil(waiter, forks[index], forks[(index + 1) % SEATS]).execute();

15 }

16 System.out.println("fim");

17 }

18 }

Listagem A.28. usecases/diningphilosophers/waiter/jchords/Runner.java

1 package usecases.diningphilosophers.waiter.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Waiter {

6 @Sync public void enter() {}

7 @Async public void leave() {}

8

9 public Waiter() {

10 for (int index = 0; index < Runner.SEATS - 1; ++index) {

11 leave();

12 }

13 }

14

15 @Join({"void enter()", "void leave()"}) public void enter_leave() {}

16 }

Listagem A.29. usecases/diningphilosophers/waiter/jchords/Waiter.java

A.2.3 Produtor Consumidor

1 package usecases.producerconsumer.java;

2

3 public class Buffer {

4 private int count = 0;

5 private int[] resources = new int[Runner.BUFFER_SIZE];

6

7 public synchronized void put(int res) throws InterruptedException {

8 while (count == resources.length) {

9 wait();

10 }

11 resources[count++] = res;

12 notifyAll();

Page 146: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

120 Apêndice A. Códigos Fonte

13 }

14

15 public synchronized int get() throws InterruptedException {

16 while (count == 0) {

17 wait();

18 }

19 int res = resources[--count];

20 notifyAll();

21 return res;

22 }

23 }

Listagem A.30. usecases/producerconsumer/java/Buffer.java

1 package usecases.producerconsumer.java;

2

3 import static jchords.util.Utils.delay;

4

5 public class Consumer extends Thread {

6 private static int seed = 0;

7 private final int id = ++seed;

8 private final Buffer buffer;

9

10 public Consumer(Buffer buffer) {

11 this.buffer = buffer;

12 }

13

14 public void run() {

15 try {

16 while (true) {

17 consume(buffer.get());

18 }

19 } catch (InterruptedException ex) {

20 ex.printStackTrace();

21 }

22 }

23

24 private void consume(int resource) {

25 delay(0, 10000, "Consumidor " + id + " consumindo " + resource);

26 }

27 }

Page 147: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 121

Listagem A.31. usecases/producerconsumer/java/Consumer.java

1 package usecases.producerconsumer.java;

2

3 import static jchords.util.Utils.delay;

4

5 public class Producer extends Thread {

6 private static int seed = 0;

7 private final int id = ++seed;

8 private final Buffer buffer;

9

10 public Producer(Buffer buffer) {

11 this.buffer = buffer;

12 }

13

14 public void run() {

15 try {

16 while (true) {

17 buffer.put(produce());

18 }

19 } catch (InterruptedException ex) {

20 ex.printStackTrace();

21 }

22 }

23

24 private int produce() throws InterruptedException {

25 int resource = (int) Math.random() * 100000000;

26 delay(0, 10000, "Produtor " + id + " produzindo " + resource);

27 return resource;

28 }

29 }

Listagem A.32. usecases/producerconsumer/java/Producer.java

1 package usecases.producerconsumer.java;

2

3 public class Runner {

4 public static final int PRODUCERS = 5;

5 public static final int CONSUMERS = 8;

6 public static final int BUFFER_SIZE = 10;

Page 148: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

122 Apêndice A. Códigos Fonte

7

8 public static void main(String[] args) {

9 System.out.println("inicio");

10 Buffer buffer = new Buffer();

11 for(int index = 0; index < PRODUCERS; ++index) {

12 new Producer(buffer).start();

13 }

14 for(int index = 0; index < CONSUMERS; ++index) {

15 new Consumer(buffer).start();

16 }

17 System.out.println("fim");

18 }

19 }

Listagem A.33. usecases/producerconsumer/java/Runner.java

1 package usecases.producerconsumer.jchords;

2

3 import jchords.Chords;

4 import jchords.annotations.*;

5

6 @Chorded public class Buffer {

7 @Async public void value(int val) {}

8 @Async public void free() {}

9 @Sync public void put(int val) {}

10 @Sync public int get() { return Chords.result(int.class); }

11

12 public Buffer() {

13 for(int index = 0 ; index < Runner.BUFFER_SIZE; ++index) {

14 free();

15 }

16 }

17

18 @Join({"int get()", "void value(int)"}) public int get_value(int res) {

19 free();

20 return res;

21 }

22

23 @Join({"void put(int)", "void free()"}) public void put_free(int res) {

24 value(res);

25 }

Page 149: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 123

26 }

Listagem A.34. usecases/producerconsumer/jchords/Buffer.java

1 package usecases.producerconsumer.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Consumer {

7 private static int seed = 0;

8 private final Buffer buffer;

9 private final int id = ++seed;

10

11 public Consumer(Buffer buffer) {

12 this.buffer = buffer;

13 }

14

15 @Async public void execute() {

16 while (true) {

17 consume(buffer.get());

18 }

19 }

20

21 private void consume(int resource) {

22 delay(0, 10000, "Consumidor " + id + " consumindo " + resource);

23 }

24 }

Listagem A.35. usecases/producerconsumer/jchords/Consumer.java

1 package usecases.producerconsumer.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Producer {

7 private static int seed = 0;

8 private final int id = ++seed;

9 private int resource = id * 100000;

10 private final Buffer buffer;

Page 150: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

124 Apêndice A. Códigos Fonte

11

12 public Producer(Buffer buffer) {

13 this.buffer = buffer;

14 }

15

16 @Async public void execute() {

17 while(true) {

18 buffer.put(produce());

19 }

20 }

21

22 private int produce() {

23 delay(0, 10000, "Produtor " + id + " produzindo " + resource++);

24 return resource;

25 }

26

27 }

Listagem A.36. usecases/producerconsumer/jchords/Producer.java

1 package usecases.producerconsumer.jchords;

2

3 public class Runner {

4 private static final int PRODUCERS = 5;

5 private static final int CONSUMERS = 5;

6 public static final int BUFFER_SIZE = 10;

7

8 public static void main(String[] args) throws InterruptedException {

9 System.out.println("inicio");

10 Buffer buffer = new Buffer();

11 for(int index = 0; index < PRODUCERS; ++index) {

12 new Producer(buffer).execute();

13 }

14 for(int index = 0; index < CONSUMERS; ++index) {

15 new Consumer(buffer).execute();

16 }

17 System.out.println("fim");

18 }

19

20 }

Page 151: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 125

Listagem A.37. usecases/producerconsumer/jchords/Runner.java

A.2.4 Papai Noel

1 package usecases.santaclaus.java;

2

3 import static jchords.util.Utils.delay;

4

5 class Elf extends Thread {

6 private static int seed = 0;

7 private int id = ++seed;

8

9 public void run() {

10 try {

11 while (true) {

12 working();

13 SantaClaus.Santa.ElvesGroup.Register();

14 SantaClaus.Santa.SantaMonitor.EnterOffice();

15 consulting();

16 SantaClaus.Santa.SantaMonitor.LeaveOffice();

17 }

18 } catch (InterruptedException e) {}

19 }

20

21 private void consulting() {

22 delay(0, 2000, "Elfo " + id + " consultando");

23 }

24

25 private void working() {

26 delay(0, 6000, "Elfo " + id + " trabalhando");

27 }

28 }

Listagem A.38. usecases/santaclaus/java/Elf.java

1 package usecases.santaclaus.java;

2

3 class Group {

4 private static final int Open = 0;

Page 152: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

126 Apêndice A. Códigos Fonte

5 private static final int Closed = 1;

6 private int GroupSize;

7 private int GroupID;

8 private int Waiting = 0;

9 private int Entrance = Open;

10 private int ExitDoor = Closed;

11

12 Group(int Size, int ID) {

13 GroupID = ID;

14 GroupSize = Size;

15 }

16

17 synchronized void Register() throws InterruptedException {

18 while (Entrance == Closed) {

19 wait();

20 }

21 Waiting++;

22 if(Waiting < GroupSize) {

23 while (ExitDoor == Closed) {

24 wait();

25 }

26 } else {

27 Entrance = Closed;

28 ExitDoor = Open;

29 notifyAll();

30 }

31 Waiting--;

32 if(Waiting == 0) {

33 SantaClaus.Santa.SantaMonitor.Wake(GroupID);

34 }

35 }

36

37 synchronized void OpenDoor() {

38 Entrance = Open;

39 ExitDoor = Closed;

40 notifyAll();

41 }

42 }

Listagem A.39. usecases/santaclaus/java/Group.java

Page 153: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 127

1 package usecases.santaclaus.java;

2

3 class Monitor {

4 private static final int Sleeping = 0;

5 private static final int Harnessing = 1;

6 private static final int ShowingIn = 2;

7 private static final int Delivering = 3;

8 private static final int Consulting = 4;

9 private static final int UnHarnessing = 5;

10 private static final int ShowingOut = 6;

11

12 private int ReindeerHarnessed = 0;

13 private int ElvesEntered = 0;

14 private int ReindeerTeam;

15 private int ElfTeam;

16 private int State = Sleeping;

17

18 Monitor(int RTeam, int ETeam) {

19 ReindeerTeam = RTeam;

20 ElfTeam = ETeam;

21 }

22

23 synchronized void Wake(int GroupID) throws InterruptedException {

24 while (State != Sleeping) {

25 wait();

26 }

27 if(GroupID == SantaClaus.REINDEER_ID) {

28 State = Harnessing;

29 } else {// GroupID == SantaClaus.ElvesID

30 State = ShowingIn;

31 }

32 notifyAll();

33 }

34

35 synchronized int Who() throws InterruptedException {

36 while ((State != Delivering) && (State != Consulting)) {

37 wait();

38 }

39 if(State == Delivering) {

Page 154: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

128 Apêndice A. Códigos Fonte

40 return SantaClaus.REINDEER_ID;

41 } else {// State == Consulting

42 return SantaClaus.ELVES_ID;

43 }

44 }

45

46 synchronized void Reset(int GroupID) throws InterruptedException {

47 if(GroupID == SantaClaus.REINDEER_ID) {

48 State = UnHarnessing;

49 } else {// GroupID == SantaClaus.ElvesID

50 State = ShowingOut;

51 }

52 notifyAll();

53 }

54

55 synchronized void Harness() throws InterruptedException {

56 while (State != Harnessing) {

57 wait();

58 }

59 ReindeerHarnessed++;

60 if(ReindeerHarnessed == ReindeerTeam) {

61 State = Delivering;

62 notifyAll();

63 }

64 }

65

66 synchronized void UnHarness() throws InterruptedException {

67 while (State != UnHarnessing) {

68 wait();

69 }

70 ReindeerHarnessed--;

71 if(ReindeerHarnessed == 0) {

72 State = Sleeping;

73 SantaClaus.Santa.ReinsGroup.OpenDoor();

74 notifyAll();

75 }

76 }

77

78 synchronized void EnterOffice() throws InterruptedException {

79 while (State != ShowingIn) {

Page 155: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 129

80 wait();

81 }

82 ElvesEntered++;

83 if(ElvesEntered == ElfTeam) {

84 State = Consulting;

85 notifyAll();

86 }

87 }

88

89 synchronized void LeaveOffice() throws InterruptedException {

90 while (State != ShowingOut) {

91 wait();

92 }

93 ElvesEntered--;

94 if(ElvesEntered == 0) {

95 State = Sleeping;

96 SantaClaus.Santa.ElvesGroup.OpenDoor();

97 notifyAll();

98 }

99 }

100

101 }

Listagem A.40. usecases/santaclaus/java/Monitor.java

1 package usecases.santaclaus.java;

2

3 import static jchords.util.Utils.delay;

4

5 class Reindeer extends Thread {

6 private static int seed = 0;

7 private int id = ++seed;

8

9 public void run() {

10 try {

11 while (true) {

12 vacationing();

13 SantaClaus.Santa.ReinsGroup.Register();

14 SantaClaus.Santa.SantaMonitor.Harness();

15 delivering();

16 SantaClaus.Santa.SantaMonitor.UnHarness();

Page 156: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

130 Apêndice A. Códigos Fonte

17 }

18 } catch (InterruptedException e) {}

19 }

20

21 private void delivering() {

22 delay(0, 1000, "Rena " + id + " entregando brinquedos");

23 }

24

25 private void vacationing() {

26 delay(0, 10000, "Rena " + id + " de férias");

27 }

28

29 }

Listagem A.41. usecases/santaclaus/java/Reindeer.java

1 package usecases.santaclaus.java;

2

3 public class Runner {

4 private static final int REINDEER = 9;

5 private static final int ELVES = 10;

6

7 public static void main(String[] args) {

8 System.out.println("inicio");

9 for (int i = 0; i < REINDEER; i++) {

10 new Reindeer().start();

11 }

12 for (int i = 0; i < ELVES; i++) {

13 new Elf().start();

14 }

15 SantaClaus.Santa.start();

16 System.out.println("fim");

17 }

18 }

Listagem A.42. usecases/santaclaus/java/Runner.java

1 package usecases.santaclaus.java;

2

3 class SantaClaus extends Thread {

4 static final int REIN_TEAM = 9;

Page 157: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 131

5 static final int ELF_TEAM = 3;

6

7 static final int REINDEER_ID = 1;

8 static final int ELVES_ID = 2;

9

10 public static SantaClaus Santa = new SantaClaus();

11 Monitor SantaMonitor = new Monitor(REIN_TEAM, ELF_TEAM);

12 public Group ReinsGroup = new Group(REIN_TEAM, REINDEER_ID);

13 public Group ElvesGroup = new Group(ELF_TEAM, ELVES_ID);

14

15 public void run() {

16 try {

17 int signalled;

18 while (true) {

19 sleeping();

20 signalled = SantaMonitor.Who();

21 if(signalled == REINDEER_ID) {

22 delivering();

23 } else if(signalled == ELVES_ID) {

24 consulting();

25 }

26 SantaMonitor.Reset(signalled);

27 }

28 } catch (InterruptedException e) {}

29 }

30

31 private void consulting() {

32 System.out.println("Papai Noel consultando");

33 }

34

35 private void delivering() {

36 System.out.println("Papai Noel entregando brinquedos");

37 }

38

39 private void sleeping() {

40 System.out.println("Papai Noel dormindo");

41 }

42 }

Listagem A.43. usecases/santaclaus/java/SantaClaus.java

Page 158: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

132 Apêndice A. Códigos Fonte

1 package usecases.santaclaus.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Elf {

7 private static int seed = 0;

8 private int id = ++seed;

9

10 @Async public void execute() {

11 while (true) {

12 working();

13 SantaClaus.INSTANCE.elf();

14 SantaClaus.INSTANCE.roomin.entry();

15 consulting();

16 SantaClaus.INSTANCE.roomout.entry();

17 }

18 }

19

20 private void consulting() {

21 delay(0, 2000, "Elfo " + id + " consultando");

22 }

23

24 private void working() {

25 delay(0, 6000, "Elfo " + id + " trabalhando");

26 }

27 }

Listagem A.44. usecases/santaclaus/jchords/Elf.java

1 package usecases.santaclaus.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class Group {

6 @Sync public void entry() {}

7 @Async public void tokens(int n) {}

8 @Sync public void waitt() {}

9 @Async public void allgone() {}

10

Page 159: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 133

11 public void accept(int n) {

12 tokens(n);

13 waitt();

14 }

15

16 @Join({"void entry()", "void tokens(int)"})

17 public void entry_tokens(int n) {

18 if (--n == 0) {

19 allgone();

20 } else {

21 tokens(n);

22 }

23 }

24

25 @Join({"void waitt()", "void allgone()"}) public void wait_allgone() {}

26 }

Listagem A.45. usecases/santaclaus/jchords/Group.java

1 package usecases.santaclaus.jchords;

2

3 import static jchords.util.Utils.delay;

4 import jchords.annotations.Async;

5

6 public class Reindeer {

7 private static int seed = 0;

8 private int id = ++seed;

9

10 @Async public void execute() {

11 while (true) {

12 vacationing();

13 SantaClaus.INSTANCE.rein();

14 SantaClaus.INSTANCE.harness.entry();

15 delivering();

16 SantaClaus.INSTANCE.unharness.entry();

17 }

18 }

19

20 private void delivering() {

21 delay(0, 1000, "Rena " + id + " entregando brinquedos");

22 }

Page 160: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

134 Apêndice A. Códigos Fonte

23

24 private void vacationing() {

25 delay(0, 10000, "Rena " + id + " de férias");

26 }

27 }

Listagem A.46. usecases/santaclaus/jchords/Reindeer.java

1 package usecases.santaclaus.jchords;

2

3 public class Runner {

4

5 private static final int REINDEER = 9;

6 private static final int ELVES = 10;

7

8 public static void main(String[] args) throws InterruptedException {

9 System.out.println("inicio");

10 for (int i = 0; i < REINDEER; i++) {

11 new Reindeer().execute();

12 }

13 for (int i = 0; i < ELVES; i++) {

14 new Elf().execute();

15 }

16 System.out.println("fim");

17 }

18 }

Listagem A.47. usecases/santaclaus/jchords/Runner.java

1 package usecases.santaclaus.jchords;

2

3 import jchords.annotations.*;

4

5 @Chorded public class SantaClaus {

6 public static final int REIN_TEAM = 9;

7 public static final int ELF_TEAM = 3;

8 public static SantaClaus INSTANCE = new SantaClaus();

9

10 public final Group harness = new Group();

11 public final Group unharness = new Group();

12 public final Group roomin = new Group();

Page 161: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 135

13 public final Group roomout = new Group();

14

15 private SantaClaus() {

16 elves(0);

17 reins(0);

18 elvesfirst();

19 sleep();

20 }

21

22 @Async public void sleep() {

23 System.out.println("Papai Noel dormindo");

24 }

25 @Async public void elf() {}

26 @Async public void elves(int e) {}

27 @Async public void elvesready() {}

28 @Async public void elvesfirst() {}

29 @Async public void rein() {}

30 @Async public void reins(int i) {}

31 @Async public void reinsready() {}

32 @Async public void reinsfirst() {}

33

34 @Join({"void reinsfirst()", "void elvesfirst()"})

35 public void reinfirst_elvesfirst() {}

36

37 @Join({"void elf()", "void elves(int)"}) public void elf_elves(int e) {

38 if (++e == ELF_TEAM) {

39 elvesready();

40 } else {

41 elves(e);

42 }

43 }

44

45 @Join({"void rein()", "void reins(int)"}) public void rein_reins(int r) {

46 if (++r == REIN_TEAM) {

47 reinsfirst();

48 reinsready();

49 } else {

50 reins(r);

51 }

52 }

Page 162: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

136 Apêndice A. Códigos Fonte

53

54 @Join({"void sleep()", "void reinsready()"})

55 public void sleep_reinsready() {

56 harness.accept(REIN_TEAM);

57 elvesfirst();

58 reins(0);

59 delivering();

60 unharness.accept(REIN_TEAM);

61 sleep();

62 }

63

64 @Join({"void sleep()", "void elvesready()", "void elvesfirst()"})

65 public void sleep_elvesready() {

66 elvesfirst();

67 roomin.accept(ELF_TEAM);

68 elves(0);

69 consulting();

70 roomout.accept(ELF_TEAM);

71 sleep();

72 }

73

74 private void consulting() {

75 System.out.println("Papai Noel consultando");

76 }

77

78 private void delivering() {

79 System.out.println("Papai Noel entregando brinquedos");

80 }

81 }

Listagem A.48. usecases/santaclaus/jchords/SantaClaus.java

A.2.5 Buffer Simples

1 package usecases.simplebuffer.jchords;

2

3 import jchords.Chords;

4 import jchords.annotations.*;

5

6 @Chorded public class Buffer {

Page 163: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

A.2. Casos de Uso 137

7 @Async public void put(int var) {}

8 @Sync public int get() { return Chords.result(int.class); }

9 @Join({"int get()", "void put(int)"}) public int get_put(int var) {

10 return var;

11 }

12 }

Listagem A.49. usecases/simplebuffer/jchords/Buffer.java

1 package usecases.simplebuffer.jchords;

2

3 import jchords.*;

4 import jchords.annotations.*;

5 import jchords.annotations.Join;

6

7 @Chorded class BufferClass {

8 public BufferClass() {

9 $initChordManager$();

10 }

11

12 @Async public void Async$put(int value) {

13 $ChordManager$.addAsync("void put(int)", value);

14 }

15

16 public void put(int value) {

17 AsyncCall.invoke(BufferClass.class, "Async$put",

18 new Class<?>[] {int.class}, this, new Object[] {value});

19 }

20

21 @Sync public int get() {

22 return (Integer)$ChordManager$.addSync("int get()");

23 }

24

25 @Join({ "get()", "put(int)"}) public int get_put(int value) {

26 return value;

27 }

28

29 protected Chords $ChordManager$;

30

31 protected void $initChordManager$() {

32 $ChordManager$ = new Chords(this,

Page 164: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

138 Apêndice A. Códigos Fonte

33 new JoinDescriptor("int get_put(int)", "int get()","void put(int)")

34 );

35 }

36 }

Listagem A.50. usecases/simplebuffer/jchords/BufferClass.java

Page 165: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

Referências Bibliográficas

Benton, N. (2003). Jingle bells: Solving the santa claus problem in Polyphonic C#.

Benton, N.; Bierman, G.; Cardelli, L.; Meijer, E.; Russo, C. & Schulte, W. (2004). Cω.

Benton, N.; Cardelli, L. & Fournet, C. (2002). Modern concurrency abstractions forC#. In ACM Transactions on Programming Languages and Systems, pp. 415–440.Springer.

Benton, N.; Cardelli, L. & Fournet, C. (2007). Introduction to Polyphonic C#.

Berry, G. & Boudol, G. (1992). The chemical abstract machine. Theoretical ComputerScience, 96(1):217–248.

Bruneton, E. (2007). ASM 3.0: A Java bytecode engineering library.

Buckley, A. (2004). JSR 175: A metadata facility for the Java programming language.

Butenhof, D. (1997). Programming with POSIX Threads. Professional ComputingSeries. Addison-Wesley.

Chandy, K. M. & Misra, J. (1984). The drinking philosophers problem. ACM Tran-sactions on Programming Languages and Systems, 6:632–646.

Chrysanthakopoulos, G. & Singh, S. (2005). An asynchronous messaging library forC#. In SCOOL Conference Proceedings.

Dijkstra, E. W. (1975). Guarded commands, non-determinacy and formal derivationof programs. Comm. ACM, 18(8):453–457.

Drossopoulou, S.; Petrounias, A.; Buckley, A. & Eisenbach, S. (2006). SCHOOL: asmall chorded object-oriented language. Electronic Notes in Theoretical ComputerScience, 135(3):37–47.

Fournet, C.; Fessant, F. L.; Maranget, L. & Schmitt, A. (2002). JoCaml: A language forconcurrent distributed and mobile programming. In Advanced Functional Program-ming, volume 2638 of Lecture Notes in Computer Science, pp. 129–158. Springer.

139

Page 166: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

140 REFERÊNCIAS BIBLIOGRÁFICAS

Fournet, C. & Gonthier, G. (1996). The reflexive CHAM and the join-calculus. InProceedings of the 23rd ACM Symposium on Principles of Programming Languages,pp. 372–385. ACM Press.

Fournet, C. & Gonthier, G. (2000). The join calculus: A language for distributed mobileprogramming. In APPSEM, volume 2395 of Lecture Notes in Computer Science, pp.268–332. Springer.

Gamma, E.; Helm, R.; Johnson, R. & Vlissides, J. (1995). Design Patterns: Elementsof Resusable Object-Oriented Software. Addison-Wesley Professional.

Gosling, J.; Joy, B.; Steele, G. & Bracha, G. (2005). The Java(TM) Language Specifi-cation. Java Series. Addison-Wesley Professional, 3rd edition edição.

Hoare, C. A. R. (1974). Monitors: an operating system structuring concept. Commu-nications of the ACM, 17(10):549–557.

Hoare, C. A. R. (1985). Communicating sequential processes. Communications of theACM, 21:666–677.

Ingalls, D. (1981). Design principles behind smalltalk. BYTE Magazine, 6(8):286–298.

Itzstein, G. S. V. (2005). Introduction of high level concurrency semantics in objectoriented languages. Master’s thesis, University of South Australia.

Itzstein, G. S. V. & Jasiunas, M. (2003). On implementing high level concurrency inJava. In Asia-Pacific Computer Systems Architecture Conference, volume 2823 ofLecture Notes in Computer Science, pp. 151–165. Springer.

Itzstein, S. & Kearney, D. (2002). Applications of Join Java. In Proceedings of theSeventh Asia-Pacific Computer Systems Architectures Conference (ACSAC2002, pp.37–46. Australian Computer Society, Inc.

Lee, E. (2006). The problem with threads. Technical Report UCB/EECS-2006-1,EECS Department, University of California, Berkeley.

Liu, Y. (2008). Join: Asynchronous message based concurrency library based on Cωand join calculus.

Matsuoka, S. & Yonezawa, A. (1993). Analysis of inheritance anomaly in object-oriented concurrent programming languages. In Research Directions in ConcurrentObject-Oriented Programming, pp. 107–150. MIT Press.

Page 167: PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA … · SÉRGIO VALE E PACE PROGRAMAÇÃO CONCORRENTE BASEADA EM ACORDES PARA PLATAFORMA JAVA Dissertação apresentada ao Programa

REFERÊNCIAS BIBLIOGRÁFICAS 141

Milner, R. (1980). A calculus of communicating systems. In Proceedings CAAP 81,LNCS 112, pp. 25–34. Springer-Verlag.

Milner, R. (1989). Communication and Concurrency. Prentice-Hall.

Milner, R. (1992). Functions as processes. Mathematical Structures in Computer Sci-ence, 2(2):119–141.

Odersky, M. (2000). Functional nets. In Proceedings European Symposium on Pro-gramming, number 1782 in LNCS, pp. 1–25. Springer Verlag.

Parrow, J. (2001). Handbook of Process Algebra, chapter An Introduction to the π-Calculus. Elsevier.

Petrounias, A.; Drossopoulou, S. & Eisenbach, S. (2008). A featherweight model forchorded languages. Technical report, Imperial College London.

Pierce, B. C. (1995). Foundational calculi for programming languages. In Handbook ofComputer Science and Engineering. CRC Press.

Russo, C. (2006). The Joins concurrency library.

Sun Microsystems (2007). JDK 5.0 Programmer Guides. Sun Microsystems.

Sutter, H. (2005). The free lunch is over: A fundamental turn toward concurrency insoftware.

Trono, J. A. (1994). A new exercise in concurrency. SIGCSE Bull, 26(3):8–10.

Valente, M. T. O. (2002). Mobilidade e Coordenação de Aplicações em Redes sem Fio.PhD thesis, Universidade Federal de Minas Gerais, UFMG, Brasil.

Wood, T. & Eisenbach, S. (2004). A chorded compiler for Java.