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