• Nenhum resultado encontrado

Um Construc¸˜ao Universal N˜ao-bloqueante Simples

6.5 Construc¸˜oes Universais

6.5.1 Um Construc¸˜ao Universal N˜ao-bloqueante Simples

A construc¸˜ao n˜ao-bloqueante apresentada nesta sec¸˜ao segue a mesma linha de construc¸˜oes pr´evias da literatura [9, 67, 85]. A id´eia ´e fazer com que todos os processos corretos percebam e exe- cutem a mesma seq¨uˆencia de operac¸˜oes invocadas no objeto emulado. Cada processo pi mant´em

uma r´eplica do estado do objeto emulado Si. Uma operac¸˜ao op ´e executada aplicando-se a func¸˜ao

applyT(Si, op) neste estado. O problema ent˜ao fica reduzido essencialmente a definir uma ordem total

para a execuc¸˜ao das operac¸˜oes.

As operac¸˜oes a serem executadas no objeto emulado podem ser invocadas em qualquer um dos processos, portanto a definic¸˜ao de uma ordem para ela requer consenso entre os processos. Assim, precisamos de um objeto com n´umero de consenso m, i.e., um objeto universal.

Tendo este objeto universal, a soluc¸˜ao ´e fazer com que as operac¸˜oes a serem executadas no ob- jeto sejam adicionadas a uma lista onde cada elemento tem um n´umero de seq¨uˆencia. O elemento com maior n´umero de seq¨uˆencia representa a ´ultima operac¸˜ao executada no objeto emulado. A con- sistˆencia da lista, i.e. a propriedade de que cada um de seus elementos (cada operac¸˜ao) ´e seguida por no m´aximo um elemento, ´e garantida pelo objeto universal, o PEATS neste caso. Dada essa lista, cada processo executa as operac¸˜oes do objeto emulado em ordem crescente do n´umero de seq¨uˆencia.

Conforme j´a discutido, a lista de operac¸˜oes ´e implementada usando o PEATS. A id´eia chave ´e representar cada operac¸˜ao como uma tupla SEQ com um campo posic¸˜ao e inserir essas tuplas no espac¸o usando a operac¸˜ao cas. Quando um processo quer executar uma operac¸˜ao op ele invoca cas da seguinte forma: se n˜ao existe uma tupla SEQ com o maior n´umero de seq¨uˆencia conhecido pelo processo no espac¸o, ent˜ao ele insere uma tupla SEQ com esse n´umero de seq¨uˆencia e sua invocac¸˜ao `a op. A figura 6.5 ilustra esta id´eia.

p2 1 p cas(<SEQ,3,?inv>,<SEQ,3,inv1>) cas(<SEQ,5,?inv>,<SEQ,5,inv2>) <SEQ,4,i4> PEATS <SEQ,1,i1> <SEQ,3,i3> <SEQ,2,i2>

Figura 6.5: Construc¸˜ao universal usando PEATS.

Nesta figura, o processo p1tenta inserir uma tupla contendo a invocac¸˜ao com n´umero de seq¨uˆencia

3 no PEATS, enquanto o processo p2executa cas na esperanc¸a de inserir uma operac¸˜ao com n´umero

de seq¨uˆencia 5. Dado que no PEATS j´a existem tuplas com n´umeros de seq¨uˆencia de 1 a 4, o processo p1n˜ao conseguir´a inserir sua tupla, enquanto o processo p2ter´a sucesso em sua inserc¸˜ao. O algoritmo

14 apresenta este objeto universal.

O algoritmo assume que cada processo pi comec¸a sua execuc¸˜ao com o estado inicial do objeto

emulado (state = ST, linha 2) e conhecendo uma lista de operac¸˜oes vazia no PEATS (pos = 0, linha

3). Quando um processo pi invoca uma operac¸˜ao inv no objeto emulado, ele itera atrav´es da lista

de operac¸˜oes no PEATS atualizando sua vari´avel state (lac¸o das linhas 4-11) e tentando inserir sua operac¸˜ao no final da lista usando a operac¸˜ao cas (linha 6). Se a operac¸˜ao cas ´e bem sucedida por pi,

a vari´avel state de pi ´e atualizada e a resposta de sua invocac¸˜ao ´e retornada (linhas 7 e 8).

O algoritmo ´e n˜ao-bloqueante devido a operac¸˜ao cas: quando dois processos tentam concorren- temente colocar uma tupla no final da lista, pelo menos um deles consegue. Entretanto, o algoritmo n˜ao ´e livre de espera porque algum processo pode ser bem sucedido em inserir suas operac¸˜oes na lista infinitas vezes, atrasando outros processos para sempre.

A pol´ıtica de acesso para a construc¸˜ao universal (apresentada na figura 6.6) define que uma tupla SEQ com um segundo campo pos s´o pode ser inserida no espac¸o (usando cas) se existe uma tupla com segundo campo com valor pos − 1 no espac¸o.

Algoritmo 14 Construc¸˜ao universal n˜ao-bloqueante (processo pi).

Vari´aveis compartilhadas:

1: ts= ∅ {PEATS}

Vari´aveis locais:

2: state= ST {estado atual do objeto}

3: pos= 0 {posic¸˜ao do fim da lista de operac¸˜oes}

invoked inv

4: loop

5: pos← pos + 1

6: if ts.cas(hSEQ, pos, ?pos invi, hSEQ, pos, invi) then

7: hstate, replyi ← applyT(state, inv)

8: return reply

9: end if

10: hstate, replyi ← applyT(state, pos inv) 11: end loop

Object State T S

Rcas: execute(cas(hSEQ, pos, xi, hSEQ, pos, invi)) : −

invoke(p, cas(hSEQ, pos, xi, hSEQ, pos, invi)) ∧ formal(x)∧ (pos = 1 ∨ ∃y : hSEQ, pos − 1, yi) ∈ T S)

Figura 6.6: Pol´ıtica de acesso para o PEATS usado no algoritmo 14.

A prova de correc¸˜ao do algoritmo ´e baseada nos seguintes lemas:

Lema 10 Em qualquer execuc¸˜ao do sistema, as seguintes propriedades s˜ao invariantes do PEATS usado no algoritmo 14:

1. Para qualquer pos≥ 1, existe no m´aximo uma tupla hSEQ, pos, invi no espac¸o de tuplas; 2. Para qualquer tuplahSEQ, pos, invi no espac¸o de tuplas, com pos > 1, existe exatamente uma

tuplahSEQ, pos − 1, invi no espac¸o.

Prova: Estas duas invariantes s˜ao conseq¨uˆencias diretas do algoritmo 14 e de sua pol´ıtica de acesso (figura 6.6):

1. A partir da pol´ıtica de acesso pode-se verificar que uma tupla s´o pode ser inserida no espac¸o atrav´es de uma invocac¸˜ao da operac¸˜ao cas, onde o molde e a entrada passados como argumento devem ser tuplas SEQ com o mesmo n´umero de seq¨uˆencia seq e o campo da invocac¸˜ao do molde deve ser formal. Com essa propriedade e a definic¸˜ao do cas, ´e f´acil ver que n˜ao pode haver duas tuplas SEQ com o mesmo n´umero de seq¨uˆencia no espac¸o de tuplas.

2. Novamente, a partir da pol´ıtica de acesso ´e poss´ıvel ver que a operac¸˜ao cas s´o pode ser exe- cutada para inserir uma operac¸˜ao na posic¸˜ao pos se existe uma tupla no espac¸o com n´umero de seq¨uˆencia uma unidade menor. Isto garante que existe uma tupla hSEQ, pos − 1, invi no espac¸o quando da inserc¸˜ao da tupla pos. A garantia de que n˜ao existe mais de uma tupla dessa

Lema 11 A construc¸˜ao universal do algoritmo 14 ´e n˜ao-bloqueante.

Prova: Este lema ´e provado por contradic¸˜ao. Considere, sem perda de generalidade, uma execuc¸˜ao α onde apenas dois processos corretos p1 e p2executam as invocac¸˜oes inv1 e inv2, respectivamente.

Suponha que eles permanecem parados para sempre, n˜ao recebendo resposta para essas invocac¸˜oes. Vamos mostrar que α n˜ao existe. Uma inspec¸˜ao no algoritmo mostra que os processos permanecem atualizando suas c´opias do estado do objeto at´e que eles executem a mais recente operac¸˜ao inserida no espac¸o de tuplas (com campo posic¸˜ao igual `a pos). Neste ponto, p1 e p2 v˜ao tentar adicionar

suas invocac¸˜oes no espac¸o na posic¸˜ao pos + 1 atrav´es da execuc¸˜ao da operac¸˜ao cas (linha 6). Como assumimos que o PEATS ´e lineariz´avel, as duas invocac¸˜oes a operac¸˜ao cas devem acontecer uma ap´os a outra, assim ou a tupla SEQ com inv1ou a com inv2ser´a inserida no espac¸o na posic¸˜ao pos + 1. O

processo bem sucedido executando cas para esta posic¸˜ao vai inserir sua invocac¸˜ao para o objeto, e vai retornar o resultado desta operac¸˜ao (linhas 7 e 8). Este fato contradiz a definic¸˜ao de α.  Teorema 7 O algoritmo 14 provˆe uma construc¸˜ao universal n˜ao-bloqueante.

Prova: O resultado apresentado no lema 10 implica na existˆencia de uma ordem total das operac¸˜oes executadas no objeto emulado. Atrav´es de uma inspec¸˜ao no algoritmo, ´e f´acil ver que um processo correto atualiza sua c´opia do estado do objeto emulado aplicando a func¸˜ao determinista applyT em

todas as tuplas SEQ na ordem definida pelos seus n´umeros de seq¨uˆencia. Desta forma, todas as operac¸˜oes s˜ao executadas na mesma ordem por todos os processos corretos e esta ordem ´e condizente com especificac¸˜ao seq¨uencial do objeto, provida pela func¸˜ao applyT. Isto ´e suficiente para provar que a construc¸˜ao universal satisfaz linearizac¸˜ao. O lema 11 prova que a construc¸˜ao ´e n˜ao-bloqueante.