Vous êtes sur la page 1sur 44

Computao Concorrente e Distriuda em Java

Vijay K. Garg

21 de dezembro de 2012

Sumrio

1 Introduo 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sistemas distribudos x Sistemas Paralelos . . . . . . . . . . . . . . . . Resumo do Livro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Caractersticas de Sistemas Paralelos e Distribudos . . . . . . . . . . . Objetivos do Projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . Especicao de Processos e Tarefas . . . . . . . . . . . . . . . . . . . . Interface Runnable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Construo de juno em Java . . . . . . . . . . . . . . . . . . . . . . . Agendamento de Thread . . . . . . . . . . . . . . . . . . . . . . . . . .

p. 4 p. 4 p. 4 p. 7 p. 10 p. 11 p. 12 p. 15 p. 15 p. 17 p. 17 p. 19 p. 21 p. 21 p. 24 p. 28 p. 31 p. 31 p. 31 p. 32 p. 34

1.10 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.11 Referncias Bibliogrcas . . . . . . . . . . . . . . . . . . . . . . . . . . 2 O Problema da Excluso Mtua 2.1 2.2 2.3 2.4 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Algortmo de Peterson . . . . . . . . . . . . . . . . . . . . . . . . . . . O Algortimo Bakery(Padeiro) de Lamport . . . . . . . . . . . . . . . . Solues de Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 2.4.2 2.5 2.6 Desabilitando Interrupes . . . . . . . . . . . . . . . . . . . . . Instrues com Alta Atomicidade . . . . . . . . . . . . . . . . .

Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Referncias Bibliogrcas . . . . . . . . . . . . . . . . . . . . . . . . . .

3 Primitivas de sincronizao 3.1 3.2 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Semforos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 3.2.2 3.2.3 3.3 O problema do produtor-consumidor . . . . . . . . . . . . . . . O Problema da leitura-escrita . . . . . . . . . . . . . . . . . . . problema do jantar dos lsofos . . . . . . . . . . . . . . . . . .

p. 35 p. 35 p. 35 p. 36 p. 38 p. 41 p. 44

Monitores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Introduo

1.1

Introduo

Sistemas de computao, paralelos e distribudos so hoje amplamente acessecveis. Um sistema paralelo consiste de mtiplos processadores que comunicam entre s usando memria compartilhada. Com o crescimento do nmero de transistors em nos chips, chips multiprocessados se tornam bastante comuns. Com bastante paralelismo disponvel nas aplicaes, tais sistemas iro facilmente bater sistemas sequenciais em perfomance. A gura 1.1 mostra um sistema paralelo com multiplos processadores. Esses processadores comunicam entre s usando memria compartilhada.Cada processador pode tambm ter memria local que no compartilhada com os outros processadores. Ns denimos sistemas distribudos como sistemas de computador que contm multiplos processadores conectador via rede. Nesses sistemas os processadores se comunicam usando mensagens que so enviadas pela rede. Tais sistemas esto cada vez mais acessecveis devido queda nos preos dos processadores e das conexes de alta largura de banda para conect-los. A gura 1.2 mostra um sistema distribudo. A rede de comunio na gura pode ser uma rede local como uma rede Ethernet, ou uma rede de rea ampla, como a Internet. Programar sistemas paralelos e distribudos exige um conjunto de ferramentas e tcnicas que diferem daquelas requeridas pelos softwares sequenciais tradicionais. O foco deste livro nessas tcnicas.

1.2

Sistemas distribudos x Sistemas Paralelos

Neste livro, ns fazemos um comparativo entre sistemas ditribudos e sistemas paralelos. Este comparativo apenas no nvel lgico. Dado um sistema fsico no qual processadores tm memria compartilhada, simples simular mensagens. Por outro lado,

Figura 1: Um sistema paralelo

Figura 2: Um sistema distribudo

dado um sistema em que processadores so conectados usando uma rede, possvel simular memria compartilhada. Assim, um sistema de hardware paralelo pode executar um software distribudo e vice versa. Essa distino levanta duas questes importantes. Deveriamos construir hardware paralelo ou hardware distribudo? Devemos escrever aplicaes considerando memria compartilhada ou troca de mensagens? No nvel de hardware, ns esperamos o modelo que prevalece seja estaes multiprocessadas conectadas por uma rede. Ento o sistema ao mesmo tempo, paralelo e distribudo. Porque o sistema no seria completamente paralelo? Existem muitas razes. Escalabilidade : Sistemas distribudos so inerentemente mais escalveis que sistemas paralelos. Em sistemas paralelos a memria compartilhada se torna o gargalo quando o nmero de processadores cresce. Modularidade e Heterogeidade : Um sistema distribudo mais exvel porque um nico processador pode ser adicionado ou retirado facilmente. Alm disso, este processador pode ser de um tipo completamente diferente dos outros j existentes. Compartilhamento de dados : Sistemas ditribudos fornecem compartilhamento de dados como nos bancos de dados ditribudos. Ento organizaes multiplas podem compartilhar seus dados entre s. Compartilhamento de recursos : Sistemas distribudos fornecem compartilhamento de recursos. Por exemplo, um processador caro, para um propsito especial, pode ser compartilhado por mltiplas organizaes. Estrutura geogrca: A estrutura geogrca de uma aplicao pode ser inerentemente distribuda. A baixa banda de comunicao pode forar processamento local. Isto sobretudo verdadeiro para redes sem o. Conabilidade : Sistemas ditribudos so mais conveis que sistemas paralelos porque a falha de um nico computador no afeta a disponibilidade dos outros. Baixo custo : Viabilidade de redes de alta largura de banda e estaes de trabalho baratas tambm favorecem a computao distribuda por razes econmicas. Porqu o sistema no pode ser puramente distribudo? As razes para manter um sistema paralelo em cada ponto de uma rede so principalmente de natureza tecnolgica.

Porque com a tecnologia atual mais rpido atualizar a memria compartilhada local que enviar uma mensagem para outro computador. Isto sobretudo verdade quando o novo valor da varivel deve ser comunicado para mltiplos processadores. Consequentemente, mais eciente obter esse renado paralismo de um sistema paralelo que que um sistema distribudo. At ento a nossa discusso tem sido a nvel de hardware. Como mensionado anteriormente, a interface disponibilizada ao programador pode hoje em dia ser implementada nas entrelinhas do hardware. Ento que modelo deve ser usado pelo programador? No nvel de programao, nos esperamos que programas sejam escritos utilizando objetos multiprocessados distribudos. Neste modelo, uma aplicao consiste de multiplos processos pesados que se comunicam usando mensagens( ou invocao de mtodos remotos). Cada um processo pesado consiste de multiplos processos leves chamados de threads. Threads se comunicam atravs de memria compartilhada. Este modelo de software espelha o hardware que (ou esperamos ser) amplamente disponvel. Assumindo que existe mais de uma thread por processo(ou ignorando o parelismo dentro de um processo) ns temos o modelo comum de um sistema distribudo. Restringindo nossa ateno a um nico processo pesado ns temos o modelo comum de um sistema paralelo. Nos esperamos que o sistema tenha aspectos de objetos ditribudos. A razo principal a simplicidade lgica do modelo de objetos ditribudos. Um programa distribudo mais orientado a objetos porque os dados em objetos remotos podem ser acessados apenas atravs de uma mensagem explicita(ou uma chamada de mtodo remota). A orienta o a objetos promove reusabilidade bem como simplicidade de design. Alm disso, esses objetos devem ser multiprocessados porque threads so teis para implementar objetos ecientes. Para mais aplicaes como servidores, elas so teis para se ter uma grande estrutura de dados compartilhada. Este uma fardo de programao e ineciente em dividir a estrutura de dados atravs de processos pesados.

1.3

Resumo do Livro

Este livro projetado para um semestre avanado de graduao ou introduo a um curso de ps-graduao em concorrncia e sistemas ditribudos. Ele tambm pode ser usado como material complementar em um curso de sistemas operacionais ou sistemas operacionais distribudos. Para cursos de graduao, o instrutor pode pular os captulos sobre condies de consistncia, espera livre de sincronizao, sincronizadores, recuperao e auto estabilizao, sem nenhuma perda de continudade.

O Captulo 1 contm as motivaes que levaram aos sistemas paralelos e distribudos. Ele compara as vantagens dos sistemas ditribudos com aquelas dos sistemas paralelos. Ele d as caractersticas dos sistemas paralelos e distribudos e as diculdades fundamentais em projetar algortmos para tais sistemas. Ele tambm apresenta construes bsicas das primeiras threads em Java. Os Captulos de 2 a 5 tratam de programao com mltiplas threads. O Captulo 2 discute o problema da excluso mtua nos sistemas de memria distribuda. Isto gera motivaes aos estudantes para primitivas de sincronizao discutidas no Captulo 3. O Captulo 3 expe os estudantes programao com mltiplas threads. Para cursos de ps-graduao os captulos 2 e 3 podem ser apotandos para auto estudo. O Captulo 4 descreve vrias condies de consistencia na execuo concorrente que o sistema pode disponibilizar aos programadores. Os captulos 4 e 5 podem ser ignorados em um curso de bacharelado. O Captulo 6 discute programao distribuda baseada em sockets e tambm em invocao remota de mtodos. Isso tambm prov uma camada para programao distribuda usada nos programas dos captulos que seguem. O Captulo 7 fornece os problemas fundamentais na programao distribuda. Ele descreve o modelo de intercalao que ordena todos os enventos no sistema, e o modelo antes do acontecido que ordena todos os eventos em um nico processo. Ele tambm discute os mecanismos chamados relgios usados para agendar eventos em uma computao distribuda assm tal iformao de ordem entre os eventos pode ser determinada por esses relgios. Este captulo fundamental para sistemas distrbudos e deve ser lido antes dos prximos. O Captulo 8 discute um dos problemas mais estudados em sistemas distribudos - excluso mtua. Este captulo fornece a interface Lock e discute vrios algortmos para implementar esta interface. Lock usado para coordenar recursos em sistemas distribudos. O Captulo 9 discute a abstrao chamada Cmera que pode ser usada para computar um instante consistente de um sistema distribudo. Ns descrevemos os algormos de Chandy e Lamport em que o receptor responsvel por gravar o estado de um canal bem como uma variante do algortmo em que o emissor grava o estado do canal. Estes algortmos tambm podem ser usados para detectar propriedades globais estveis - propriedades que permanecem verdades, uma vez que se tornam verdadeiras.

Capitulos 10 e 11 discutem a abstrao chamada Sensor que podem ser usadas para avaliar propriedades globais em um sistema distribudo. O Captulo 10 descreve algortmos para deteco de predicados conectivos em que um predicado global apenas um conjunto de predicados locais. O Captulo 11 descreve algortmos para deteco de nalizao e deadlock. Embora nalizao e deadlock possam ser detectados usando tecnicas descritas nos captulos 9 e 10, ns dedicamos um captulo separado para tal porque esses algormos podem ser mais ecientes que aqueles usados para deteco geral de propriedades globais. Eles tambm ilustram tecnicas em projetos de algortmos distribudos. O captulo 12 descreve mtodos para fornecer camadas de mensageria com propriedades fortes ento fornecidas pelo protocolo de controle de transmisso(TCP). Discutimos a ordenao casual de mensagens, a sincronia e a ordenao total de mensagens. O captulo 13 discute duas abstraes em um sistema distribudo = Eleio e Funo Global. Discutimos eleio em sistemas baseados em anel bem como em cenrios gerais. Uma vez que elegido, ns mostramos que uma funo global pode ser facilmente computada via uma convergercast ou broadcast. O captulo 14 discute sincronizadores, um mtodo para abstrair assincronia no sistema. Um sincronizador permite a simulao de um algortmo sincronizado no topo de um sistema assncrono. Ns aplicamos sincronizadores para computar a busca em largura(BFS) em uma rede assncrona. Os captulos de 1 a 14 presumem que no h nenhuma falha no sistema. O resto do livro trata de tcnicas para manipulao de vrios tipos de falhas. O captulo 15 analisa a possiblidade(ou impossibilidade) de resolver problemas na presena de vrios tipos de falhas. Isto inclui o resultado impossibilidade fundamental de Ficher, Lynch e Paterson que mostram que o consenso impossvel na presena de um par de falhas no anunciadas em um sistema assncrono. Ele tambm mostra que o problema do consenso pode ser resolvido em um ambiente sincronizado sob crash e falhas bizantinas. Ele tambm discute a capacidade de resolver problemas com a ausncia de comunicao convel. O problema dos dois generais mostra que o acordo sobre um bit(obteno de conhecimento comum) impossvel em um sistema distribudo. O captulo 16 descreve a noo de transao e vrios algortimos utilizados na implementao de transaes. O captulo 17 discute mtodos para se recuperar de falhas. Ele inclui ambos as tcnicas checkpoints e registro de mensagens de log.

10

Finalmente, o captulo 18 discute sistemas auto-estabilizantes. Discutimos solues para o problema da excluso mtua quando o estado de um processador pode alterar arbitrariamente por causa de uma falha. Mostramos que possvel projetar algortmos que garantem que o sistema converge para um estado legal em um nmero nito de moviemntos independente da execuo do sistema. Ns tambm discutimos algortmos auto-estabilizantes para manuteno de rvore abrangente em uma rede. Existem numerosos problemas, marcados e desmarcados, no nal de cada captulo. esperado de um estudante resolver os problemas no marcados com pouco esforo. Os problemas marcados podem exigir que o estudante gaste mais esforo e so indicados apenas para os cursos de ps-graduao.

1.4

Caractersticas de Sistemas Paralelos e Distribudos

Recordando que ns distinguimos sistemas paralelos de distribudos com base na memria compartilhada. Um sistema distribudo caracterizado pela ausncia de memria compartilhada. Portanto, em um sistema distribudo impossvel para qualquer processador conhecer o estado global do sistema. Como resultado, difcil observar qualquer propriedade global do sistema. Veremos mais adiante como algortmos ecientes podem ser desenvolvidos para avaliar adequadamente um conjunto restrito de variveis globais. Um sistema paralelo ou distribudo pode ser formente acoplado ou fracamente acoplado dependendo se multiplos processadores trabalham com etapas de bloqueio. A ausncia de um relcio compartilhado resulta em um sistema de acoplamento fraco. Em um sistema geogrcamente ditribudo impossvel sincronizar os relgios de diferentes processadores precisamente devido incerteza nos atrasos de comunicao entre eles. Como resultado, fora do comum usar relgios fsicos para sincronizao em sistemas distribudos. Neste livro veremos como o conceito de casualidade utilizado em vez do tempo para resolver este problema. Em um sistema paralelo, embora um relgio compartilhado possa ser simulado, projetar um sistema em uma arquitetura de acoplamento forte raramente uma boa idia, devido a perda de performance causada pela sincronizao. Neste livro, iremos presumir que os sistemas so fracamente acoplados. Sistemas distribudos podem aida ser classicados entre sistemas sncronos e assncronos. Um sistema distribudo assncrono se no h nenhum limite superior sobre o tempo de comunicao de mensagem. Assumindo assincronia temos as mais gerais solues para

11

varios problemas. Nos veremos vrios exemplos nesse livro. Entretanto, as coisas se tornam difceis em um sistema assncrono quando processadores ou conexes podem falhar. Em um sistema assncrono distribudo impossvel distinguir entre um processador lento e um processador com falha. Isto leva a diculdade no desenvolvimento de algoritmos para consenso, eleio, e outros importantes problemas em computao distribuda. Ns iremos descrever essas diculdades e tambm mostrar algoritmos que trabalham sob falhas em sistemas sncronos.

1.5

Objetivos do Projeto

A experincia em grandes softwares paralelos e distribudos tem mostrado que seu projeto deve considerar os seguintes conceitos[TvS02]: Tolerncia a falha: O software do sistema deve mascarar a falha de um ou mais componentes no sistema, incluindo processadores, memria, e conexes de rede. Isso geralmente requer redundancia, que pode ser caro dependendo do nvel de tolerncia de falha. Portanto, uma anlise de custo-benefcio necessria para determinar o nvel apropriado de tolerncia a falha. Transparncia: O sistema deve ser o mais amigvel possvel. Isto requer que o usurio no tenha que lhe dar com detalhes desnecessrios. Por exemplo, em um sistema distribudo heterognio a diferena na representao interna dos dados(como a diferena entre os formatos de inteiros big endian e little endian) devem ser escondidas do usurio, um conceito chamado transparncia de acesso. Similarmente, o uso de um recurso pelo usurio no deve exigir que o usurio saiba onde ele est localizado(transparncia de acesso ), se ele replicado(transparncia de replicao ), se ele compartilhado(transparncia de concorrncia), ou se ele est em memria voltil ou disco rgido(transparncia de persistncia). Flexibilidade : O sistema deve ser capaz de interagir com um grande nmero de outros sistemas e servios. Isso requer que o sistema apoie-se a um conjunto xo de regras para sintaxe e semntica, preferencialmente um padro, para interao. Isso frequentemente facilitado pela escicao dos servios fornecidos pelo sistema atravs de uma linguagem de denio de interface. Outra forma de exibilidade pode ser dada ao usurio por uma distino entre poltica e mecanismo. Por exemplo, em um contexto de Web caching, o mecanismo se refere implementao para armazenar localmente as pginas web. A poltica se refere s decises de alto nvel

12

como o tamanho do cache, que pginas sero cacheadas, e quanto tempo essas pginas iro permanecer em cache. Tais questes podem ser melhor respondidas pelo usurio e alm disso melhor para os usurios construir suas prprias polticas no topo do mecanismo de cache fornecido. Projetando o sistema como um componente monoltico, ns perdemos a exibilidade do uso de diferentes polticas com diferentes usurios. Escalabilidade : Se o sistema no feito para ser escalvel, ento ele pode ter performance insatisfatria quando o nmero de usurios e recursos aumenta. Por exemplo, um sistema distribudo com apenas um servidor pode vir a ser sobrecarredo quando o nmero de clientes requisitando o servio desse servidor aumenta. Geralmente, o sistema ou completamente descentralizado usando algortmos distribudos ou parcialmente descentralizado usando hierarquia de servidores.

1.6

Especicao de Processos e Tarefas

Neste livro ns cobrimos os conceitos de programao para linguagens baseadas em memria compartilhada e linguagens distribudas. Deve-se notar que os problemas de concorncia surgem mesmo em um computador com um nico CPU onde um sistema pode ser estruturado como uma coleo de processos cooperativos. De fato, os problemas de sincronizao e deadlock tem raiz no desenvolvimento dos primeiros sistemas operacionais. Por esta razo ns iremos nos referir s construes descritas nesta seo como programao concorrente. Antes de embarcarmos na construo de programao concorrente, necessrio entender a distino entre programa e processo. Um programa de computador apenas um conjunto de estrues de alto nvel ou de linguagem de mquina. Apenas quando executamos um programa que temos um ou mais processos. Quando o programa sequncial, isto resulta em um nico processo, quando concorrente - mltiplos processos. Um processo pode ser visto como constituinte da rvore dos segmentos da mmoria: cdigo, dados e pilha de execuo. O cdigo so as instrues de mquina na memria que o processo executa. Os dados consistem da memria utilizada pelas variveis globais estticas e variveis alocadas em tempo de execuo(heap). A pilha consiste das variveis locais e registros de ativao das chamadas de funo. Todo processo tem sua prpria pilha. Quando processos compartilham o espao de endereos, isto , cdigo e dados, ento eles so chamados processos leves ou threads. A gura 1.3 mostra quatro threads. Todas as threads compartilham o espao de endereos mas tm suas prprias pilhas. Quando processos tm seus prprios cdigo e dados, eles so chamados de um

13

processo pesado ou simplesmente processo. Processos pesados podem compartilhar dados atravs de arquivos ou enviando explicitamente mensagens uns aos outros.

Figura 3: Um processo com quatro threads Qualquer linguagem de programao que suporte programao concorrente precisa ter uma maneira de especicar a estrutura do processo, e como varios processos comunicam e sincronizam uns com os outro. Existem vrias maneiras nas quais um programa pode especicar a estrutura do processo ou criao de novos processos. Olharemos para a mais popular delas. No UNIX, processos so organizados como uma rvore de processos com cada processo identicado usando um nico identicador de processo(pid). O UNIX fornece as chamadas de sistema fork e wait para criao e sincronizao de processos. Quando um processo executa uma chamada fork, um processo lho criado com uma cpia do espao de endereos do processo pai. A nica diferena entre o processo pai e lho o valor do cdigo de retorno para fork. O processo pai obtm o pid do processo lho como o cdigo de retorno, e o processo lho adiquire o valor 0 como mostrado no

14

exemplo seguinte.

A chamada wait usada pelo processo pai para esperar o trmino do processo lho. Um processo termina quando ele executa a ltima instruo no cdigo ou faz uma chamada explcita chamada de sistema exit. Quando o processo lho termina, o processo pai, se estiver esperando, acordado e o pid do processo lho retornado para a chamada wait. Dessa maneira o processo pai pode determinar se o processo lho terminou. Frequentemente, o processo lho faz uma chamada chamada de sistema execute, que carrega um arquivo binrio na memria e inicializa a execuo dele. Outra forma de programao para lanar tarefas paralelas cobegin-coend (tambm chamada deparbeginparend ). Sua sintaxe dada abaixo:

Esta forma diz que S 1 e S 2 devem ser executadas paralelamente. Alem disso, se um deles terminar mais cedo que o outro, ele deve esperar o outro terminar. Combinando o cobegin-coend com sequenciamento, ou o operador de sequncia, ponto-e-vgula(;), ns podemos criar qualquer estrutura de tarefa srie-paralela. Por exemplo,

inicia com um processo que executa S 0 . Quando S 0 termina, temos dois processos(ou threads) que executam S 1 e S 2 em paralelo. Quando ambos terminam, s ento S 3 inicializado. Ainda outro mtodo para especicao de concorrncia criar explicitamente objetos de threads. Por exemplo, em Java existe uma classe predenida chamada Thread. Outra classe pode extender a classe Thread, sobrescrever o mtodo run e ento chamar start() para lanar a thread. Por exemplo, uma thread para imprimir "Hello World"pode ser lanada como como mostrado na gura 1.4.

15

Figura 4: HelloWorldThread.java

1.7

Interface Runnable

No exemplo HelloWorld, a classe HelloWorldThread precisa herdar mtodos apenas da classe Thread. E se ns quisermos extender uma classe, como, Foo, mas tambm fazer os objetos da nova classe executar como threads separadas? Uma vez que Java no possui herana mltipla, ns no podemos simplesmente extender ambas Foo e a classe Thread simultneamente. Para resolver este problema, Java fornece uma interface chamada Runnable com o nico seguinte mtodo:

Para projetar uma classe runnable FooBar que extende Foo, ns procedemos como mostrado na gura 1.5. A classe FooBar implementa a interface Runnable. A funo principal cria um objeto runnable f1 do tipo FooBar. Agora ns podemos criar uma thread t1 passando o objeto runnable como um argumento ao construtor da Thread. Esta thread pode ento ser inicializada envocando o mtodo start. Deste modo o programa cria duas threads. Cada uma das threads imprime a string getName() herdada da classe Foo.

1.8

Construo de juno em Java

Temos visto que ns podemos usar start() para inicializar uma thread. O exemplo seguinte mostra como uma thread pode esperar por outra thread terminar de executar usando o mecanismo de juno. Ns escrevemos um programa em Java para computar o ensimo Fibonacci Fn . Usando a relao de recurso

16

Figura 5: FooBar.java

17

para n 2. A base

Para calcular Fn , o mtodo run bifurca-se em duas threads que computam Fn1 e Fn2 respectivamente. A thread principal espera essas duas threads terminarem seus clculos usando juno. O programa completo mostrado na gura 6.

1.9

Agendamento de Thread

No exemplo FooBar, ns temos duas threads. O mesmo programa Java funcionar em uma mquina de um nico CPU bem como em uma mquina de multiplos processadores. Em uma mquina de um nico processador, se ambas as threads esto foram estartadas, qual delas ser escolhida pelo sistema para executar? A resposta dessa pergunta depende da prioridade e das polticas de agendamento do sistema. O programador pode alterar a prioridade da thread usando setPriority e resgatar a prioridade corrente usando getPriority. MIN_PRIORITY e MAX_PRIORITY so constantes inteiras denidas na classe Thread. O mtodo setPriority pode usar apenas valores entre essas duas constantes. Por padro, uma thread tem prioridade NORM_PRIORITY. Uma thread Java que est em execuo pode bloquear atravs da chamada sleep, wait, ou qualquer funo do sistema que a bloqueie(tais funes sero descritas mais a frente). Quando isso ocorre, a thread de maior prioridade que est no estado executvel selecionada para execuo. Quando a thread de maior prioridade esta em execuo, ela pode ser interrompida quando sua fatia de tempo acaba. Outra thread no mesmo nvel de prioridade pode ento ter permisso para executar.

1.10

Exerccios

1.1 Cite as vantagens e desvantagens de um modelo de programao paralelo em relao a um modelo de sistema distribudo(basedo em mensagens).

18

Figura 6: Fibonnaci.java

19

1.2 Escreva uma classe Java que permita uma busca paralela em um arranjo de inteiros. Ela deve fornecer o seguinte mtodo static:

Este mtodo um nmero de threads especicado por numThreads, divide o array A em neste nmero de partes, e da a cada thread uma parte do array para procurar por x sequencialmente. Se alguma das threads encontrar x, ento ela retorna um index i em que A[i] = x. Caso contrrio o mtodo retorna 1. 1.3 Considere a classe mostrada abaixo.

Se uma thread chama op1 e outra thread chama op2, ento quais valores podem ser retornados por op1 e op2? 1.4 Escreve um programa com multiplas threads em Java que ordena um array usando merge sort recursivo. A thread principal bifurca-se em duas threads para ordenar as duas metades do array, que so ento mescladas. 1.5 Escreva um programa em Java que usa duas threads para procurar um dado elemento em uma lista duplamente encadeada. Uma thread atravessa a lista na direo normal e a outra na direo contrria.

1.11

Referncias Bibliogrcas

Existem vrios livros disponveis sobre sistemas distribudos. O leitor referido a livros por Attiya e Welch [AW92], Barbosa[Bar96], Chandy e Misra[CM89], Garg[Gar96, Gar02], Lynch[Lyn96], Raynal[Ray88], e Tel[Tel94] para uma variedade de tpicos em agortmos distribudos. Couloris, Dollimore e Kindberg[CDK94], e Chow e Johson[CJ97] abordam alguns outros aspectos prticos de sistemas distribudos como sistemas de arquivos distribudos, que no so abordados neste livro. Goscinski[Gos91] e Singhal e Shivaratri[SS94] abordam conceitos em sistemas operacionais distribudos. O livro editado por Yang e Marshland[YM94] incluem varios artigos que tratam de tempo global e estado em sistemas distribudos. O livro editado por Mullender[SM94] aborda outros tpicos como proteo, tolerncia a falha, e comunicaes de tempo real.

20

Existem varios livros para cculos concorrentes em Java tambm. O leitor referido a esses livros por Farley[Fa98], Hartley[Har98] e Lea[Lea99] por exemplo. Tais livros no discutem algormos distribudos.

21

O Problema da Excluso Mtua

2.1

Introduo

Quando processos comparilham dados, importante sincronizar seus acessos aos dados para que atualizaes no sejam perdidas como um resultado da concorrncia da acesso e os dados no sejam conrrompidos. Isto pode ser observado no exemplo que se segue. Considerando que o valor inicial da varivem compartilhada x 0 e que existem dois processos, P0 e P1 de forma que cada um deles incrementa x com o seguinte trecho em alguma linguagem de programao de alto nvel. x=x+1 natural para um programador achar que o valor nal de x ser 2 depois de ambos os processos terem sido executados. Entretanto, isto pode no acontecer se o programador no garantir que x = x + 1 seja executado atomicamente. O trecho de cdigo pode ser compilado para cdigo de mquina na forma

Agora a execuo de P0 e P1 pode ser intercalada como se segue:

22

Ento ambos processos carregam o valor 0 para os registradores e nalmente gravam 1 em x, resultando no problema "atualizaes perdidas". Para evitar este problema, a expresso x = x + 1 deve ser executada atmicamente. Uma poro de cdigo que precisa ser executada atomicamente tambm chamada de regio crtica ou seo crtica. O problema de garantir que a seo crtica seja executada atomicamente chamado de problema da excluso mtua. Este um dos mais fundamentais problemas em computao concorrente e ns iremos estud-lo em detalhes. O problema da excluso mtua pode ser resumido como se segue. Somos obrigados a implementar a interface mostrada na gura 2.1. Um processo que quer entrar na seo crtica (CS) faz uma chamada requestCS com seu prprio identicador como argumento. O processador ou a thread que faz essa chamada retorna deste mtodo apenas quando ele tem acesso exclusivo seo crtica. Quando o processo termina acesso seo crtica, ele faz uma chamada ao mtodo releaseCS.

Figura 7: Interface para acesso seo crtica O protocolo de entrada dado pelo mtodo requestCS e o protocolo de sada dado pelo mtodo releaseCS devem ser tais que a excluso mtua no seja violada. Para testar o Lock, ns usamos o programa mostrado na gura 2.2. Este programa testa o algortmo Bakery que ser apresentado mais tarde. O usurio do programa pode testar um algortmo diferente para a implementao de bloqueio invocando o construtor daquela implementao do bloqueio. O programa lana N threads como especicado pelo argumento arg[0]. Cada thread um objeto da classe MyThread. Vamos agora dar uma olhada para classe MyThread. Esta classe possui dois mtodos, nonCritialSection e critialSection, e ela sobrescreve o mtodo run da classe Thread como se segue. Cada thread repetidas vezes entra na seo crtica. Depois de sair da seo crtica ela gasta uma quantidade indeterminada de tempo na seo no crtica do cdigo. No nosso exemplo, ns simplesmente usamos um nmero randmico para dormir nas sees crtica e no crtica. Vamos agora olhar para alguns possveis protocolos, uma possvel tentativa, para resolver o problema da excluso mtua. Para simplicar ns iremos primeiro assumir que existiro apenas dois processos, P0 e P1 .

23

Figura 8: Um programa para testar excluso mtua

24

2.2

Algortmo de Peterson

Nossa primeira tentaiva poderia ser usar uma varivel booleana compartilhada openDoor inicializada com true. O protocolo de entrada ir esperar openDoor ser verdadeira. Se ela verdadeira, ento o processo pode entrar na seo crtica e depois congurando-a com false. Ao sair o processo recongura ela para true. Este algortimo mostrado na gura 2.3.

Figura 9: Uma tentativa que viola a excluso mltipla Esta tentativa no funciona porque o teste de openDoor e a sua alterao para false no feita atmicamente. Permitidamente, um processo pode checar openDoor e sair do while na gura 2.3. Entretanto, antes que o processo possa alterar openDoor para false, o outro processo pode iniciar sua execuo. O outro processo agora checa o de openDoor e tambm sai da espera ocupada. Ambos processos podem agora setar openDoor como false e etrar na seo crtica. Ento a excluso mtua violada. Na tentativa descrita acima, a varivel compartilhada openDoor no grava quem alterou o seu valor para false. Uma forma para tentar solucionar este problema seria manter duas variveis compartilhadas, wantCS[0] e wantCS[1], como mostrado na gura 2.4. Todos os processos Pi primeiro alteram o seu prprio bit wantCS para true na linha 4 e at que wantCS do outro processo seja false na linha 5. Usamos 1 i para obter o idencador do outro processo quando houverem apenas dois processos - P0 e P1 . Para liberar a seo crtica, Pi simplesmente recongura seu bit wantCS para false. Infelismente, esta tentativa tambm no funciona. Ambos processos podem setar suas wantCSs com verdadeiro e depois car indenidamente em loop, esperando que o outro processo atualize sua wantCS com false. Uma outra tentativa de resolver o problema mostrada na gura 2.5. Esta tentativa baseada em avaliar uma varivel turn. Um processo espera por sua vez para entrar na seo crtica. Ao deixar a seo crtica, ele congura turn para 1 i.

25

Figura 10: Uma tentativa que pode gerar deadlock

Figura 11: Uma tentativa com alternncia rigorosa Este protocolo garante excluso mtua. Ele tambm garante que se ambos os processos estiverem tentando entrar na seo crtica, ento um deles ter sucesso. Entretanto ele sofre por outro problema. Neste protocolo, ambos os processos tm que alternar entre eles para acessar a seo crtica. Portanto, depois de o processo P0 deixar a seo crtica ele no pode entrar na seo crtica denovo a menos que o processo P1 tenha entrado na mesma. Se o processo P1 no estiver interessado na seo crtica, ento o processo P 0 ca simplesmente emperrado esperando por P1 . No queremos isso. Combinando as duas abordagens anteriores, entretanto, ns temos o algortmo de Peterson para o problema da excluso mtua em um sistema de dois processos. Neste protocolo, mostrado na gura 2.6, ns gerenciamos duas ags, wantCS[0] e wantCS[1], como na Tentativa 2, e a varivel turn como na tentativa 3. Para requerer a seo crtica o processo Pi seta sua ag wantCS para true na linha 6 e ento seta a varivel turn para o outro processo Pj na linha 7. Depois disso ele espera na linha 8 enquanto a seguinte condio for verdadeira:

Ento um processo s entra na seo crtica ou se a sua vez ou se o outro processo no est interessado na seo crtica.

26

Para liberar a seo crtica, Pi simplesmente recongura a ag wantCS[i] na linha 11. Isto permite que Pj entre na seo crtica fazendo com que a condio do seu loop while seja falsa.

Figura 12: Algortmo de Peterson para excluso mtua Ns mostramos que o algortmo de Peterson satifaz as propriedades desejadas: 1. Excluso Mtua: Dois processos no podem estar na seo crtica ao mesmo tempo. 2. Progresso : Se um ou mais processos est tentando entrar na seo crtica e no h nenhum processo dentro da seo crtica, ento pelo menos um dos processos ser bem sucedido em entrar na seo crtica. 3. Ausncia de Inanio : Se um processo esta tentando entrar na seo crtica, ele eventualmente ter sucesso em faz-lo. Ns primeiramente mostramos que a excluso mtua satisfeita pelo algortmo de Peterson. Considerando, sem peda de generalidade que P0 o primeiro processo a entrar na seo crtica. Para entrar na seo crtica, P0 precisa ou ter lido wantCS[1[ como false, ou turn igual a 0. Ns agora fazemos uma anlise de caso: Caso 1 : P0 l wantCS[1] como false. Se wantCS[1] falso, ento para P1 entrar na seo crtica, ele precisa setar wantCS[1] para verdadeiro. Neste caso ns temos a seguinte ordem de eventos: P0 le wantCS[1] como falso antes de P1 setar o valor de wantCS[1] para verdadeiro. Esta ordem dos eventos implica que P1 deve setar turn = 0 antes de checar a condio de entrada e depois do evento de leitura da ag wantCS[1] por P0 . Por outro lado, P0 seta turn = 1 antes de ler wantCS[1]. Portanto, ns temos a seguinte ordem de eventos no tempo: P0 seta turn = 1

27

P0 l wantCS[1] como falso P1 seta wantCS[1] como verdadeiro P1 seta turn para 0 P1 l turn. Claramente, turn pode ser apenas 0 quando P1 a l. Agora vamos olhar para o conjunto de valores de wantCS[0] que P1 possivelmente pode ler. Pelo programa ns sabemos que P0 seta wantCS[0] como verdadeiro antes de ler wantCS[1]. Similarmente, P1 seta wantCS[1] antes de ler wantCS[0]. Ns sabemos que P0 l wantCS[1] como falso. Portanto P1 seta wantCS[1] como verdadeiro depois que P0 l wantCS[1]. Isto implica que ns temos a seguinte ordem de eventos: P0 seta wantCS[0] com verdadeiro P0 l wantCS[1] como falso P1 seta wantCS[1] com verdadeiro P1 l wantCS[0]: Portanto, P1 pode apenas ler wantCS[0] como true. Como P1 l turn como 0 e wantCS[0] como true, ele no pode entrar na seo crtica. Caso 2 : P0 l turn igual a 0. Isto implica a seguinte ordem dos eventos: P1 seta turn com 0 entre a congurao de turn = 1 por P0 e a leitura do valor de turn por P0 . Uma vez que P1 l o valor de turn s depois de setar turn = 0, ns sabemos que ele pode ler turn apenas como 0. Tambm, wantCS[0] setada antes de P0 setar turn = 1. Portanto, P0 seta wantCS[0] antes de P1 setar turn = 0. Isto implica que P1 le o valor de wantCS[0] como verdadeiro. Ento, sempre neste caso, P1 le turn como 0 e wantCS[0] como verdadeiro. Isto signica que P1 no pode entrar na seo crtica. fcil notar que o algortmo satisfaz a condio de progresso. Se ambos os processos estiverem para sempre testando a condio de entrada no loop while, ento nos temos

28

Que claramente falsa j que (turn = 2) (turn = 1) falso. A prova de ausncia de inanio deixada como exerccio. O leitor pode tambm vericar que o algortmo de Peterson no exige alternancia rigorosa para a seo crtica - um processo pode repetidamente usar a seo crtica se outro processo no estiver interessada nela.

2.3

O Algortimo Bakery(Padeiro) de Lamport

Embora o algortmo de Peterson satisfaa todas as propriedades que so exigidas pelo protocolo, ele funciona apenas para dois processos. Embora o algortmo possa ser extendido para N processos repetindo a invocao do protocolo de entrada, o resultado seria um algortmo mais complexo. Ns agora descreveremos o algortmo do padeiro de Lamport, que supera essa disvantagem. O algortmo similar quele usado pelos padeiros servindo os seus clientes. Cada cliente que chega na padaria recebe um nmero. O atendente serve o cliente com o menor nmero. Em um sistema concorrente, difcil garantir que cada processo ter um nmero nico. Ento em caso de empate, ns usamos o identicador do processo para escolher o menor processo. O algortmo mostrado na gura 2.7 exige que um processo Pi atravesse duas etapas principais antes que ele possa entrar na seo crtica. Na primeira etapa (linhas 15-20), ele obrigado a escolher um nmero. Para fazer isso, ele l os nmeros de todos os outros processos e escolhe se nmero como sendo um nmero maior que o maior nmero ldo. Ns iremos chamar esta entrada de porta de entrada. Na prxima etapa o processo Pi checa se ele pode entrar na seo crtica da seguinte maneira. Para todos os outros processos Pj , o processo Pi primeiro checa se Pj est na porta de entrada na linha 25. Se Pj est na porta de entrada, ento Pi espera at que Pj saia de l. Nas linhas 26-29, Pi espera at que number[j ] se torne 0 ou (number[i], i) < (number[j ], j ). Quando Pi tem sucesso em vericar essas condies para todos os outros processos, ele pode entrar na seo crtica. Primeiro provaremos a armao: (A1) Se um processo Pi est na seo crtica e algum outro processo Pk j escolheu o seu nmero, ento (number[i], i) < (number[k ], k ). Se o processo Pi est na seo crtica, ento ele conseguiu sair da ksima iterao do loop for na segunda etapa. Isto implica que ou (number[k ] = 0) ou ((number[i], i) <

29

Figura 13: O algortmo do padeiro de Lamport

30

(number[k ], k )) para aquela interao. Primeiro consideremos que o processo Pi leu number[k ] como 0. Isto signica que o processo Pk no deve ter terminado de escolher seu nmero ainda. Existem dois casos. Ou Pk no entrou na porta de entrada ou ele entrou mas ainda no saiu. Se Pk no entrou na porta de entrada, ele ir ler o ltimo valor do number[i] e garantidamente tera number[k ] > number[i]. Se ele entrou na porta de entrada, ento sua entrada obrigatoriamente ocorre depois de Pi checar choosing [k ] porque Pi espera Pk terminar de escolher antes de checar a condio (number[k ] = 0) ((number[i], i) < (number[k ], k )). Isto novamente signica que Pk ir ler o ultimo valor de number[i] e portanto (number[i] < number[k ]). Se ((number[i], i) < (number[k ], k )) na ksima iterao, isto se manter porque number[i] no muda e number[k ] apenas aumenta. Ns agora armaremos a armao: (A2) Se um processo Pi est na seo crtica, ento (number[i] > 0). (A2) verdade. Claramente pelo programa o valor de qualquer number[k ] no mnimo 0 e um processo executa operao de incremento nesse nmero na linha 20 antes de entrar na seo crtica. Mostrar que o algortmo do padeiro satisfaz a excluso mtua agora trivial. Se dois processos Pi e Pk esto na seo crtica, ento por (A2) ns sabemos que ambos os seus nmeros so diferentes de 0. Por (A1) arma-se que ((number[i], i) < (number[k ], k )) e vice versa, o que uma contradio. O algortmo do padeiro tambm satisfaz a ausncia de inanio porque qualquer processo que est esperando para entrar na seo crtica ir eventualmente ter o menor nmero diferente de zero. Este processo ir ento ser bem sucedido em entrar na seo crtica. Pode ser mostrado que o algortmo do padeiro no faz nenhuma suposio de atomicidade sobre qualquer operao de leitura ou escrita. Note que o algortmo do padeiro no usa nenhuma varivel que pode ser escrita por mais de um processo. O processo Pi escreve apenas nas variveis number[i] e choosing [i]. H duas principais desvantagens no algortmo do padeiro: (1) ele exige um trabalho O(N ) para cada processo obter o bloqueio mesmo se no h nenhuma disputa, e (2) ele exige que cada processo usem arrays que sejam de tamanho ilimitado.

31

2.4

Solues de Hardware

Como temos visto, solues puramente de sofware para excluso mtua pode ser muito complexas e caras. Entretanto, excluso mtua pode ser fornecida muito mais facilmente com a ajuda do hardware. Discutiremos algumas tcnicas a seguir.

2.4.1

Desabilitando Interrupes

Em um sistema com um nico processador, um processo pode desabilitar todas as interrupes antes de entrar na seo crtica. Isto signica que o processo no pode ter ser comutado(porque a troca de contexto ocorre quando a thread corrente recebe uma interrupo de clock no momento em que sua fatia de tempo termina). Ao sair da seo crtica o processo habilita as interrupes. Embora este mtodo possa funcionar para uma mquina de apenas um processador, ele possui vrias ferramentas indesejaveis. Primeiro, ele invivel para um sistema de mltiplos processadores em que mesmo se as interrupes so desabilitadas em um processador, outro processador pode executar. Desabilitar as interrupes em todos os processadores muito carro. Tambm, vrias partes do sistema como registradores de clock so mantidos usando interrupes de hardware. Se as interrupes so desabilitadas, ento esses registradores no mostram valores corretos. Dasabilitar interrupes pode tambm conduzir a problemas se o processo do usurio tiver um bug como um loop innito na seo crtica.

2.4.2

Instrues com Alta Atomicidade

A maioria das mquinas fornecem instrues com alto grau de atomicidade para leitura ou escrita. A instruo testAndSet fornecida por algumas mquinas faz ambas, leitura e escrita, em uma instruo atmica. Esta instruo l e retorna o antigo valor de uma posio de memria enquanto a substitui com o novo valor. Ns podemos resumir a instruo como um mtodo testAndSet em um objeto da classe testAndSet como mostrado na gura 2.8. Se a instruo testAndSet estiver disponvel, ento pode-se desenvolver um protocolo simples para a excluso mtua, mostrado na gura 2.9. Este algortmo satisfaz as propriedades de excluso mtua e progresso. Entretanto, ele no satisfaz a ausncia de inanio. O desenvolvimento de um protocolo deixado como exerccio.

32

Figura 14: Instruo de harware TestAndSet

Figura 15: Excluso mtua usando TestAndSet Algumas vezes mquinas fornecem instrues de troca, que podem trocar duas posies de memria em uma etapa atmica. Esta escrita mostrada na gura 2.10. O leitor convidado a projetar um protocolo de excluso mtua usando troca.

Figura 16: Semntica da operao de troca

2.5

Exerccios

2.1 Mostre que qualquer uma das alteraes no algortmo de Peterson o torna incorreto: (a) Um processo no algortmo de Peterson set a varivel turn para ele mesmo ao invs de set-la para o outro processo

33

(b) Um processo seta a varivel turn antes de setar a varivel wantCS. 2.2 Mostre que o algortmo de Petersno tambm garante ausncia de inanio. 2.3 Mostre que o algortmo do padeiro no trabalha na ausncia da varivel choosing. 2.4 Considere o protocolo de sofware mostrado na gura 2.11 para excluso mtua entre dois processos. Esse protocolo satisfaz (a) excluso mtua, e (b) progresso ( ambos processos tentando entrar na seo critica e nenhum deles tem sucesso)? Ele satisfaz ausencia de inanio?

Figura 17: Dekker.java 2.5 Modique o algortmo do padeiro para resolver o probelma da k-mtua excluso, em que at k processos podem estar na seo crtica simultneamente. 2.6 Fornea um algortmo de excluso mtua que use a instruo atmica de troca . 2.7 Fornea um algortmo de excluso mtua que use a instruo TestAndSet e seja livre de inanio. *2.8 Fornea um algortmo de excluso mtua para N processos que exige tempo O(1) na ausncia de competio.

34

2.6

Referncias Bibliogrcas

O problema da excluso mtua foi primeiramente introduzido por Dijkatra [Dij65a]. Dekker desenvolveu o algortmo para excluso mtua para dois processos. Dijkstra [Dij65b] deu a primeira soluo do o problema para N processos. o algortmo do padeiro foi feito por Lamport [Lam74], e o algortmo de peterson foi retirado de um artigo escrito por Peterson[Pet81].

35

Primitivas de sincronizao

3.1

Introduo

Todos as nossas solues anteriores para o problema da excluso mtua eram um desperdcio em uma considerao. Se um processo impedido de entrar na seo crtica, ele repetidamente checa se a condio de entrada verdadeira. Enquanto um processo est fazendo isto, nenhum trabalho til realizado. Esta uma forma de esperar chamada espera ocupada. Se ao invs de checar a condio de entrada repetidamente, o processo checar a condio apenas quando ela puder ter se tornado verdadeira, ele no ir desperdiar ciclos de CPU. Realizar isso requer suporte do sistema operacional.

3.2

Semforos

Dijkstra propos o conceito de semforo que resolve o problema da espera ocupada. Um semforo tm dois campos, o seu valor e uma la de processos bloqueados. E duas operaes associadas a isso - P () e V (). A semntica de um semforo binrio mostrada na gura 3.1. O valor de um semforo(ou semforo binrio) pode ser apenas falsou ou verdadeiro. A la de processos vazios ca inicialmente vazia e um processo pode se adicionar la quando ele faz uma chamada a P (). Quando um processo chama P () e o valor verdadeiro, ento o valor do semforo se torna falso. Entretanto, se o valor do semforo falso, ento o processo bloqueado na linha 7 at ele se tornar verdadeiro. A invocao do mtodo Util.myWait() na linha 8 consegue isso. A classe Util mostrada no apendice, mas agora simplesmente considere que esta chamada insira o processo chamador dentro da la de processos bloqueados. Quando o valor se torna verdadeiro, o processo pode fazlo falso e retornar de P (). A chamada a V () torna o valor verdadeiro e tambm notica um processo se a la dos processos adormecidos no semforo no est vazia.

36

Figura 18: Semforo binrio Agora, quase trivial implementar excluso mtua:

Outra variante de semforo permite que ele tenha um inteiro arbitrrio como seu valor. Esses semforos so chamados semforos contadores. Sua semntica mostrada na gura 3.2. Semforos pode ser usados para solucionar uma ampla variedade de problemas de sincronizao. Informo que Java no fonece semforos como construes bsicas da linguagem, mas eles pode ser facilmente implementados em Java, usando a ideia de monitores, que iremos abordar mais tarde. Por hora ns simplesmente assumimos que semforos esto disponveis para ns e resolvemos problemas de sincronizao usando eles.

3.2.1

O problema do produtor-consumidor

Nos primeiraremos consideraremos o problema do produtor-consumidor. Neste problema, existe um buer compartilhado entre dois processos chamados o produtor e o consumidor. O produtor produz itens que so depositados no buer e o consumidor captura itens do buer e os consome. Para simplcar, nos consideraremos que nossos itens so do tipo double. Uma vez que o buer compartilhado, cada processo precisa acesslo de forma mutuamente exclusiva. Ns usamos um array de double de tamanho size

37

Figura 19: Semforo contador como nosso buer. O buer possui dois ponteiros, inBuf e outBuf, que apontam para os indices no array para depositar um item e capturar um item, respectivamente. A varivel count armazena o nmero de itens correntemente no buer. A gura 3.3 mostra o buer como um array circular em que inBuf e outBuf so incrementados por mdulo de size para acompanhar os slots para depositar e buscar itens. Neste problema, ns vemos que alm de excluso mtua, existem duas restries adicionais de sincronizao que devem ser satisfeitas: 1. O consumidor no deve capturar nenhum item de um buer vazio. 2. O produtor nado deve depositar qualquer item em um buer cheio. O buer pode se tornar cheio se o produtor estiver produzindo em uma taxa maior que a taxa em que os itens so consumidos pelo consumidor. Tal forma de sincronizao chamada de sincronizao condicional. Ela exige que um processo espere por alguma condio se tornar verdadeira ( como o buer no estar vazio ) antes de continuar suas operaes. A classe BounderedBuer mostrada na gura 3.4. Ela usa um semforo mutex para garantir que todas as variveis compartilhadas sejam acessadas de maneira mutualmente exclusiva. O semforo contador isFull usado para fazer um produtor esperar em caso de o buer estar cheio, e o semforo isEmpty usado para fazer um consumidor esperar quando o buer estiver vazio. No mtodo deposit, a linha 10 checa se o buer est cheio. Se ele estiver o processo faz uma chamanda de espera usando o semforo isFull. Note que este semforo foi inicializado com o valor size, e portando na ausncia de um consumidor as primeiras size chamadas a isFull.P() no bloqueiam. Neste ponto o buer estra cheio e qualquer chamada a

38

isFull.P() ir bloquear. Se a chamada isFull.P() no bloqueia, ento ns entramos na seo crtica para acessar o buer compartilhado. A chamada mutex.P() na linha 11 serve como entrada para a seo crtica, e mutex.V() serve como saida da seo crtica. Uma vez na seo crtica ns depositamos o valor no buer usando o ponteiro inBuf na linha 12( veja a gura 3.4 ). A linha 15 faz uma chamada a isEmpty.V() para acordar algum consumidor que pode estar esperando porque o buer estava vazio. O mtodo fetch identico ao mtodo deposit. A classe BoundedBuer pode ser testada atravs do programa produtor-consumidor mostrado na gura 3.5. Este programa inicializa uma thread Producer e uma thread Consumer, repetidamente chamadas aos mtodos deposit e fetch, respectivamente.

3.2.2

O Problema da leitura-escrita

A seguir ns mostraremos a soluo para o problema da leitura-escrita. Este problema exige que ns projetemos um protocolo para coordenar o acesso a um banco de dados compartilhado. As exigncias so: 1. Nenhum conito de leitura-escrita: O protocolo deve garantir que um leitor e um escritor no acesse a base de dados simultneamente. 2. Nenhum conito de escrita-escrita: O protocolo deve garantir que dois escritores no acessem a base de dados simultneamente. Alm disso, ns gostaramos que vrios leitores fossem capazes de acessar a base de dados simultneamente. Uma soluo usando semforos mostrada na gura 3.6. Consideramos que os leitores seguem o protocolo onde eles chamam startRead antes de ler a base de dados e chamam endRead quando terminam de ler da base dados. Escritores seguem um protocolo similar. Ns usamos o semforo wlock para garantir que ou h apenas um escritor acessando a base de dados ou apenas leitores podem acessar ela. Para contar o nmero de leitores acessando a base de dados, ns usamos a varivel numReaders. Os mtodos startWrite e endWrite so muito simples. Qualquer escritor que quer usar a base de dados bloqueia a base usando wlock.P(). Se a base de dados no est bloqueada, esse escritor tem acesso. Agora, nenhum outro leitor ou escritor pode acessar a base de dados at que este escritor libere o bloqueio usando endWrite().

39

Figura 20: Um buer compartilhado implementado com um array circular

Figura 21: Um buer com limite usando semforos

40

Figura 22: O problema do produtor-consumidor usando semforos

41

Figura 23: O algortmo de leitura e escrita usando semforos Agora vamos dar uma olhada nos mtodos startRead e endRead. Em startRead uma leitura primeiro incrementa numReaders. Se ele o primeiro leitor( numReaders igual a 1), ento ele precisa bloquear a base de dados usando wlock.P(); por outro lado, se houver outros leitores acessando a base de dados e este leitor tambm pode comear a us-la. Em endRead, a varivel numReaders decrementada e o ltimo leitor que a deixar a base de dados desbloqueia ela usando wlock.V(). Este protocolo tem a desvantagem que um escritor pode morrer de fome na presena de chegada constante de leitores. Uma soluo livre de inanio para o problema do leitor-escritor deixada como exerccio.

3.2.3

problema do jantar dos lsofos

Este problema, primeiramente apresentado e resolvido por Dijkstra, muito util para expor os problemas associados programao concorrente e simetria. O problema do jantar consiste em multiplos lsofos que gastam seu tempo pensando e comendo espaguete. Entretanto, um lsofo necessita de recursos compartilhados, como garfos, para comer espaguete(veja a gura 3.7). Somos obrigados a criar um protocolo para coordenar o acesso aos recursoso compartilhados. Um leitor com espirito de computao pode substituir lsofos por processos e garfos por arquivos. A tarefa de comer corresponderia ento a

42

Figura 24: O problema do jantar dos lsofos

43

uma operao que exige acesso a arquivos compartilhados.

Figura 25: O jantar dos lsofos Vamos ao primeiro modelo o processo de um losofo. A classe Philosofer mostrado na gura 3.8. Cada lsofo Pi , repetidamente alternam atravs dos seguintes estados pensando, com fome e comendo. Para comer, um lsofo precisa de recursos(garfos) para os quais ele faz chamadas aquire(i). Ento, o protocolo para adquirir recursos resumido em uma interface Resource mostrada na gura 3.9.

Figura 26: A interface Resource A primeira tentativa de resolver o problema mostrada na gura 3.10. Ela usa um semforo binrio para cada um dos garfos. Para adquirir o recurso para comer, um lsofo i pega o garfo que est na sua esquerda usando fork[i].P() na linha 12, e o garfo da direita usando fork[i + 1%n].P() na linha 13. Para liberar o recurso, o lsofo chama V() em ambos os garfos, nas linhas 16 e 17. Esta tentativa ilusta os perigos da simetria em um sistema distribudo. Este protocolo pode resultar em deadlock quando cada lsofo puder seu garfo da esquerda e ento esperar o seu vizinho da direita liberar o garfo.

44

Figura 27: O jantar dos lsofos usando semforos Existem vrias maneiras que algum pode extender a soluo para garantir a ausncia de deadlock. Por exemplo: 1. Podemos introduzir assimetria exigindo que um dos sofos pegue o garfo em uma ordem diferente(ou seja, o garfo da direita seguido da esquerda ao invs do contrario). 2. Podemos exigir que os lsofos peguem ambos os garfos de uma s vez. 3. Suponhamos que um lsofo tenha que se levantar antes de pegar qualquer garfo. Permitimos que, no mximo, quatro lsofos podem estar de p em um determinado instante. deixado como exerccio ao leitor projetar um protocolo que livre de deadloks. O problema do jantar dos lsofos tambm ilustra a diferena entre ausncia de deadlock e auscia de inanio. Considere que ns exigimos que um lsofo pegue ambos os garfos ao mesmo tempo. Embora isto elimine o deadlock, ns continuamos tendo o problema de um lsofo morrer de fome devido aos seus vizinhos carem contnumente alternando em comer. O leitor convidado a mostrar uma soluo que livre de deadlock bem como de inanio.

3.3

Monitores

Vous aimerez peut-être aussi