Escolar Documentos
Profissional Documentos
Cultura Documentos
Este captulo discute o problema de garantir exclusividade de execuo para um processo, em um sistema de processos concorrentes. Os protocolos que implementam excluso mtua entre processos so algoritmos clssicos e interessantes por si s. Nos algoritmos aqui apresentados no so usados recursos especiais de programao. Na verdade, eles podem ser expressos em qualquer linguagem de programao.
42
de leitura podem ocorrer simultaneamente com atualizaes, pois os dados lidos podem estar temporariamente inconsistentes. O seguinte exemplo ilustra os problemas que podem ocorrer quando no se garante excluso mtua no acesso aos dados compartilhados. Supor que um vetor global R de 5 elementos seja utilizado para controlar a alocao de 5 unidades de um recurso (o recurso poderia ser, por exemplo, 5 blocos de memria de igual tamanho). A varivel global T usada como contador de unidades disponveis e cada elemento do vetor identifica uma unidade. O valor R[T] (isto , o elemento de R cujo ndice T) indica a prxima unidade a ser alocada. Os valores iniciais de R e T (com todas as unidades livres) so: R = [5, 4, 3, 2, 1] T=5 Os procedimentos para requisitar e liberar uma unidade do recurso so: requisita(U): ... U:=R[T]; T:=T-1; ... libera(U): ... T:=T+1; R[T]:=U; ...
Vamos supor que as 5 unidades tenham sido requisitadas (e alocadas) sem ocorrncia de erro e que, em seguida, 3 delas tenham sido liberadas. Supondo que as unidades liberadas sejam as de nmero 3, 1 e 4, nesta ordem, a estrutura de dados que descreve o recurso ficaria na seguinte situao: R = [3, 1, 4, 2, 1] T=3 Isto significa que, no momento, esto disponveis as unidades 3, 1 e 4 (portanto, esto alocadas as unidades 5 e 2). Supor que, agora, dois processos executem as operaes libera(5) e requisita(K) e que as 4 operaes envolvidas sejam executadas na seguinte ordem: T:=T+1 K:=R[T] T:=T-1 R[T]:=5 O resultado neste caso ser: R = [3, 1, 5, 2, 1] T=3 E ter acontecido o seguinte: a unidade 2, que estava sendo usada por um processo, ter sido alocada para outro processo (o que no pode acontecer) e a unidade 5, liberada, estar (passo 1 de libera(5): T=4) (passo 1 de requisita(K): K=R[4]=2) (passo 2 de requisita(K): T=3) (passo 2 de libera(5): R[3]=5)
43
ocupando a 3 posio do vetor R (lugar onde estava a unidade 4). O fato da unidade 5 ocupar o lugar onde estava a unidade 4, faz com que a unidade 4 desaparea do conjunto de unidades disponveis. Em resumo, a unidade 2 estar alocada para dois processos ao mesmo tempo e estaro disponveis as unidades 3, 1 e 5 (a unidade 4 sumiu do sistema). O resultado correto da execuo das operaes libera(5) || requisita(K) poderia ser qualquer um dos dois seguintes: R = [3, 1, 4, 5, 1] T=3 ou R = [3, 1, 5, 2, 1] T=3
No primeiro caso teria sido alocada a unidade K=5, ficando disponveis as unidades 3, 1 e 4. No segundo caso teria sido alocada a unidade K=4, ficando disponveis as unidades 3, 1 e 5. Este exemplo ilustra o conceito de condio de corrida (race condition seo 2.2), pois o resultado da execuo funo das velocidades relativas dos processos (ou da ordem com que os processos acessam os dados compartilhados). Na histria da computao existem diversos exemplos de desastres devidos a esse tipo de erro. O caso da mquina de radioterapia Therac-25 um exemplo clssico [LEV 93]. Uma condio de corrida fazia com que, s vezes, essa mquina administrasse dosagens milhares de vezes maior que a normal, resultando na morte ou em srios danos para os pacientes.
Um busy loop uma situao na qual um processo fica utilizando o processador de forma contnua (testando uma condio), sem realizar trabalho til.
44
um processo esperar pelo outro. So utilizadas variveis globais (compartilhadas) para decidir se possvel entrar na regio crtica ou no, e, em toda soluo, ambos os processos executam o mesmo cdigo (ou protocolo de acesso). Os algoritmos so especificados utilizando a linguagem Vale 4. Nessa linguagem, o smbolo representa o operador lgico not (na verdade, o compilador aceita ambas as representaes e not).
Tentativa 1
Varivel global: em_uso: boolean initial false; A varivel global indica se alguma regio crtica est em uso ou no. Cdigo de um processo: ... loop exit when em_uso endloop; em_uso:=true; REGIO CRTICA; em_uso:= false; ... A soluo no correta, pois os processos podem chegar concluso simultaneamente que a entrada est livre (em_uso=false). Isto , os dois processos podem ler (testar) o valor de em_uso antes que essa varivel seja feita igual a true por um deles. OBSERVAO: Para os prximos algoritmos, supe-se que os processos tenham duas variveis locais, eu e outro. Para o processo 1, eu=1 e outro=2; para o processo 2, eu=2 e outro=1. Os cdigos dos processos so iguais, mas cada processo usa suas variveis privativas eu e outro.
45
Tentativa 2
Varivel global: vez: integer initial 1; Esta varivel indica de quem a vez, na hora de entrar na regio crtica. Cdigo de um processo: ... loop exit when vez=eu endloop; REGIO CRTICA; vez:= outro; ... Este algoritmo garante excluso mtua, mas obriga a alternncia na execuo das regies crticas (isto , primeiro entra P1, depois P2, depois P1, etc). No possvel um mesmo processo entrar duas vezes consecutivamente. Se P2 desejar entrar primeiro na sua regio crtica, ele no poder faz-lo, pois P1 deve ser o primeiro. Se um processo terminar, o outro no poder mais entrar na sua regio crtica. No aceitvel que um processo tranque a entrada de outro sem necessidade.
Tentativa 3
Varivel global: quer: array[2] of boolean initial false; Se quer[i] true, isto indica que o processo Pi (i{1,2}) quer entrar na sua regio crtica. Observe que o valor inicial especificado para um array (vetor ou matriz) se aplica a todos os elementos desse array. Esta conveno adotada na linguagem V4. Cdigo de um processo: ... loop exit when quer[outro] endloop; quer[eu]:=true; REGIO CRTICA; quer[eu]:=false; ... A soluo no assegura excluso mtua. Repete-se aqui o mesmo problema da tentativa 1, pois cada processo pode chegar concluso que o outro no quer entrar e assim entrarem
46
simultaneamente na regio crtica. Isso acontece porque existe a possibilidade de cada processo testar se o outro no quer entrar antes de um deles marcar a sua inteno de entrar. O prximo algoritmo (tentativa 4) soluciona esse problema fazendo com que cada processo marque sua inteno de entrar antes de testar a inteno do outro. OBSERVAO IMPORTANTE: Se cada processo marca sua inteno de entrar antes de testar a inteno do outro, ento, certamente, se um processo chega concluso que o outro no quer entrar porque esse outro ainda no testou a inteno do primeiro (pois o teste realizado depois de marcar a inteno de entrar). Portanto, quando esse outro processo for realizar o teste, certamente, ir encontrar a indicao que o parceiro quer entrar. Isto impossibilita que os dois processos cheguem simultaneamente a concluso que o outro no quer entrar.
Tentativa 4
Varivel global: quer: array[2] of boolean initial false; o mesmo algoritmo anterior, porm marcando a inteno de entrar, antes de testar a inteno do outro processo. Cdigo de um processo: ... quer[eu]:=true; loop exit when quer[outro] endloop; REGIO CRTICA; quer[eu]:=false; ... Com este algoritmo a excluso mtua garantida, mas, infelizmente, os processos podem entrar em um loop eterno. Isto porque ambos os processos podem marcar simultaneamente a inteno de entrar (antes que um deles consiga testar, dentro do loop, se o outro quer entrar ou no). Nesse caso, depois de entrarem no loop, os processos no vo sair mais de l. O prximo algoritmo melhora esta tentativa de soluo, pois, dentro do loop, o processo verifica se o outro tambm quer entrar e, em caso afirmativo, d a vez para o parceiro.
47
Tentativa 5
Varivel global: quer: array[2] of boolean initial false; semelhante ao algoritmo anterior, porm o processo d a vez para o outro no caso do outro querer entrar. Cdigo de um processo: ... incio: quer[eu]:=true; if quer[outro] then { quer[eu]:=false; goto inicio }; REGIO CRTICA; quer[eu]:=false; ... A excluso mtua continua garantida, mas pode acontecer dos processos ficarem dando a vez um para o outro indefinidamente. Embora essa sincronizao dos processos seja difcil de acontecer na prtica, ela no deixa de ser teoricamente possvel. O algoritmo seguinte soluciona definitivamente o problema, usando uma varivel adicional vez para resolver as situaes de empate. Esta varivel s usada quando os dois processos querem entrar simultaneamente nas regies crticas.
48
loop exit when vez=eu endloop; goto incio }; REGIO CRTICA; quer[eu]:=false; vez:=outro; ... O algoritmo satisfaz todas as exigncias para a soluo ser considerada correta, quaisquer que sejam as velocidades relativas dos processos. Por exemplo, no acontece de um processo ficar eternamente tentando entrar na sua regio crtica enquanto o outro, mais veloz, entra e sai repetidamente da sua regio crtica.
49
Verso 2: o mesmo algoritmo anterior, porm com outros nomes de variveis, que iro facilitar o entendimento da generalizao para n processos, a ser discutida na seo 4.3.4. Na generalizao, interessa saber qual foi o ltimo processo que chegou e no o primeiro. Na verso a seguir, em caso de empate, fica trancado o ltimo que chegou (antes, nesse caso, entrava o primeiro que tinha chegado o que equivalente). Variveis globais: quer: array[2] of boolean initial false; ultimo: integer; Cdigo de um processo: ... quer[eu]:= true; ultimo:= eu; loop exit when quer[outro] or ultimoeu endloop; REGIO CRTICA; quer[eu]:= false; ...
50
A seguir mostrada a soluo do problema da excluso mtua utilizando a funo TS. O algoritmo utiliza uma varivel global is_free para controlar o acesso regio crtica. Varivel global: is_free: boolean initial true; Cdigo de um processo: ... loop exit when TS(is_free) endloop; REGIO CRTICA; is_free:= true; ... Deve ser observado que esta soluo vlida para qualquer nmero de processos. As solues anteriores valiam para 2 processos apenas.
51
Os dois vetores so inicializados com false. Os elementos quer[i] e dentro[i] so alterados apenas pelo processo i, 1in. A varivel vez assume valores entre 1 e n e seu valor inicial irrelevante. Cada processo utiliza uma varivel local k. O comando for k:=1 to n st ki ... endfor no faz parte da linguagem Vale 4. Nele, a sigla st deve ser entendida como such that (tal que). Em sua execuo, a varivel k vai assumir os valores 1, 2, ..., n, sendo deixada de fora a iterao correspondente a k=i. Cdigo do processo i: ... quer[i]:=true; inicio: loop dentro[i]:=false; if quer[vez] then vez:=i; exit when vez=i endloop; dentro[i]:=true; for k:=1 to n st ki if dentro[k] then goto inicio endfor; REGIO CRTICA; quer[i]:=false; dentro[i]:=false; ... Um processo i s entra na regio crtica se aps fazer o seu dentro[i] igual a true ele encontra todos os demais processos com "dentros" iguais a false. Isto garante excluso mtua. O requisito de progresso garantido pela seguinte propriedade: aps um processo i fazer vez:=i, nenhum outro conseguir atribuir seu nmero vez antes da regio crtica ser executada. Explicando melhor: se o processo vez no est entre os que desejam entrar, ento os que desejam entrar vo fazer vez:=eu; aps todas as atribuies varivel vez serem realizadas, essa varivel vai indicar um dos processos que deseja entrar e esse valor no vai ser mais alterado. Todos os processos que desejavam entrar, com exceo daquele indicado por vez, vo fazer seus dentros iguais a false e ficaro repetindo o comando loop. O requisito espera limitada no garantido, pois, teoricamente, um processo pode ficar indefinidamente tentando entrar na sua regio crtica, enquanto os outros entram e saem (convena-se disso).
52
53
O algoritmo similar ao de Dijkstra, porm corrigido em relao ao problema da espera limitada. A excluso mtua garantida, como antes, atravs do vetor dentro. A garantia de progresso conseguida da seguinte maneira: o valor de vez alterado apenas quando um processo entra na regio crtica (e, mais tarde, quando sai); ento, se nenhum processo est entrando ou saindo de sua regio crtica, o valor de vez permanece constante; dentre os processos que desejam entrar, o primeiro na ordenao cclica vez, vez+1, ..., n, 1, 2, ..., vez-1 o que vai conseguir. A espera limitada garantida porque quando um processo deixa a sua regio crtica ele designa como seu nico sucessor o primeiro processo, dentre os que desejam entrar, na ordem cclica vez+1, ..., n, 1, 2, ..., vez-1, vez; isto garante que qualquer processo desejando entrar espere no mximo n-1 processos entrar antes dele. Convm observar que, se nenhum processo deseja entrar na sua regio crtica, o processo que sai da regio crtica faz vez igual ao seu prprio nmero. Por motivos didticos, o algoritmo acima usou os mesmos nomes de variveis usados pelo algoritmo de Dijkstra. Isto facilita o seu atendimento e deixa claro o relacionamento existente entre os dois algoritmos. O algoritmo original de Eisenberg e McGuire [EIS 72] pode ser encontrado na maioria dos livros de programao concorrente e sistemas operacionais.
54
Cdigo do processo i: ... pegando[i]:= true; ticket[i]:= max(ticket[1],ticket[2],...,ticket[n]) + 1; pegando[i]:= false; for j:= 1 to n st ji loop exit when pegando[j] endloop; loop exit when ticket[j]=0 or (ticket[i],i)<(ticket[j],j) endloop endfor; REGIO CRTICA; ticket[i]:= 0; ... Antes de entrar na regio crtica, o processo i compara o seu ticket com o ticket de cada outro processo j; essa comparao feita s aps i adquirir a certeza (no primeiro loop) que ou (1) j j pegou o seu ticket (i., j foi atribuido um valor ticket[j]), ou (2) j ainda no iniciou o processo de retirar um ticket (e nesse caso certamente j ir pegar um ticket maior que ticket[i]). No primeiro caso pode-se ter qualquer relao entre ticket[i] e ticket[j] (maior, menor ou igual), mas certamente o par (ticket[id], id) de um dos processos ser estritamente menor que o par do outro. Nesse caso, o processo com o maior par ficar retido no segundo loop at que o outro entre e saia da sua regio crtica, garantindo a excluso mtua. Para mostrar que o progresso e a espera limitada so garantidos e que o algoritmo justo (isto , atende igualmente a todos), suficiente observar que os processos entram nas suas regies crticas na ordem FCFS (First Come First Served). Teoricamente, possvel que mais de um processo entre na regio crtica. Isto pode ocorrer quando o limite de representao de inteiros ultrapassado no comando que obtm o nmero do ticket, sendo atribudo a um processo um nmero menor que o do processo correntemente na regio crtica.
55
(b) chega outro processo no estgio em que ele est (ele deixa de ser o ltimo no seu estgio atual). Variveis globais: estagio: array[n] of integer initial 0; ultimo: array[ n-1] of integer; No vetor estagio, o elemento estagio[i], 1in, indica o estgio atual do processo i. Portanto, cada elemento corresponde a um processo (inicialmente, todos os elementos esto zerados). No vetor ultimo, o elemento ultimo[j], 1jn-1, indica qual o ltimo processo que chegou ao estgio j, portanto cada elemento corresponde a um estgio. Cdigo do processo i: ... for j:= 1 to n-1 /*percorre os n-1 estgios*/ estagio[i]:=j; /*estgio atual de i*/ ultimo[j]:=i; /*o ltimo sou eu*/ for k:= 1 to n st ki loop exit when estagio[i]>estagio[k] or ultimo[j]i endloop endfor endfor; REGIO CRTICA; estagio[i]:= 0; ... Em cada estgio o processo se compara com todos os demais. O processo decide se avana nessas comparaes atravs do algoritmo de 2 processos, mas com uma interpretao um pouco diferente. Aqui o processo avana quando ele est num estgio mais adiantado (em relao ao outro) ou quando ele no o ltimo no estgio atual. S aps ter sucesso na comparao com todos os demais que o processo avana um estgio. O comportamento resultante o seguinte: o processo i avana um estgio sempre que (a) todos os processos na sua frente saem de suas regies crticas ou (b) outro processo entra no seu estgio atual (pi deixa de ser o ltimo). Enquanto um processo est executando (ou tentando entrar) na regio crtica, os estgios funcionam como barreiras (em cada barreira fica retido o ltimo que l chega): o estgio 1 deixa passar no mximo n-1 processos, o estgio 2 deixa passar no mximo n-2 e o ltimo deixa passar apenas 1 processo. Isto garante a excluso mtua. Para se convencer que os outros dois requisitos tambm so satisfeitos basta observar que um processo se bloqueia somente se algum outro est na sua frente; como um processo no fica indefinidamente na sua regio crtica, isto garante que todos os processos possam avanar.
56
Deve ser observado que para entrar na regio crtica todo processo executa O(n2) vezes o algoritmo para 2 processos, mesmo que s um esteja desejando entrar. O algoritmo a seguir reduz o nmero de operaes para O(n*m) quando a competio envolve apenas m dos n processos.
57
Considerando que m processos esto competindo, a complexidade do algoritmo O(n*m) visto que so percorridos apenas m estgios e, em cada estgio, so verificados os valores dos n elementos do vetor quer.
58
cada par de processos <i, j>, com ij, usa o algoritmo de dois processos, com variveis nicas e exclusivas30 do par. Nessa competio decidido quem prossegue e quem fica retido. A prova de que o algoritmo satisfaz as condies de progresso e de espera limitada deixada como exerccio.
4.4 EXERCCIOS
Exerccio 4.1 Um especialista em programao concorrente apresentou a seguinte soluo para o problema da excluso mtua entre dois processos: Variveis compartilhadas: quer : array[2] of boolean initial false; vez : integer; Processo 1: ... quer[1] := true; loop exit when vez=1; if quer[2] then vez:=1 endloop; REGIO CRTICA; quer[1] := false; ... Responda (justificando a resposta): (a) Pode haver bloqueio eterno dos dois processos? (b) Os dois processos podem estar simultaneamente na regio crtica? Exerccio 4.2 (Soluo de Hyman [HYM 66].) Explique se a seguinte soluo para 2 processos satisfaz as 3 condies para que um algoritmo de excluso mtua seja considerado correto: Variveis globais: quer : array[2] of boolean initial false; vez : integer initial 1 Cdigo de um processo: ... quer[eu]:= true; loop exit when vez=eu; loop
30
Processo 2: ... quer[2] := true; loop exit when vez=2; if quer[1] then vez:=2 endloop; REGIO CRTICA; quer[2] := false; ...
Mesmo os pares <i, j> e <i, k> usam conjuntos disjuntos de variveis, se jk.
59
exit when quer[outro] endloop; vez:= eu endloop; REGIO CRTICA; quer[eu]:= false; ... Exerccio 4.3 (Soluo de Doran & Thomas [DOR 80]) Compare a seguinte soluo com a soluo de Dekker e diga se ela correta ou no. Cdigo de um processo: ... quer[eu]:=true; if quer[outro] then if vez=outro then { quer[eu]:=false; loop exit when vez=eu endloop quer[eu]:=true; } REGIO CRTICA; quer[eu]:=false; vez:=outro ... Exerccio 4.4 Considerando o algoritmo de Dijkstra, mostre que o mesmo no satisfaz o requisito de espera limitada, isto , mostre que um processo pode ficar indefinidamente tentando entrar na sua regio crtica enquanto os outros entram e saem. Exerccio 4.5 Responda se o algoritmo de Dijkstra permite que se tenha um processo k dentro da regio crtica e ao mesmo tempo se tenha vezk. Exerccio 4.6 A seguir apresentada a soluo original de Eisenberg e McGuire. Compare a soluo com o algoritmo apresentado no texto. Variveis globais: flag: array[n] of (out, quer, in); vez: integer;
60
Os elementos do vetor flag so inicializados com out. O valor de flag[i] alterado apenas pelo processo i. A varivel vez assume valores entre 1 e n e seu valor inicial irrelevante. Cada processo utiliza uma varivel local k. Cdigo do processo i: ... inicio: flag[i]:=quer; k:=vez; loop if flag[k]=out then k:=(k mod n)+1 else k:=vez; exit when k=i endloop; flag[i]:=in; for k:=1 to n st ki if flag[k]=in then goto inicio endfor; if vezi and flag[vez]out then goto inicio; vez:=i; REGIO CRTICA; k:=(vez mod n)+1; loop exit when flag[k]out; k:=(k mod n)+1 endloop; vez:=k; flag[i]:=out; ... Exerccio 4.7 No algoritmo de Block&Woo por que o comando repeat termina por until ultimo[estagio] = i e no por until estagio=quer ? Exerccio 4.8 Prove que o algoritmo de Toscani satisfaz as condies de progresso e de espera limitada. Exerccio 4.9 Usando a linguagem V4, programe os diversos algoritmos de excluso mtua e teste o funcionamento dos mesmos.