Espera Ocupada

Transcrição

Espera Ocupada
FACENS - Faculdade de Engenharia de Sorocaba
Sistemas Operacionais
Espera Ocupada
Peterson para 2 threads
Peterson genérico (NProcs)
int s = 0 ;
vez = 0 ;
int interesse[2];
Thread 1
int vez[N-1]; int fase[N-1];
Thread 2
while (true)
while (true)
interesse[1] = true;
interesse[2] = true;
vez = 1;
vez = 2;
while (vez == 1 &&
while (vez == 2 &&
interesse[2]);
s = 1;
interesse[1]);
s = 2;
print ("Thr 1:" , s);
print ("Thr 2:" , s);
interesse[1] = false;
interesse[2] = false;
O algoritmo de Peterson foi visto na última aula como algoritmo do desempate. Este algoritmo permite que uma thread,
sempre consiga entrar na região crı́tica se estiver pronta para utilizá-la. Se apenas uma thread está interessada pela RC, então
ela conseguirá entrar nela quantas vezes for necessário.
Thread i:
for k = 1 to N-1 do
fase(i) ← k
vez(k) ← i
waitfor ((∀ j 6= i: fase(j) < k) or (vez(k) 6= i))
RC // (s = i; print ("Thr " , i, s))
fase(i) = 0
Este algoritmo generaliza a idéia do algoritmo de Peterson de
2 processos para n processos. Em cada fase (iteração do k),
o algoritmo garante que haverá pelo menos um perdedor. No
primeiro nı́vel, todos os processos podem competir, mas apenas
n − 1 processos podem passar para a fase seguinte. Depois de
n − 1 nı́veis, apenas um processo conseguirá entrar na RC. Note
que as variáveis vez e fase são compartilhadas entre as threads
porém as variáveis k e j são locais as threads. Esta solução
garante justiça entre os competidores.
Peterson genérico – Campeonato
int vez 01 = 0; int vez 23 = 0; int vez final = 0 ;
int i elim[4] = {0, 0, 0, 0}; int i final[2] = {0, 0};
Thread 0
i elim[0] = true; vez 01 = 0;
while (vez 01 == 0 && i elim[1]);
i final[0] = true;
vez final = 0;
while (vez final == 0 && i final[1]);
s = 0;
print ("Thr 0:" , s);
i final[0] = false;
i elim[0] = false;
Esta solução pode ser facilmente generalizada para n threads.
Basta fazer com que a disputa seja feita de 2 a 2 threads como
em um campeonato até que apenas uma delas seja a vencedora
final com direito a entrar na RC. Se 4 threads t0 , t1 , t2 , t3 estão
disputando pela RC, uma possı́vel ordem de entrada na RC seria:
t0 , t2 , t1 , t3 . Note que se t3 não tem interesse pela RC e as outras
disputam a RC por tempo indeterminado, a saı́da passaria a ser
t0 , t 2 , t 1 , t 2 , t 0 , t 2 , t 1 , t 2 , . . .
Profa. Tiemi Christine Sakata
1
FACENS - Faculdade de Engenharia de Sorocaba
Algoritmo da Padaria
Primeira tentativa
num[N] = { 0, 0, 0, 0, 0, ..., 0 };
Thr i:
num[i] = max (num[0]...num[N]) + 1;
for (j = 0; j < N; j++)
while (num[j] != 0 &&
num[j] < num[i]) ;
RC
num[i] = 0;
Este é o chamado algoritmo da padaria. Na realidade, qualquer loja que atenda os seus clientes baseando-se na entrega de
senhas. Nas lojas, a entrega de senhas é centralizada. Neste algoritmo não. Funciona como se para saber a sua senha o cliente
olhasse as senhas de todos os outros clientes que estão na loja e
atribuı́sse a si mesmo um número maior.
Para entrar na RC, a thread deve escolher um número e só
poderá entrar na RC a thread que tiver o menor número.
Neste algoritmo podemos ter empates. Basta que duas ou
mais threads executem num[i] = max simultaneamente.
Sistemas Operacionais
Algoritmo da Padaria
num[N] = { 0, 0, 0, 0, 0, ..., 0 };
escolhendo[N] = { 0, 0, 0, ..., 0 };
Thr i:
escolhendo[i] = 1;
num[i] = max (num[0]...num[N]) + 1;
escolhendo[i] = 0;
for (j = 0; j < N; j++)
while (escolhendo[j]);
while (num[j] != 0 && (num[j],j) < (num[i],i)) ;
RC
num[i] = 0;
Se uma thread Thr j estiver escolhendo um número, a
thread Thr i deverá esperar pelo término da escolha, pois Thr
j pode atribuir um número menor ou igual do que o de Thr i.
Se Thr i está na posição k e Thr j, j < k, começa a escolher,
com certeza escolherá um número maior do que o de Thr i.
Algoritmo da Padaria
Segunda tentativa
O desempate para o algoritmo da primeira
tentativa poderia ser feito por meio do
identificador da thread.
while (num[j] != 0 &&
num[j] < num[i] ||
num[j] == num[i] && j < i);
Outro problema acontece quando Thr i está conferindo a
posição k e a Thr j, j < k, faz uma atribuição ¨atrasada¨. Por
exemplo, suponha que temos 4 threads e a Thr 1 verificou que
o número máximo de todas as senhas é zero e antes de fazer
a atribuição do seu número, ocorre uma interrupção e a Thr 0
começa a sua execução. Como Thr 1 não atualizou sua senha, a
Thr 0 verifica o máximo de todas as outras senhas, ou seja, zero
e atribui 1 como sendo sua senha. Thr 0 verifica que a condição
do while é falsa para a Thr 1, Thr 2, Thr 3 e entra na região
crı́tica. Quando a Thr 1 volta a sua execução, atribui 1 como
sua senha e verifica a condição do while para j = 0. Como a
condição num[0] == num[1] && 0 < 1 é falsa, ele passa para
j = 2, j = 3 e também consegue entrar na região crı́tica.
Profa. Tiemi Christine Sakata
2