Concorrência:
Sincronização de fina granularidade
André Santos
CIn-UFPE
©André Santos, 1998-2000
Busy Waiting
Tipo de sincronização em que um
processo continuamente verifica uma
condição até que ela se torne
verdadeira
Pode ser implementada com o conjunto
de instruções de qualquer processador
moderno
Ineficiente para multiprogramação
©André Santos,
1998-2000
Busy waiting
Utilizado em dispositivos de hardware
multiprocessados
Pode ser usado para implementar
await
©André Santos,
1998-2000
O Problema da Exclusão
Mútua (Região Crítica)
N processos executam um loop infinito:
Seção crítica
Seção não crítica
O programa deve satisfazer a
propriedade de exclusão mútua
instruções das regiões críticas de dois ou
mais processos não podem ser
executadas ao mesmo tempo.
©André Santos,
1998-2000
Exclusão Mútua para N
processos
N processos executando loop infinito
Seção crítica
Seção não crítica
Programa deve satisfazer a propriedade
de exclusão mútua
Em um dado instante no máximo um
processo está executando sua região
crítica.
©André Santos,
1998-2000
solução: instruções adicionais
protocolo de entrada e de saída
P[i: 1..n]:: while (TRUE) {
entry protocol
critical section
exit protocol
non-critical section
}
©André Santos,
1998-2000
outras condições
um processo pode parar ou terminar
fora da região crítica, sem interferir com
outros processos.
Ausência de deadlock (ou livelock)
se dois ou mais processos tentam entrar
em sua região crítica, um deles deve
conseguir.
©André Santos,
1998-2000
Outras condições
Ausência de espera desnecessária
Se um processo quer entrar em sua região
crítica e os outros processos estão fora da
sua região crítica ou terminaram, ele não
será impedido de entrar
Entrada eventual (ausência de
starvation)
se um processo quer entrar na região
crítica, em algum momento ele entrará.
©André Santos,
1998-2000
Tentativa 1: variável Turn
int Turn = 1;
void P1() {
void P2() {
while (TRUE) {
while (TRUE) {
/* Non_Cr_S_1 */
/* Non_Cr_S_2 */
while (Turn != 1) {}; while (Turn != 2) {};
/* Crit_S_1 */
/* Crit_S_2 */
Turn = 2;
Turn = 1;
}
}
}
}
©André Santos,
1998-2000
Verificação da solução
A solução satisfaz o requisito de
exclusão mútua
assuma que ela não satisfaz
contradição
A solução não entra em deadlock
assuma que o programa está em deadlock
contradição
©André Santos,
1998-2000
Verificação da solução
Não há starvation
ao sair da região crítica cada processo
passa a vez ao outro
©André Santos,
1998-2000
Verificação da solução
A solução pode falhar se um processo
parar fora da região crítica
se um processo pára em sua região não
crítica, o outro não pode prosseguir.
Corrotinas
Execução “sincronizada”
©André Santos,
1998-2000
Tentativa 2: 2 variáveis
int In1, In2 = FALSE;
void P1 () {
void P2 () {
while (TRUE)
while (TRUE)
{ Non_Cr_S_1;
{ Non_Cr_S_2;
while (In2) {};
while (In1) {};
In1 = TRUE;
In2 = TRUE;
Crit_S_1;
Crit_S_2;
In1 = FALSE;
In2 = FALSE;
}
}
}
}
©André Santos,
1998-2000
Verificação da solução
P1 e P2 podem entrar na seção crítica
simultaneamente
P1 verifica In2 e encontra In2 = FALSE
P2 verifica In1 e encontra In1 = FALSE
P1 seta In1 para TRUE
P2 seta In2 para TRUE
P1 entra na seção crítica
P2 entra na seção crítica
©André Santos,
1998-2000
Tentativa 3:
Int In1, In2 = FALSE;
void P1 () {
void P2() {
while (TRUE)
while (TRUE)
{ Non_Cr_S_1;
{ Non_Cr_S_2;
In1 = TRUE;
In2 = TRUE;
while (In2) {};
while (In1) {};
Crit_S_1;
Crit_S_2;
In1 = FALSE;
In2 = FALSE;
}
}
}
}
©André Santos,
1998-2000
Verificação da solução
A solução satisfaz a propriedade de
exclusão mútua
©André Santos,
1998-2000
Verificação da solução
A solução pode entrar em deadlock
P1 atribui TRUE a In1
P2 atribui TRUE a In2
P1 testa In2 e fica no loop
P2 testa In1 e fica no loop
©André Santos,
1998-2000
Tentativa 4: passando a vez
Int In1, In2 = 1;
void P1 () {
while (TRUE)
{ Non_Cr_S_1;
In1 = TRUE;
while (In2)
{ In1 = FALSE;
In1 = TRUE;
};
Crit_S_1;
In1 = FALSE;
}
}
void P2 () {
while (TRUE)
{ Non_Cr_S_2;
In2 = TRUE;
while (In1)
{ In2 = FALSE;
In2 = TRUE;
};
Crit_S_2;
In2 = FALSE;
}
}
©André Santos,
1998-2000
Verificação da solução
Um processo pode ser starved
P1 seta In1 para TRUE
P2 seta In2 para TRUE
P2 verifica In1 e seta In2 para FALSE
P1 faz um ciclo completo: verifica In2,
entra na região crítica, seta In1 para
FALSE, executa região não-crítica, seta
In1 para TRUE
P2 seta In2 para TRUE...
©André Santos,
1998-2000
Verificação da solução
A solução pode entrar em livelock
deadlock: nenhuma sequência resulta
em sucesso
livelock: existe uma ou mais sequências
que evita que os processos entrem na
região crítica
©André Santos,
1998-2000
Entretanto...
É possível inserir um delay entre as
mudanças nas variáveis, para aumentar
a possibilidade de context-switch
ocorrer com variável alterada.
Uso prático: algorítimo semelhante é
usado em redes Ethernet
©André Santos,
1998-2000
Solução Ideal 1
int In1, In2 = FALSE;
void P1 () {
void P2 () {
while (TRUE)
while (TRUE)
{ Non_Cr_S_1;
{ Non_Cr_S_2;
<await not In2 ->
<await not In1 ->
In1 = TRUE;>
In2 = TRUE;>
Crit_S_1;
Crit_S_2;
In1 = FALSE;
In2 = FALSE;
}
}
}
}
©André Santos,
1998-2000
Solução Ideal 2
int lock = FALSE;
void P1 () {
void P2 () {
while (TRUE)
while (TRUE)
{ Non_Cr_S_1;
{ Non_Cr_S_2;
<await not lock ->
<await not Iock ->
lock = TRUE;>
Iock = TRUE;>
Crit_S_1;
Crit_S_2;
lock = FALSE;
lock = FALSE;
}
}
}
}
©André Santos,
1998-2000
Exclusão mútua assistida por
hardware
load e store em uma única instrução
test e set:
TS(lock, cc) = <cc := lock; lock := true>
Exchange(A,B)
= <Temp := A; A := B; B := Temp;>
©André Santos,
1998-2000
Exclusão mútua com Test and Set
int lock = FALSE;
void P1 () {
int C1;
while (TRUE)
{ Non_Cr_S_1;
TS (lock,C1);
while (C1) {
TS (lock,C1);
};
Crit_S_1;
lock = FALSE;
}
}
void P2 () {
int C2;
while (TRUE)
{ Non_Cr_S_2;
TS (lock,C2);
while (C2) {
TS (lock,C2);
};
Crit_S_2;
lock = FALSE;
}
}
©André Santos,
1998-2000
Vantagens
Funciona facilmente para vários
processos.
©André Santos,
1998-2000
Desvantagens
Escrita frequente nas variáveis
Todos os processos acessam a mesma
variável lock.
©André Santos,
1998-2000
Exclusão mútua com Exchange
int InCS = FALSE;
void P1 () {
int L1 = TRUE;
while (TRUE)
{ Non_Cr_S_1;
Exchng (L1,InCS);
while (L1) {
Exchng (L1,InCS);
};
Crit_S_1;
Exchng (L1,InCS);
}
}
void P2 () {
int L2 = TRUE;
while (TRUE)
{ Non_Cr_S_2;
Exchng (L2,InCS);
while (L2) {
Exchng (L2,InCS);
};
Crit_S_2;
Exchng (L2,InCS);
}
}
©André Santos,
1998-2000