• Nenhum resultado encontrado

2.3 Problemas de Acordo

2.3.3 Exclus˜ao M´utua

O problema da exclus˜ao m ´utua [52] consiste em gerenciar um conjunto de processos que desejam acessar um recurso indivis´ıvel que n˜ao pode sofrer acessos simultaneamente. Um algoritmo que resolve este problema deve garantir que processos nestas condic¸˜oes tenham acesso ao recurso um por vez. Os processos obt´em acesso ao recurso exclusivo executando uma sec¸˜ao cr´ıtica de seu c´odigo. Os processos que est˜ao tentando executar suas sec¸˜oes cr´ıticas s˜ao ditos na sec¸˜ao de entrada e os processos que j´a executaram suas sec¸˜oes cr´ıticas s˜ao ditos na sec¸˜ao de sa´ıda.

Um algoritmo de exclus˜ao m´utua ´e muitas vezes modelado como um servic¸o onde os processos executam as operac¸˜oes enter(), para tentar obter o acesso ao recurso (sec¸˜ao de entrada), e exit(), para liberar o recurso (sec¸˜ao de sa´ıda). As operac¸˜oes enter() e exit() s´o retornam quando o processo ´e bem sucedido na obtenc¸˜ao e liberac¸˜ao do recurso, respectivamente.

Um algoritmo de exclus˜ao m´utua precisa satisfazer algumas propriedades [5, 83]. Uma destas propriedades fundamenta a seguranc¸a (safety) do algoritmo:

1. Exclus˜ao M ´utua: N˜ao existe um estado alcanc¸´avel do sistema onde dois processos corretos est˜ao em suas sec¸˜oes cr´ıticas (executaram enter() e n˜ao comec¸aram a executar exit());

Em termos de vivacidade (liveness), s˜ao duas as principais garantias que devem ser consideradas em algoritmos de exclus˜ao m´utua:

1. Progresso (Deadlock-freedom): Se um processo correto est´a na sec¸˜ao de entrada (executando enter()), ent˜ao algum processo correto termina por executar sua sec¸˜ao cr´ıtica.

2. Progresso justo (Starvation-freedom): Se um processo correto est´a na sec¸˜ao de entrada (exe- cutando enter()), ent˜ao este processo termina por executar sua sec¸˜ao cr´ıtica.

Note que a diferenc¸a entre a propriedade de progresso e a de progresso justo est´a no fato de que na primeira um processo pode ficar esperando por um recurso indefinidamente (“algum processo

correto termina por executar sua sec¸˜ao cr´ıtica”) enquanto que na segunda n˜ao (“este processo termina por executar sua sec¸˜ao cr´ıtica”).

Quando consideramos o problema da exclus˜ao m´utua em sistemas com processos sujeitos a falhas bizantinas [20], pelo menos uma premissa adicional deve ser assumida. Conforme observado por Lynch [83], o progresso de um algoritmo de exclus˜ao m´utua depende dos processos concorrentes sa´ırem de sua sec¸˜ao cr´ıtica (liberarem o recurso compartilhado). Desta forma, assumimos que todos os processos que entram em sua sec¸˜ao cr´ıtica acabam por sair desta sec¸˜ao (mesmo que de maneira forc¸ada). A forma de implementar esta premissa ´e dependente da aplicac¸˜ao. Nesta tese, quando usamos primitivas de exclus˜ao m´utua assumimos que um processo que entra em sua sec¸˜ao cr´ıtica executa uma tarefa exatamente uma vez e sai desta sec¸˜ao automaticamente com o t´ermino desta tarefa (ver sec¸˜ao 4.3.4).

Exclus˜ao M ´utua baseada no PAXOSBIZANTINO

Usando uma primitiva de difus˜ao com ordem total ´e f´acil implementar um servic¸o de exclus˜ao m´utua tolerante a faltas bizantinas utilizando um conjunto de servidores. Para tanto, ´e requerido um conjunto U com pelo menos n ≥ 3 f + 1 servidores que controlam os processos que competem pelo acesso a suas sec¸˜oes cr´ıticas, i.e. o conjunto de servidores controla os acessos em exclus˜ao m´utua provendo operac¸˜oes enter() e exit() de tal forma que as propriedades da exclus˜ao m´utua sejam satisfeitas. Clientes que desejam executar o algoritmo de exclus˜ao m´utua acessam este servic¸o. O algoritmo 1 apresenta o protocolo.

No protocolo do algoritmo 1, cada servidor s tem uma vari´avel local Queues, que representa

uma fila onde s˜ao armazenados os processos que utilizam o servic¸o de exclus˜ao m´utua. Esta fila ´e gerenciada atrav´es das operac¸˜oes usuais de lista como append, empty, tail e head. O processo que se encontra em primeiro na fila de um servidor ´e o detentor do recurso controlado para este servidor. A id´eia fundamental do algoritmo ´e fazer com que o cliente envie uma mensagem avisando que deseja entrar em sua sec¸˜ao cr´ıtica usando difus˜ao com ordem total (linha 1) para ent˜ao ficar bloqueado a espera de n − f respostas provenientes de diferentes servidores liberando o acesso ao recurso (linha 2). Todos os servidores corretos, ao receberem a requisic¸˜ao do cliente, colocam-no na fila de processos (linha 4), e esperam pela liberac¸˜ao do recurso compartilhado. O acesso ao recurso ´e dado aos processos conforme este ´e liberado por outros processos (linhas 5-7 e 12-14). A liberac¸˜ao do recurso ´e feita atrav´es do procedimento exit(): o processo envia mensagens a todos os servidores informando que ele saiu de sua sec¸˜ao cr´ıtica (linhas 3 e 8-10). O algoritmo 1 tamb´em define o predicado hasLock, usado para verificar se um processo est´a em sua sec¸˜ao cr´ıtica. Uma ilustrac¸˜ao da execuc¸˜ao deste algoritmo ´e apresentada na figura 2.4.

Levando-se em considerac¸˜ao que, por premissa, todo processo que obt´em acesso ao recurso con- trolado acaba por liber´a-lo (o procedimento exit() ´e sempre invocado para informar a liberac¸˜ao do recurso), ´e f´acil ver que o algoritmo satisfaz as propriedades de “exclus˜ao m´utua” e “progresso justo” definidas na sec¸˜ao anterior. A primeira ´e garantida devido ao uso da difus˜ao com ordem total (que

Algoritmo 1 Exclus˜ao m´utua (processo p e servidor s). {Cliente}

procedure enter()

1: TO-multicast(U, hENTERi)

2: wait until receive(s, hGOi) de n − f servidores s ∈ U procedure exit()

3: ∀s ∈ U, send(s, hEXITi)

{Servidor}

Vari´avel: Queues= hi

upon TO-receive(p, hENTERi)

4: Queues← append(Queues, p)

5: if head(Queues) = p then

6: send(p, hGOi)

7: end if

upon receive(p, hEXITi)

8: if head(Queues) = p then 9: unlock() 10: end if procedure unlock() 11: Queues← tail(Queues) 12: if ¬empty(Queues) then 13: send(head(Queue), hGOi) 14: end if

Predicado: hasLock(p), (head(Queues) = p)

garante que as filas dos servidores conter˜ao sempre a mesma ordem de processos) e pela impossibili- dade de n − f servidores darem permiss˜ao de acesso a dois processos10. A propriedade de progresso justo ´e conseq¨uˆencia direta da propriedade de validade da difus˜ao com ordem total (toda mensagem difundida ´e entregue) e da premissa que os processos sempre saem da sec¸˜ao cr´ıtica. Desta forma, todo processo que pede a entrada na sec¸˜ao cr´ıtica (executando a difus˜ao com ordem total - linha 1), acaba recebendo permiss˜ao para entrar nesta sec¸˜ao (linha 2).