Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns...

105
Sincronização

Transcript of Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns...

Page 1: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização

Page 2: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Tipos de Sincronização

Competição de vários processos porum recurso

Exclusão mútua

Cooperação entre processosProdutores-consumidoresLeitores-escritoresJantar de filósofos

Page 3: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua

Page 4: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Problema da ExclusãoMútuaint levantar_dinheiro (ref *conta, int valor)

{if (conta->saldo >= valor) {

conta->saldo = conta->saldo – valor;} else valor = -1return valor;

}

Page 5: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Problema da ExclusãoMútua (à lupa)

As instruções C correspondem normalmente a váriasinstruções máquina

int levantar_dinheiro (ref *conta, int valor){if (conta->saldo >= valor) {

/* conta->saldo = conta->saldo – valor; */mov R1, conta->saldomov R2, valorsub R1, R2mov conta->saldo, R1

} else valor = -1return valor;

}

Page 6: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Problema da ExclusãoMútua (à lupa)

int levantar_dinheiro (ref *conta, int valor)

{if (conta->saldo >= valor) {mov R1, conta->saldomov R2, valor

sub R1, R2mov conta->saldo, R1

} valor = -1;return valor;

}

int levantar_dinheiro (ref *conta, int valor)

{if (conta->saldo >= valor) {mov R1, conta->saldomov R2, valorsub R1, R2mov conta->saldo, R1

} else valor = -1;return valor;

}

P1 P2

Interrupção provocacomutação de processos

Saldo inicial = 100Valor = 50

Saldo inicial = 1002 levantamentos de 50Saldo final = 50!!

SO volta a escalonar P1

Page 7: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Secção crítica(intuitivamente)

int levantar_dinheiro (ref *conta, int valor)

{if (conta->saldo >= valor) {

/* conta->saldo = conta->saldo – valor; */mov R1, conta->saldomov R2, valor

sub R1, R2mov conta->saldo, R3

} else valor = -1return valor;

}

Secção Crítica:não pode serinterrompida

Page 8: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Secção Crítica

Propriedade de exclusão mútua: as instruções de uma região críticade dois ou mais processos nãopodem ser intercaladas emnenhuma execução.

Page 9: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Formato dos programas

loop secção não críticafechar() // pré-protocolosecção críticaabrir() // pós-protocolo

end

Page 10: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

PropriedadesUm processo pode bloquear-se na secção não crítica, sem interferir com os outros processos. Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles irá consegui-lo alguma vez no futuro. Não pode haver míngua (starvation). Se um processo inicia o pré-protocolo, então alguma vez no futuro iráconseguir o acesso à região crítica. Na ausência de contenção, se um único processo quiser entrar na região crítica, consegui-lo-á e de uma forma eficiente.

Page 11: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Deadlock, livelock, starvation

Deadlock (interblocagem): Para qualquerexecução, nenhum processo conseguefazer progresso. Todos os processosficam bloqueados à espera uns dos outros.Livelock: Existe pelo menos umaexecução para a qual nenhum processoconsegue fazer progresso.Starvation (míngua): Um dos processosnão consegue fazer progresso, enquantoos outros conseguem.

Page 12: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

InterblocagemPropriedade estável: não há forma dos processos saírem da interblocagem. Normalmente é necessário terminar um ou mais processosFácil de detectar (“pára tudo”), impossível de inverterEx: Proc A está à espera de Proc BProc B está à espera de Proc CProc C está à espera de Proc A

A

BC

Page 13: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

MínguaPropriedade instável: os processos podem fazer progresso, mas há pelo menos uma combinação de acontecimentos que, se se repetirem consecutivamente, faz com que um deles nunca consiga fazer progressoDifícil de detectar pois qualquer alteração pode fazer com que se “esconda”… mas fica à espera do pior momento para reaparecer (Lei de Murphy)!Ex.: processo nunca é atendido porque outros mais prioritários lhe passam sempre à frente

Page 14: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Soluções para o problema da Secção Crítica

Soluções algorítmicasSoluções com suporte de hardwareSoluções oferecidas pelo Sistema Operativo (com suporte de hardware)

Page 15: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Soluções algorítmicas

O pré-protocolo (fechar()) e o pós-protocolo (abrir()) usam apenasinstruções normais com leitura e escrita na memória

Algoritmo DekkerAlgoritmo PetersenAlgoritmo Lamport (Bakery)

Page 16: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Primeira tentativa

int p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE;

p1_fechar(){

while (p2—quer—entrar);p1—quer—entrar = TRUE;

}

p1_abrir(){

p1—quer—entrar = FALSE; }

p2_fechar(){

while (p1—quer—entrar);p2—quer—entrar = TRUE;

}

p2_abrir(){

p2—quer—entrar = FALSE; }

Não garante exclusão mútua. Porquê ?

Processo 1 Processo 2

Page 17: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Segunda tentativa

int p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE;

p1_fechar(){

p1—quer—entrar = TRUE;while (p2—quer—entrar);

}

p1_abrir(){

p1—quer—entrar = FALSE; }

p2_fechar(){

p2—quer—entrar = TRUE;while (p1—quer—entrar);

}

p2_abrir(){

p2—quer—entrar = FALSE; }

Interblocagem. Porquê ?

Processo 1 Processo 2

Page 18: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Terceira tentativa

int p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE;

p1_fechar(){

p1—quer—entrar = TRUE;while (p2—quer—entrar);

}

p1_abrir(){

p1—quer—entrar = FALSE; }

p2_fechar(){

p2—quer—entrar = TRUE;while (p1—quer—entrar) {

p2-que-entrar = FALSE;while(p1—quer—entrar);p2—quer—entrar = TRUE;

}}

p2_abrir(){

p2—quer—entrar = FALSE; }

Míngua. Porquê ?

Processo 1 Processo 2

Page 19: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Quarta tentativa

int proc—prio = 1;

p1_fechar(){

while (proc-prio == 2); }

p1_abrir(){

proc-prio = 2; }

p2_fechar(){

while (proc-prio == 1); }

p2_abrir(){

proc-prio = 1;}

Não garante nem a 1º nem a 4ª propriedade. Porquê ?

Processo 1 Processo 2

Page 20: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo Dekkerint p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE; int proc—prio = 1; p1_fechar(){

p1—quer—entrar = TRUE; a1: while (p2—quer—entrar) {a2: if (proc—prio == 2) {

p1—quer—entrar = FALSE; while (proc—prio == 2) ;

p1—quer—entrar = TRUE; }

}}p1_abrir(){

p1—quer—entrar = FALSE; proc—prio = 2;

}

p2_fechar() {

p2—quer—entrar = TRUE; a1: while (p1—quer—entrar) {a2: if (proc—prio == 1) {

p2—quer—entrar = FALSE; while (proc—prio == 1) ;

p2—quer—entrar = TRUE; }

}}p2_abrir()

{ p2—quer—entrar = FALSE; proc—prio = 1;

}

Page 21: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo Dekkerint p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE; int proc—prio = 1; p1_fechar(){

p1—quer—entrar = TRUE; a1: while (p2—quer—entrar) {a2: if (proc—prio == 2) {

p1—quer—entrar = FALSE; while (proc—prio == 2) ;

p1—quer—entrar = TRUE; }

}}p1_abrir(){

p1—quer—entrar = FALSE; proc—prio = 2;

}

p2_fechar() {

p2—quer—entrar = TRUE; a1: while (p1—quer—entrar) {a2: if (proc—prio == 1) {

p2—quer—entrar = FALSE; while (proc—prio == 1) ;

p2—quer—entrar = TRUE; }

}}p2_abrir()

{ p2—quer—entrar = FALSE; proc—prio = 1;

}

•P1 anuncia que quer entrar•Verifica se P2 quer entrar. Se não quiser, P1 entra

•Se P2 quer entrar, mas P1 for o mais prioritário, P2 há-de retirar a intenção de entrar e P1 entra

•Senão, P1 indica que não quer entrar (para deixarP2 entrar) e fica em espera activa qté que P2 saia

•Ao sair, indica que já não está na secção crítica

•O algoritmo é totalmente simétrico, P2 fazexactamente o mesmo que P1 (basta trocar o “1”pelo “2” e vice-versa)

•P1 volta a anunciar que quer entrar e repete o pré-protocolo

Page 22: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo de Petersonint p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE; int proc—prio = 1; p1_fechar() {a1: p1—quer—entrar = TRUE; b1: proc—prio = 2; c1: while (p2—quer—entrar&&

proc—prio == 2) ;

}p1_abrir(){

p1—quer—entrar = FALSE; }

p2_fechar() {a2: p2—quer—entrar = TRUE; b2: proc—prio = 1; c2: while (p1—quer—entrar &&

proc—prio == 1) ;

}p2_abrir(){

p2—quer—entrar = FALSE; }

Page 23: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo de Petersonint p1—quer—entrar = FALSE; int p2—quer—entrar = FALSE; int proc—prio = 1; p1_fechar() {a1: p1—quer—entrar = TRUE; b1: proc—prio = 2; c1: while (p2—quer—entrar&&

proc—prio == 2) ;

}p1_abrir(){

p1—quer—entrar = FALSE; }

p2_fechar() {a2: p2—quer—entrar = TRUE; b2: proc—prio = 1; c2: while (p1—quer—entrar &&

proc—prio == 1) ;

}p2_abrir(){

p2—quer—entrar = FALSE; }

•P1 anuncia que quer entrar

•P1 estabelece P2 como mais prioritário•Se P2 não quer entrar, P1 entra•Se P2 quer entrar e for o prioritário, P1 fica emespera activa até que P2 saia•Se P1 e P2 quiserem entrar ao mesmo tempo, o último coloca o outro como prioritário

•Ao sair, indica que já não está na secção crítica

Page 24: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo de Bakery, N=2int n1 = 0; int n2 = 0; p1_fechar() {

n1 = 1; n1 = n2+1; while (n2 && n1 > n2) ;

}p1_abrir(){

n1 = 0; }

p2_fechar() {

n2 = 1; n2 = n1+1; while (n1 && n2 >= n1) ;

}p2_abrir(){

n2 = 0; }

Page 25: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Mais do que 2 processosAlgoritmo de Bakery (Lamport)

Cada processo que quer entrar num secção crítica escolhe um inteiro, maior do que qualquer outro inteiro escolhido.O processo com o menor número inteiro entra, os outros esperam.Os empates são resolvido pela identificação do processo

Garante exclusão mútuaGarante todas as propriedades enunciadas anteriormenteFavorece ligeiramente os processo com menor identificador.

Page 26: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Algoritmo de Bakeryint choosing[N]; // Inicializado a FALSEint ticket[N]; // Inicializado a 0fechar(int i) {

int j; choosing[i] = TRUE; ticket[i] = 1 + maxn(ticket); choosing[i] = FALSE;

for (j=0; j<N; j++) {if (j==i) continue; while (choosing[j]) ;

while (ticket[j] && (ticket[j] < ticket[i])||(ticket[i] == ticket[j] && j < i))) ;

}}abrir(int i){

ticket[i] = 0; }

•Pi verifica se tem a menor senha de todos os Pj

•Se Pj estiver a escolher uma senha, espera que termine

•Neste ponto, Pj ou já escolheu uma senha, ou ainda não escolheu

•Se escolheu, Pi vai ver se é menor que a sua•Se não escolheu, vai ver a de Pi e escolher uma senha maior

•Pi indica que está a escolher a senha•Escolhe uma senha maior que todas as outras•Anuncia que escolheu já a senha

•Se o ticket de Pi for menor, Pi entra•Se os tickets forem iguais, entra o que tiver o menor identificador

Page 27: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Conclusões sobre as Soluções Algorítmicas

Complicadas de usar directamente porprogramasNão funcionam dentro do sistema operativo (ex: rotinas de interrupção)Só contemplam espera activa, sendo muito ineficientes em esperas prolongadas (ex: esperar que uma tecla seja premida)Solução: Introduzir instruções hardware para facilitar a solução

Page 28: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Soluções com suporte do hardware

O pré-protocolo e pós-protocolousam instruções especiais oferecidaspelos processadores para facilitar a implementação da sincronização

Inibição de interrupçõesExchange (xchg no Intel IA)Test-and-set (cmpxchg no Intel IA)

Page 29: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua com inibição de interrupções

int mascara;fechar(){

mascara = mascarar_int();}abrir(){

repoe_int(m);}

•As interrupções são mascaradas(inibidas) na entrada da secção crítica

•Durante a secção crítica, como não há forma de interromper o processo, é garantidoque as instruções se executam atomicamente•Este mecanismo só pode ser utilizado dentro do sistema operativo em secçõescríticas de muito curta duração

•Inibição das interrupções impede que se executem serviços de sistema (I/O, etc)•Se o programa se esquecer de chamar abrir(), as interrupções ficam inibidas e o sistema fica parado

•Não funciona em multiprocessadores

•Na saída da secção crítica é reposta a máscara de interrupções que existia antes da secção crítica

Page 30: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

O problema da atomicidadecom multiprocessadores

CPU CPU CPU

Cache Cache Cache Cache

Memoria IO

bus

CPU

P2 na secção críticaERRO!!

P1 na secção críticaERRO!!

Instante 3

P2 inibe as suas interrupções e entra na secção crítica

Instante 2

P1 inibe as suas interrupções e entra na secção crítica

Instante 1

P2P1

Page 31: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua com exchangeint trinco = FALSE;

fechar() {

li R1, trinco; guarda em R1 o endereço do trincoli R2, #1

l1: exch R2, 0(R1); faz o exchangebnez R2, l1 ; se não estava a 0 entra, senão repete

}

abrir(){

trinco = FALSE;

}

Page 32: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua com exchangeint trinco = FALSE;

fechar() {

li R1, trinco; guarda em R1 o endereço do trincoli R2, #1

l1: exch R2, 0(R1); faz o exchangebnez R2, l1 ; se não estava a 0 entra, senão repete

}

abrir(){

trinco = FALSE;

}

•O exchange corresponde às seguintes operaçõesexecutadas de forma atómica

•lw Rt, 0(R1)•sw 0(R1), R2•mov R2, Rt

•A atomicidade é conseguida mantendo o bus trancado entre o Load e o Store

•R2 contém o valor que estava no trinco•Se era 0, o trinco estava livre

•O processo entra•O exchange deixou o trinco trancado

•Se não era 0, significa que o trinco estavatrancado

•O processo fica em espera activa até queencontre o trinco aberto

Page 33: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exchange emmultiprocessadores

CPU CPU CPU

Cache Cache Cache Cache

Memoria IO

bus

CPU

P2 verifica que o trinco estátrancado e fica em espera activa

P1 entra secção críticaInstante 3

P2 tenta fazer exchange masbloqueia-se a tentar obter o bus

P1 completa exchange e tranca a secção crítica

Instante 2

P1 inicia exchange e tranca o busInstante 1

P2P1

Page 34: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua com test-and-setint trinco = FALSE;

fechar() {

li R1, trinco; guarda em R1 o endereço do trincol1: tst R2, 0(R1); faz o test-and-set

bnez R2, l1 ; se não estava set entra, senão repete}abrir(){

trinco = FALSE; }

Page 35: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua com test-and-setint trinco = FALSE;

fechar() {

li R1, trinco; guarda em R1 o endereço do trincol1: tst R2, 0(R1); faz o test-and-set

bnez R2, l1 ; se não estava set entra, senão repete}abrir(){

trinco = FALSE; }

•O test-and-set corresponde às seguintes operaçõesexecutadas de forma atómica

•lw R2, 0(R1)•sw 0(R1), #1

•A atomicidade é conseguida mantendo o bus trancado entre o Load e o Store

•R2 contém o valor que estava no trinco•Se era 0, o trinco estava livre

•O processo entra•O test-and-set deixou o trinco trancado

•Se não era 0, significa que o trinco estavatrancado

•O processo fica em espera activa até queencontre o trinco aberto

Page 36: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Conclusões sobre as Soluçõescom Suporte do Hardware

Oferecem os mecanismos básicos para a implementação da exclusão mútua, mas...Não podem ser usadas directamente por programas em modo utilizador (ex: inibição de interrupções)Só contemplam espera activa, sendo muito ineficientes em esperas prolongadas (ex: esperar que uma tecla seja premida)

Page 37: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Soluções oferecidas peloSistema Operativo

Analisando as soluções anteriores (algorítmica e com suporte de hardware), conclui-se que…… tem que haver uma solução melhor para osprogramadores!Solução:

O Sistema Operativo oferece objectos de sincronização• Trinco Lógico: secções críticas• Semáforo: sincronização genérica

Programas utilizador sincronizam-se usando apenas Trincos Lógicos e Semáforos

• Interface simples• Semântica clara• Implementação eficiente e segura, assegurada pelo sistema

operativoA implementação dos objectos de sincronização no Sistema Operativo usa um misto das soluções algorítmicas e do suporte de hardware

Page 38: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Trinco LógicoObjecto do Sistema Operativo para a implementação de secções críticas em programas utilizadorOferece duas operações:

fechar (trinco): chamada pelo programa quando quer entrar na secção crítica

• Se a secção crítica estiver aberta, o processo entra na secção crítica e fecha-a

• Se a secção crítica estiver fechada, o processo bloqueia-se atéela ser aberta; nessa altura, entra na secção crítica e fecha-a

abrir (trinco): Chamada pelo programa quando quer sair da secção crítica

• Abre a secção crítica• Se houver processos bloqueados na secção crítica, acorda um

Page 39: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Trinco lógico

O trinco lógico serve exclusivamente para implementar exclusão mútuaUm processo só pode fazer abrir(t) se tiver previamente feitofechar(t)

O processo que faz abrir(t) tem que ser o mesmo que fez fechar(t)

Um trinco é criado sempre no estado ABERTO

No início da secção crítica, osprocessos têm que chamarfechar(t)Se o trinco estiver FECHADO, o processo espera que ele fiqueaberto. Quando ficar ABERTO, passa-o ao estado FECHADO. Estas operações executam-se atomicamente.

No fim da secção crítica, osprocessos têm que chamarabrir(t)Passa o trinco para o estadoABERTO e desbloqueia um processo que esteja à suaespera em fechar()

SecçãoCrítica:

trinco_t t = ABERTO;

int levantar_dinheiro (ref *conta, int valor){

fechar(t);if (conta->saldo >= valor) {conta->saldo = conta->saldo – valor;

} else valor = -1abrir(t);return valor;

}

Page 40: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Diagrama de Estado dos Processos

ExecuçãoEm

Executável Bloqueado

Seleccionado pelo Despacho

Retirado pelo Despacho

Bloqueado num Trinco Lógico

Desbloqueado

Page 41: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Cooperação entre Processos

Page 42: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Cooperação entre Processos

Vários processos executam em conjunto uma ou mais tarefas, nas quais

Competem por recursosIndicam uns aos outros a:• Ausência/existência de recursos• Ocorrência de acontecimentos

Page 43: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exemplo de Cooperação entreProcessos: produtor - consumidor

/* ProdutorConsumidor com semaforos */ int buf[N]; int prodptr=0, consptr=0; produtor() {

while(TRUE) {int item = produz(); buf[prodptr] = item; prodptr = (prodptr+1) % N;

}}

consumidor() {

while(TRUE) {int item; item = buf[consptr]; consptr = (consptr+1) % N; consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptr

Que acontece se não houveritens no buffer ?

Que acontece se o buffer estiver cheio ?

Page 44: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

SemáforosObjecto do sistema operativo para sincronizaçãogenéricaUm semáforo é conceptualmente composto por

ContadorFila de processos bloqueados no semáforo

Primitivascriar_semaforo(): cria um semáforo e inicializa o contadoresperar(s): bloqueia o processo chamador se o contador for menor ou igual a zero; senão decrementa o contadorassinalar(s): se houver processos bloqueados, liberta um; senão, incrementa o contador

Todas as primitivas se executam atomicamenteesperar() e assinalar() podem ser chamadas porprocessos diferentes.

Page 45: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Diagrama de Estado dos Processos

ExecuçãoEm

Executável Bloqueado

Seleccionado pelo Despacho

Retirado pelo Despacho

Bloqueado num semáforo

Desbloqueado

Page 46: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Semáforos – Estrutura de Dados

Semáforo s

Tabela deSemáforos do Sistema

Fila de processos bloqueados

Contador

Descritores dos processosbloqueados no semáforo s

Page 47: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

SemáforosExistem muitas variantes de semáforo

Genérico: assinalar() liberta um processo qualquerda filaFIFO: assinalar() liberta o processo que se bloqueouhá mais tempoSemáforo com prioridades: o processo especifica emesperar() a prioridade, assinalar() liberta osprocessos por ordem de prioridadesSemáforo com unidades: as primitivas esperar() e assinalar() permitem especificar o número de unidades a esperar ou assinalar

Page 48: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Semáforos: especificação do semáforo genérico

typedef struct {int contador;queue_t fila_procs;

} semaforo_t;

esperar

contador > 0

contador-- bloqueia processo

S N

assinalar

processosbloqueados

desbloqueia processo contador++

S N

criar_semaforo(n)

cria estrutura dados

contador ← n

Page 49: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão Mútua com Semáforossemaforo_t sem = 1;

int levantar_dinheiro (ref *conta, int valor)

{esperar(sem);if (conta->saldo >= valor) {

conta->saldo = conta->saldo – valor;} else valor = -1

assinalar(sem);return valor;

}

No início da secção crítica, todosos processos têm que chamaresperar()

No fim da secção crítica, todosos processos têm que chamarassinalar()

Um semáforo para exclusãomútua tem que ser inicializadocom 1 unidade

O semáforo é mais genérico que o trinco lógico, por isso pode ser usadopara garantir exclusão mútuaMas…

Mais ineficiente que o trinco lógicoO programador tem que garantir o uso simétrico de esperar() e assinalar()

Page 50: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco);assinalar(pode_prod);consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptrint buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

Page 51: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco);assinalar(pode_prod);consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptrint buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

Cada semáforo representa um recurso:•pode_produzir: espaços livres, inicialmente N•pode_consumir: itens no buffer, inicialmente 0

Espera que haja 1 item no buffer

Assinala que há 1 espaço livre no buffer

Espera que haja 1 espaço livre no buffer

Assinala que há 1 item no buffer

Page 52: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização GenéricaInclui

Secções críticasCooperação entre processos

Mecanismos de programaçãoTrincos Lógicos para as secções críticasSemáforos para a cooperação entre processos

Problemas de Sincronização:Produtor-ConsumidorLeitores-EscritoresJantar dos Filósofos

Page 53: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Metodologia de Resolução de Problemas de Sincronização

Cooperação entre processos1. Identificar os recursos (condições,

acontecimentos) partilhados entre processos2. Associar um semáforo a cada recurso

(condição, acontecimento)3. Inicializar o semáforo com o número de

recursos inicialmente existentes4. Chamar esperar(s) quando se tem que

garantir a existência do recurso associado ao semáforo s

5. Chamar assinalar(s) quando se produziu um recurso associado ao semáforo s

Page 54: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Metodologia de Resolução de Problemas de Sincronização

Gestão de recursossemGest = criar_semaforo(N);

void reservar_recurso(){esperar (semGest);algoritmo

}void libertar_recurso(){

algoritmoassinalar (semGest);

}

Page 55: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Metodologia de Resolução de Problemas de Sincronização

Assinalar acontecimentoProcisemEvent = criar_semaforo(0);void esperar_acontecimento(){

esperar (semEvent);}

Procjvoid assinalar_acontecimento(){

assinalar (semEvent);}

Page 56: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Metodologia de Resolução de Problemas de Sincronização

Secções Críticas1. Identificar as secções críticas

1. Uma secção crítica é uma secção de código onde se lê e/ou escreve uma ou mais variáveis partilhadas por vários processos

2. Associar um trinco lógico a cada uma delas1. A mesma variável partilhada tem que estar

protegida sempre pelo mesmo trinco2. Usam-se trincos diferentes para proteger variáveis

completamente independentes, que podem ser acedidas concorrentemente

3. Chamar fechar(t) no início e abrir(t) no fim de cada secção crítica

Page 57: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Metodologia de Resolução de Problemas de SincronizaçãoExclusão mútuatrinco_t trinco;fechar (trinco);

Secção criticaabrir (trinco);

Ou

mutex = criar_semaforo(1);esperar (mutex);

Secção criticaassinalar (mutex);

Page 58: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Aplicação da Metodologia ao Produtor-Consumidor

Cooperação entre processos1. Recursos: posições livres para os produtores produzirem;

itens no buffer para os consumidores consumirem2. Posições livres: semáforo pode_prod; Itens no buffer:

semáforo pode_cons3. Número inicial de posições livres: N; Número inicial de itens

no buffer: 04. Produtores: têm que garantir a existência de uma posição

livre antes de produzirem => têm que chamar esperar no semáforo correspondente (pode_prod); Consumidores: têm que garantir a existência de um item no buffer antes de o usarem => têm que chamar esperar no semáforo correspondente (pode_cons);

5. Produtores: produzem itens quando os colocam no buffer=> chamam assinalar no semáforo correspondente (pode_cons); Consumidores: produzem posições livres no buffer => chamam assinalar no semáforo correspondente (pode_prod)

Page 59: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Aplicação da Metodologia ao Produtor-Consumidor

Secções críticas1. Variáveis partilhadas pelos vários processos: buffer,

prodptr, consptr2. Proteger o acesso a essas variáveis com o trinco trinco3. Chamar fechar(trinco) antes de as ler ou escrever,

chamar abrir(trinco) depois de as ler ou escrever

Page 60: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco);assinalar(pode_prod);consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptrint buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

Cada semáforo representa um recurso:•pode_produzir: espaços livres, inicialmente N•pode_consumir: itens no buffer, inicialmente 0

Espera que haja 1 item no buffer

Assinala que há 1 espaço livre no buffer

Espera que haja 1 espaço livre no buffer

Assinala que há 1 item no buffer

Page 61: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos: erro comum #1

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;fechar(trinco);esperar(pode_cons);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco);assinalar(pode_prod);consome(item);

}}

int buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

Se não houver itens no buffer (situação inicial):• Consumidor fecha o trinco e bloqueia-se no semáforo (com o trinco fechado)• Outros consumidores bloqueiam-se no trinco

• Os produtores vão tentar produzir (e desbloquear os consumidores) mas encontramo trinco fechado e bloqueiam-se• Interblocagem: os consumidores estão àespera dos produtores, e vice-versa

Page 62: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

fechar (trinco)

fechar (trinco)

Processo 1

assinalar (sem)

esperar (sem)

Processo 2

abrir (trinco)

abrir (trinco)

.

.

.

.

.

.

.

.

.

.

Page 63: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

fechar (trinco)

fechar (trinco)

Processo 1

assinalar (sem)

esperar (sem)

Processo 2

abrir (trinco)

abrir (trinco)

Bloqueado

Bloqueado

Solução: Um processo não se pode bloquear num semáforo dentro de uma secção crítica

Chama esperar fora da secção crítica, ouLiberta a secção crítica, faz esperar e volta a readquirir a secção crítica

Page 64: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

esperar (semA)

esperar (semA)

Processo 1

esperar (semB)

esperar (semB)

Processo 2

assinalar (semA)assinalar (semB) assinalar (semA)

assinalar (semB)

.

.

.

.

.

.

.

.

.

Page 65: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

esperar (semA)

esperar (semA)

Processo 1

esperar (semB)

esperar (semB)

Processo 2

assinalar (semA)assinalar (semB) assinalar (semA)

assinalar (semB)

Expira o quantum do processo

Bloqueado

Bloqueado

Solução: quando um processo precisa de adquirir vários semáforos outrincos, eles têm que ser adquiridos sempre pela mesma ordem

Page 66: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos: erro comum #2

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco);item = buf[consptr]; consptr = (consptr+1) % N; assinalar(pode_prod);abrir(trinco);consome(item);

}}

int buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

O consumidor assinala que há espaço paraproduzir antes de libertar o trinco

• O produtor vai tentar produzir mas encontra o trinco fechado e bloqueia-se• De seguida executa-se o consumidor que liberta o trinco• Agora o produtor já se pode executar• Não há interblocagem mas existem 2 comutações de processosdesnecessárias

Page 67: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos: versão optimizada

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco_prods);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco_prods);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco_cons);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco_cons);assinalar(pode_prod);consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptrint buf[N]; int prodptr=0, consptr=0;trinco_t trinco_prods, trinco_cons;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

•Consumidores e produtores têm secçõescríticas diferentes pois não partilham variáveis•Permite produzir e consumir ao mesmo tempo em partes diferentes do buffer

Page 68: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Problemas de Sincronização

Produtor-ConsumidorLeitores-EscritoresJantar dos Filósofos

Page 69: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Produtor-Consumidor com Semáforos

produtor() {

while(TRUE) {int item = produz();esperar(pode_prod);fechar(trinco);buf[prodptr] = item; prodptr = (prodptr+1) % N;abrir(trinco);assinalar(pode_cons);

}}

consumidor() {

while(TRUE) {int item;esperar(pode_cons);fechar(trinco);item = buf[consptr]; consptr = (consptr+1) % N; abrir(trinco);assinalar(pode_prod);consome(item);

}}

Produtor

Produtor

Consumidor

Consumidor

prodptrconsptrint buf[N]; int prodptr=0, consptr=0;trinco_t trinco;semaforo_t pode_prod = criar_semaforo(N),

pode_cons = criar_semaforo(0);

Page 70: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Leitores-Escritores com Semáforos

ProblemaPretende-se gerir o acesso a uma estrutura de dados partilhada em que existem duas classes de processos:• Leitores – apenas lêem a estrutura de dados• Escritores – lêem e modificam a estrutura de dados

Condições• Os escritores só podem aceder em exclusão mútua• Os leitores podem aceder simultaneamente com

outro leitores mas em exclusão mútua com os escritores

• Nenhuma das classes de processos deve ficar àmingua

Page 71: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Leitores-Escritores com Semáforos

inicia_leitura(){

fechar(m);if (em_escrita || escritores_espera > 0) {

leitores_espera++;abrir(m);esperar(leitores);fechar(m);leitores_espera--;if (leitores_espera > 0)

assinalar(leitores);}

nleitores++;abrir(m);

}acaba_leitura(){

fechar(m);nleitores--;if (nleitores == 0 && escritores_espera > 0)

assinalar(escritores);abrir(m);

}

int nleitores=0;boolean_t em_escrita=FALSE;int leitores_espera=0, escritores_espera=0;

inicia_escrita(){

fechar(m);if (em_escrita || nleitores > 0) {

escritores_espera++;abrir(m);esperar(escritores);fechar(m);escritores_espera--;

}em_escrita = TRUE;abrir(m);

}acaba_escrita(){

fechar(m);em_escrita = FALSE; if (leitores_espera > 0)

assinalar(leitores);else if (escritores_espera > 0)

assinalar(escritores);abrir(m);

}

semaforo_t leitores=0, escritores=0;trinco_t m;

Page 72: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos

Cinco Filósofos estão reunidos para filosofar e jantar spaghetti. Para comer precisam de dois garfos, mas a mesa apenas tem um garfo por pessoa.

Condições:• Os filósofos podem estar em um de três estados :

Pensar; Decidir comer ; Comer.• O lugar de cada filósofo é fixo.• Um filósofo apenas pode utilizar os garfos

imediatamente à sua esquerda e direita.

Page 73: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos

Page 74: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos com Semáforos, versão #1

INCORRECTA, pode conduzir a interblocagem

semaforo_t garfo[5] = {1, 1, 1, 1, 1};

filosofo(int id){

while (TRUE) {pensar();esperar(garfo[id]);esperar(garfo[(id+1)%5]);comer();assinalar(garfo[id]);assinalar(garfo[(id+1)%5]);

}}

Page 75: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

InterblocagemEsta solução pode conduzir a interblocagem

Filósofo 0 adquire garfo 0 e perde o processador (expira o seu quantum ou háum processo mais prioritário para se executar)Filósofo 1 adquire o garfo 1 e perde o processador (idem)Filósofo 2 adquire o garfo 2 e perde o processador (idem)Filósofo 3 adquire o garfo 3 e perde o processador (idem)Filósofo 4 adquire o garfo 4, tenta adquirir o garfo 1 e bloqueia-se (estáadquirido pelo filósofo 1)Filósofos 0, 1, 2 e 3 voltam a executar-se e ficam bloqueados à espera, respectivamente, dos garfos 1, 2, 3 e 4

Interblocagem: os processos estão todos à espera uns dos outros e nunca sairão dessa situação

Existe uma cadeia circular de processos na qual cada processo possui um ou mais recursos que são pretendidos pelo processo seguinte na cadeia

Razão: Os processos necessitam de adquirir vários semáforos, mas eles não foram adquiridos sempre mesma ordem

Filósofo 0: esperar(0), esperar(1)Filósofo 4: esperar(4), esperar(0)

Page 76: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos com Semáforos, versão #2

Adquirir os semáforos sempre pela mesma ordem (ordemcrescente de número de semáforo)

semaforo_t garfo[5] = {1, 1, 1, 1, 1};semaforo_t sala = 4;

filosofo(int id){

while (TRUE) {pensar();if (i == 4) {

esperar(garfo[(id+1)%5]);esperar(garfo[id]);

} else {esperar(garfo[id]);esperar(garfo[(id+1)%5]);

}comer();assinalar(garfo[id]);assinalar(garfo[(id+1)%5]);

}}

Page 77: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos com Semáforos, versão #3

Usar um semáforo para representar a condição de bloqueio (e não o estado dos garfos/filósofos), Representar o estado dos garfos/filósofos com variáveis acedidas numa secçãocrítica

#define PENSAR 0

#define FOME 1

#define COMER 2

#define N 5

int estado[N] = {0, 0, 0, 0, 0};

semaforo_t semfilo[N] = {0, 0, 0, 0, 0};

trinco mutex;

Testa(int k){

if (estado[k] == FOME &&

estado[(k+1)%N] != COMER &&

estado[(k-1)%N] != COMER){

estado[k] = COMER;

assinalar(semfilo[K]);

}

}

filosofo(int id)

{while (TRUE) {

pensar();

fechar(mutex);

estado[id] = FOME;

Testa(id);

abrir(mutex);

esperar(semfilo[id]);

comer();

fechar(mutex);

estado[id] = PENSAR;

Testa((id-1+N)%N);

Testa((id+1)%N);

abrir(mutex);

}

}

Page 78: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Jantar dos Filósofos com Semáforos, versão #4

Limitar o acesso à “sala” a N-1 filósofos (fica sempre pelo menos1 garfo livre)

semaforo_t garfo[5] = {1, 1, 1, 1, 1};semaforo_t sala = 4;

filosofo(int id){

while (TRUE) {pensar();esperar(sala);esperar(garfo[id]);esperar(garfo[(id+1)%5]);comer();assinalar(garfo[id]);assinalar(garfo[(id+1)%5]);assinalar(sala);

}}

Page 79: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Implementação do TrincoLógico no SO

Pode ser chamada pelos programasutilizador através das chamadas sistemasfechar() e abrir()Também usada para sincronizaçãointerna do SOTrês técnicas de implementação:

Inibição de interrupções e bloqueio de processosExchange e bloqueio de processosExchange e espera activa

Page 80: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Implementação do trinco lógico no SO

Inibição de interrupções e bloqueio de processos

void fechar (trinco_t t){

int m = mascara_int();if (t == FECHADO)bloqueia processo

t = FECHADO;repoe_int(m);

}

void abrir (trinco_t t){

int m = mascara_int();t = ABERTO;if (processos bloqueados em t) {desbloqueia um processo

}repoe_int(m);

}

trinco_t t = ABERTO;

• Inibição das interrupções garante exclusão mútua• Processo é bloqueado no trinco, passando ao estado “bloqueado”• É muito eficiente em uniprocessadores, mas não funciona em multiprocessadores

Page 81: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Implementação do trinco lógico no SO

Exchange e bloqueio de processos

void fechar (trinco_t t){

int m = FECHADO;while (exchange(t,m) == FECHADO) {bloqueia_processo(t);m = FECHADO;

}}

void abrir (trinco_t t){

t = ABERTO;desbloqueia_processos(t);

}

trinco_t t = ABERTO;

• Instrução exchange(t,m) obtém o estado do trinco e fecha-o atomicamente• Se o trinco estava aberto, fica fechado e rotina termina• Se o trinco estava fechado, o sistema bloqueia o processo

Page 82: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Implementação do trinco lógico no SO (apenas para uso interno do SO)

Exchange e Espera Activa

void so_fechar (trinco_t t){

int m = FECHADO;while (exchange(t,m) == FECHADO);

}

void so_abrir (trinco_t t){

t = ABERTO;}

so_trinco_t t = ABERTO;

•Instrução exchange(t,m) obtém o estadodo trinco e fecha-o atomicamente•Espera activa só é possível se for usadaapenas para sincronização interna do sistemaoperativo•Eficiente em secções críticas pequenas (4-5 instruções C)•Instruções load linked – store conditionalpodem ser usadas em vez do exchange

•Para abrir o trinco, basta posicionar a variável•Os processos bloqueados estão em esperaactiva e vão imediatamente ver que o trincojá está aberto

Page 83: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Implementação do trinco lógico no SO

Optimização: exchange em modoutilizador

void fechar (trinco_t t){

int m = FECHADO;if (exchange(t,m) == ABERTO)return;

_fechar(t);}

void abrir (trinco_t t){

_abrir(t);}

trinco_t t = ABERTO;

• Rotinas fechar() e abrir() são bibliotecas em modoutilizador, _fechar() e _abrir() as chamadas sistemasapresentadas anteriormente• fechar() tenta fechar o trinco em modo utilizador com exchange. Se conseguir porque o trinco estava aberto, émuito eficiente (1 instrução máquina).• Se o trinco estiver fechado, efectua a chamada sistema_fechar()

• Para abrir o trinco, efectua a chamadasistema _abrir() para desbloquear osprocessos que estejam bloqueados

Page 84: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Exclusão mútua emmultiprocessadores modernos:load linked – store conditional (R4600)

int trinco = FALSE; fechar() {

li R1, trincol1: ll R2, 0(R1)

bnez R2, l1 li R2, #1sc R2, 0(R1)beqz R2, l1

}abrir(){

trinco = FALSE;}

As instruções exchange e test-and-set não são adequadas aosmultiprocessadores modernos:

•Deixam o bus trancado durante os dois acessos àmemória (load e store), que significam muitas dezenas de instruções•Não se adequam à estrutura de pipeline dos processadores RISC•Ocupam o bus na espera activa, impedindo que o processador que a obteve execute a secção crítica e a liberte

Solução: load linked, store conditional•Em conjunto, funcionam como um “exchange” com controlo de concorrência optimista•Load linked

•Faz um load•Inicia o snoop ao bus, detectando acessos ao endereço do load

•Store conditional•Se não houve acessos ao endereço do load, faz um store normal•Se houve, falha

•Se o conjunto load linked – store conditional falhar, terá que ser repetido até funcionar

Page 85: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização em Windows

Secções críticas em WindowsProdutor – consumidor em Windows

Page 86: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização em WindowsModo utilizador

InterlockedLONG InterlockedExchangeAdd(PLONG plAddend, LONG lIncrement);LONG InterlockedExchange(PLONG plTarget, LONG lValue); PVOID InterlockedExchangePointer(PVOID* ppvTarget, PVOID pvValue);

// Secção crítica com InterlockedExchangeBOOL g_trinco = FALSE;void levantar_dinheiro (ref *conta, int valor){

while (InterlockedExchange (&g_trinco, TRUE) == TRUE)Sleep(0);

if (conta->saldo >= valor) {conta->saldo = conta->saldo – valor;

} else valor = -1

InterlockedExchange(&g_trinco, FALSE);

return valor;}

Page 87: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização em WindowsModo utilizador – threads do mesmoprocesso

Critical SectionVOID InitializeCriticalSection(PCRITICAL_SECTION trinco); VOID DeleteCriticalSection(PCRITICAL_SECTION trinco); VOID EnterCriticalSection(PCRITICAL_SECTION trinco);VOID LeaveCriticalSection(PCRITICAL_SECTION trinco);BOOL TryEnterCriticalSection(PCRITICAL_SECTION trinco);

// Secção crítica com CRITICAL_SECTIONCRITICAL_SECTION trinco;void levantar_dinheiro (ref *conta, int valor){

EnterCriticalSection(trinco);

if (conta->saldo >= valor) {conta->saldo = conta->saldo – valor;

} else valor = -1

LeaveCriticalSection(trinco);

return valor;}

Page 88: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização em WindowsModo núcleo

WaitFor objectDWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds); DWORD WaitForMultipleObjects(DWORD dwCount, CONST HANDLE* phObjects,

BOOL fWaitAll, DWORD dwMilliseconds);

MutexHANDLE CreateMutex(PSECURITY_ATTRIBUTES psa, BOOL fInitialOwner, PCTSTR pszName);HANDLE OpenMutex(DWORD fdwAccess, BOOL bInheritHandle, PCTSTR pszName);BOOL ReleaseMutex(HANDLE hMutex);

SemaphoreHANDLE CreateSemaphore(PSECURITY_ATTRIBUTE psa,

LONG lInitialCount, LONG lMaximumCount, PCTSTR pszName);HANDLE OpenSemaphore(DWORD fdwAccess, BOOL bInheritHandle, PCTSTR pszName);BOOL ReleaseSemaphore(HANDLE hsem, LONG lReleaseCount, PLONG plPreviousCount);

Page 89: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

DeleteCriticalSection(&cs);CloseHandle(hmtx);

--Pode ser misturada com outrosobjectos núcleo

Outros

LeaveCriticalSection(&cs);ReleaseMutex(hmtx);Notify

TryEnterCriticalSection(&cs);

WaitForSingleObject (hmtx, 0);

Wait condicional

--WaitForSingleObject (hmtx, dwMilliseconds);

Wait com timeout

EnterCriticalSection(&cs);WaitForSingleObject (hmtx, INFINITE);

Wait

InitializeCriticalSection(&cs);

hmtx= CreateMutex (NULL, FALSE, NULL);

Inicialização

CRITICAL_SECTION m;HANDLE m;Declaração

Threads do mesmo processoThreads de qualquer processoÂmbito

Eficiente (modo utilizador)Ineficiente (modo núcleo)Performance

Critical SectionMutex

Page 90: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Sincronização em Linux

Secções críticas em LinuxProdutor – consumidor em Linux

Page 91: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

pthreads#include <thread.h>

int thr_create(void * stack_base, size_t stack_size, void *(*start_routine)(void *)void * arg, long flags, thread_t * new_thread);

size_t thr_min_stack(void);int thr_join(thread_t wait_for, thread_t *departed,

void **status);

thread_t thr_self(void);void thr_yield(void);

int thr_suspend(thread_t target_thread);int thr_continue(thread_t target_thread);void thr_exit(void *status);int thr_kill(thread_t target_thread, int sig);

int thr_setconcurrency(int new_level);int thr_getconcurrency(void);int thr_setprio(thread_t target_thread, int pri);int thr_getprio(thread_t target_thread, int *pri);

int thr_keycreate(thread_key_t *keyp, void (*destructor)(void *value));

int thr_setspecific(thread_key_t key, void *value);int thr_getspecific(thread_key_t key, void **valuep);

Page 92: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Mutexes

#include <synch.h>

int mutex_init(mutex_t *mp, int type, void * arg);

int mutex_destroy(mutex_t *mp);int mutex_lock(mutex_t *mp);int mutex_trylock(mutex_t *mp);int mutex_unlock(mutex_t *mp);

Page 93: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Read-Write Locks

int rwlock_init(rwlock_t *rwlp, inttype, void * arg);

int rwlock_destroy(rwlock_t *rwlp);int rw_rdlock(rwlock_t *rwlp);int rw_wrlock(rwlock_t *rwlp);int rw_unlock(rwlock_t *rwlp);int rw_tryrdlock(rwlock_t *rwlp);int rw_trywrlock(rwlock_t *rwlp);

Page 94: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Semaphores

#include <synch.h>

int sema_init(sema_t *sp, unsignedint count, int type, void * arg);

int sema_destroy(sema_t *sp);int sema_wait(sema_t *sp);int sema_trywait(sema_t *sp);int sema_post(sema_t *sp);

Page 95: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Semáforos (Sistema V)

Page 96: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

IPC no SV - Semáforosum semáforo consiste num conjunto de contadores que sópodem ter valores positivoscriação de um semáforo:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget (key, nsems, semflg)key_t key;int nsems, semflg;

“nsems” especifica o número de contadores, que são inicializados a zero na criaçãooperações sobre semáforos:

int semop (semid, sops, nsops)int semid;struct sembuf (*sops)[ ];int nsops;

são executadas as nsops operações definidas em sops e devolvido o valor do último contador acedidouma operação é definida, de acordo com a estrutura sembuf, por:

short sem_num; /* numero */short sem_op; /* operação */short sem_flag; /* flags */

segundo o valor de sem_op temos:sem_op > 0 o valor de sem_op é adicionado ao do contadorsem_op < 0 o valor de sem_op é adicionado ao do contador; o processo pode ficar bloqueadosem_op = 0 o processo é suspenso até o valor do contador atingir zero

Page 97: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Semáforos - Controlosintaxe:int semctl (semid,

semnum, cmd, arg)int semid, semnum, cmd;union semun {

int val;struct semid_ds *buf;ushort *array;

} arg;

comandos possíveis:IPC_STAT preenche arg.buf com estado actualIPC_SET inicializa parâmetros a partir de buf.argIPC_RMID elimina o semáforo em causaGETALL copia os valores dos contadores para arg.arraySETALL inicializa os valores a partir de arg.array

comandos possíveis com semnum especificado:GETVAL devolve o valor do contadorSETVAL inicializa o valor do contadorGETPID devolve o pid da última operaçãoGETNCNT devolve o número de processos aguardando um valor não zero do contadorGETZCNT devolve número de processos aguardando um valor zero do contador

Page 98: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

#define SEMMUTEX 5#define SEMALOC 6int mutex, semaloc;

void IniSem(int nmax) { union semun {

int val;struct semid_ds *buf;ushort *array;} init;

if ((mutex = semget (SEMMUTEX, 1,0777|IPC_CREAT)) < 0) erro ("semgetSEMMUTEX");if ((semaloc = semget (SEMALOC, 1, 0777|IPC_CREAT)) < 0) erro("semgetSEMALOC");

init.val = 1;if (semctl (mutex, 0, SETVAL, init) < 0) erro("semctl mutex");

init.val = nmax;if (semctl (semaloc, 0, SETVAL, init) < 0) erro("semctl SemAloc");

}

Distribuidor de Memória

Page 99: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Distribuidor de Memória (cont.)

void Esperar (key_t semid, int semnum, int uni) {struct sembuf s;

s.sem_num = semnum;s.sem_op = -uni;s.sem_flg = 0;if (semop (semid, &s, 1) < 0) erro ("semopEsperar");

}

void Assinalar (key_t semid, int semnum, int uni) {struct sembuf s;

s.sem_num = semnum;s.sem_op = uni;s.sem_flg = 0;if (semop (semid, &s, 1) < 0) erro ("semopAssinalar");

}

void EsperarMutex (key_t semid, int semnum) {struct sembuf s;

s.sem_num = semnum;s.sem_op = -1;s.sem_flg = SEM_UNDO;if (semop (semid, &s, 1) < 0) erro ("semopEsperarMutex");

}

void AssinalarMutex (key_t semid, int semnum) {struct sembuf s;

s.sem_num = semnum;s.sem_op = 1;s.sem_flg = SEM_UNDO;if (semop (semid, &s, 1) < 0) erro ("semopAssinalarMutex");

}

Page 100: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

Soluções preventivas -procuram evitarsituações de interblocagem

Garantir que os recursos são adquiridos todos pela mesma ordemRequisitar todos os recursos que o processo necessita no início da sua execuçãoQuando a aquisição de um recurso não épossível liberta todos os recursos detidos.

Page 101: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Interblocagem

Soluções de Detecção de Interblocagemdetecção de um estado de interblocagem e tentativa de resolução por libertação forçada de recursos

Soluções de Eliminação do Estado de Interblocagem

o algoritmo analisa a evolução do conjunto de recursos que os processos possuem e procura evitar o aparecimento de um estado de interblocagem

Page 102: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Mecanismos Directos de Sincronização

ObjectivoSuspender temporariamente a execução de subprocessos

Limitações:A sincronização directa implica o conhecimento do identificador do processo sobre o qual se pretende actuar. Não se pode dar aos programas dos utilizadores a possibilidade de interferirem com outros utilizadores A restrição habitual é apenas permitir o uso de sincronização directa entre processos do mesmo utilizador

Page 103: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Mecanismos Directos de Sincronização

Funções que actuam directamente sobre o estado dos processos

Suspender (IdProcesso)Acordar (IdProcesso)

A função de suspensão é também frequentemente utilizada para implementar mecanismos de atraso temporizado que funcionam como uma auto suspensão

Adormecer (Período)

Page 104: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Diagrama de Estadodos Processos

Em Execução

Executável Bloqueado Suspenso

SuspenderSeleccionado pelo

Despacho

Preempção

Desbloquear

Acordar

Acordar

Suspender

Suspender

Page 105: Sincronização - fenix.tecnico.ulisboa.pt · Não pode haver interblocagem (deadlock). Se alguns processos estão a tentar entrar na região crítica, então pelo menos um deles

Modelo Computacional (resumo)

Trincoscriar_trinco

abrirfechar

Semáforoscriar_semáforoeliminar_semáforo

esperarassinalar

Sincronização Directasuspenderacordar

adormecer