PROGRAMAÇÃO PARALELA E DISTRIBUÍDA - DAINF

Propaganda
PR
UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ
PROGRAMAÇÃO PARALELA E DISTRIBUÍDA
Fundamentos
Prof. Cesar Augusto Tacla
http://www.dainf.ct.utfpr.edu.br/~tacla
JAVAProgParSD/0030-ProgParalelaDistribuida.ppt
Sumário
1. Introdução
a.
b.
c.
d.
e.
f.
g.
Definição de sistemas paralelos e distribuídos
Conceitos: programa, processo e thread
Criação de threads
Yield, Sleep, Join
Prioridade entre threads
Compartilhamento de memória
Máquina de estados de uma thread
2. Problemas de concorrência
a. Race condition
b. Vivacidade (deadlock, livelock, starvation)
c. Soluções (mutex, semáforos, monitor)
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
2
REFERÊNCIAS BIBLIOGRÁFICAS
(Coulouris et al., 2003) George Coulouris, Jean Dollimore, Tim Kindberg.
Distributed Systems - Concepts and Design, Addison Wesley Publ.
Comp., 3a edição, 2003.
(Tanenbaum & Steen, 2002) Andrew S. Tanenbaum, Maarten van Steen.
Distributed Systems, Prentice-Hall International, 2002.
(Garg, 2004) Vijay K. Garg. Concurrent and Distributed Computing in
Java, Wiley Inter-Science, 2004, 309p.
(LEA, 200) Douglas Lea. Concurrent programming in Java: design
principles and patterns, 2nd ed. Reading: Addison-Wesley, c2000.
411 p. (Java series).
3
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Sumário
1a
Definição de sistemas paralelos e distribuídos
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
4
Sistema Paralelo
Múltiplos processadores conectados por uma memória compartilhada
Memória
Compartilhada
barramento
CPU
CPU
CPU
CPU
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
5
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Sistema Distribuído
Múltiplos processadores conectados por uma rede de comunicação
Troca de mensagens
Rede de
Comunicação
Segundo (Garg, 2004), são sistemas compostos por
múltiplos processadores conectados por uma rede de
comunicação, sendo a rede de comunicação uma LAN
(Ethernet) ou WAN (Internet). Neste tipo de sistema os
processadores se comunicam por troca de mensagens
(não por memória compartilhada)
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
6
Necessidades
◊ Sistemas paralelos e distribuídos
Necessitam de ferramentas e técnicas
Distintas das utilizadas em software sequencial
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
7
Distribuído x Paralelo (1)
◊ Em relação ao hardware,
Se pensarmos em desempenho, é melhor termos sistemas
distribuídos ou paralelos?
R: combinação
Computadores multiprocessados conectados por uma rede
Rede de
Comunicação
Memória
Compartilhada
CPU
CPU
CPU
CPU
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
8
Distribuído x Paralelo (2)
◊ Por que não sistemas completamente paralelos?
Escalabilidade
Modularidade e heterogeneidade
Compartilhamento de dados
Compartilhamento de recursos
Estrutura distribuída por si
Confiabilidade
Baixo custo
9
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Distribuído x Paralelo (3)
◊ Por que não sistemas completamente distribuídos?
Melhor desempenho no processamento local
É mais rápido atualizar uma memória local do que enviar uma
mensagem para outro processador, especialmente quando o valor
de uma variável deve ser comunicado para vários processadores
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
10
Distribuído x Paralelo (4)
◊ Em relação ao software (API programação),
Pode ser independente do hardware?
◊ Na realidade, reflete a estrutura de hardware
Modelo de objetos distribuídos (ex. RMI) tem-se
Processos que se comunicam por mensagens
Processos que podem ter várias threads
Threads que se comunicam por memória compartilhada
Rede de
Comunicação
Memória
Compartilhada
CPU
CPU
CPU
CPU
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
MEM
LOCAL
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
11
Sumário
1b
Conceitos: programa, processo e thread
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
12
Programa, processo, thread
◊ Programa conjunto de instruções numa linguagem de alto nível ou
de máquina
◊ Processo resulta da execução do programa, tem um ambiente de
execução autocontido e privado.
O que o usuário enxerga como aplicação ou sistema, normalmente é
composto por vários processos
Sequencial = 1 processo
Concorrente = vários processos
Processo 1
programa
execução
Processo 2
Processo n
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
13
Programa, processo, thread
◊ Thread são chamadas de processos peso-pena
◊ Tanto threads como processos provêm um ambiente de
execução ou contexto de execução
◊ Toda aplicação possui pelo menos uma thread main
◊ Threads compartilham o mesmo "espaço de
endereçamento“ (memória)
◊ É mais rápido chavear a execução entre threads do que
entre processos.
◊ Threads compartilham recursos do processo: memória e
arquivos abertos.
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
14
Programa, processo e thread
◊ Uma thread recebe recursos próprios durante a execução:
uma pilha (stack) de execução para poder chamar métodos,
passar parâmetros, alocar variáveis locais
um "Program Counter"
Estes elementos formam o contexto de execução da thread
15
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Programa, processo, thread
Stack: armazena o estado de
cada invocação de método:
variáveis locais, argumentos,
retorno e dispatch de
exceções. São vários frames
empilhados stack overflow
Heap: armazena instâncias de
objetos criadas em tempo de
execução. Também armazena
arrays OutOfMemoryError
Processos que compartilham código e
dados são chamados de threads, são
também chamados de processos lightweight
Program Counter Register
PCR
PCR
PCR
Stack
Thread 1
Stack
Thread 2
Stack
Thread 3
Contexto de
execução de uma
thread
heap
Method area
Compartilhado
pelas threads
Method area: informações da classe (nome,
modificadores), superclasse, atributos e seus
modificadores, atributos estáticos com valores,
métodos e seus modificadores, bytecodes
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
16
Exemplos de threads
◊Threads – demos
Links na página do curso
http://www.doc.ic.ac.uk/~jnm/concurrency/classes/ThreadDemo/ThreadDemo.html
http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/threads/threads1.html
observar como uma applet é incorporada a uma página WEB
<applet codebase="Sort/" code="SortItem.class" width="300" height="300">
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
17
Sumário
1c
Criação de Processos/Threads
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
18
UNIX, C++
◊ Criação de processos
Processo pai
programa
pid = fork();
if (pid == 0) {
cout << “processo filho”;
else
cout << “processo pai”;
pid = fork();
if (pid == 0) {
cout << “processo filho”;
else
cout << “processo pai”;
Processo filho
pid = fork();
if (pid == 0) {
cout << “processo filho”;
else
cout << “processo pai”;
19
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Criação de threads em Java
◊ Há 2 métodos
Extends Thread
Implements Runnable
Thread
Runnable
<<realizes>>
MinhaThread
+run():void
MinhaThread
+run():void
Possibilita estender outra classe
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
20
Criação de threads em Java
◊ Exemplo de criação de Thread por extends
Diagrama de sequência em UML
public class MinhaThread extends Thread {
public void run() {
System.out.println(“Ola!!!!”);
}
}
:Main
new
:MinhaThread
start()
run()
public class Main {
public static void main(String[] args) {
MinhaThread t = new MinhaThread();
t.start();
}
}
21
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Criação de threads em Java
◊ Exemplo de criação de Thread por implements
public class MinhaThread implements Runnable {
public void run() {
System.out.println(“Ola!!!!”);
}
}
public class Main {
public static void main(String[] args) {
MinhaThread t = new MinhaThread();
Thread t2 = new Thread(t);
t2.start();
}
}
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
:Main
new
:MinhaThread
start()
run()
22
Criação de threads em Java
◊ Exemplo básico: threads contadoras
Código fonte e .jar disponível em
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JThreadContadoras
Duas threads são criadas, cada uma conta até
1.000. Os resultados podem aparecer intercalados.
Para compilar e executar
Ir ao subdiretório src/jthread
Salvar o arquivo em Main.java <dir>/jthread/
Lance o shell: executar cmd
Posicione no diretório <dir>
Compile: javac jthread/Main.java
Execute: java -cp . jthread/Main
Para executar somente
Ir ao subdiretório dist
Salve o arquivo .jar em <dir>
Lance o shell: executar cmd
Posicione no diretório <dir>
Execute: java -jar JThreadContadoras.jar
JAVARepositorio\JThreads\JThreadContadoras
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
23
Criação de Threads em Java
◊Exemplo básico: threads contadoras
class MinhaThread implements Runnable {
public void run() {
// a interface Runnable exige a implementação do método run
String name = Thread.currentThread().getName();
System.out.println(name + " rodando");
for (int i=0;i < 1000; i++) {
System.out.println(name + ": " + i);
}
System.out.println(name + " FIM ***");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("INICIO DA THREAD MAIN ***");
Thread t1 = new Thread(new MinhaThread(), "thread 1");
Thread t2 = new Thread(new MinhaThread(), "\t\tthread 2");
t1.start();
t2.start();
}
}
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
24
Criação de Threads em Java
◊Exemplo básico: threads contadoras
Quem faz o chaveamento de contexto?
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
25
Criação de threads em Java
◊ Exercício 1: modifique o programa das threads contadoras
de forma a criá-las estendendo a classe Thread
class MinhaThread implements Runnable {
....
◊ Exercício 2: criar várias threads (> 4) e observar o
chaveamento de contexto.
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
26
Sumário
1d
Yield, Sleep e Join
27
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Java THREADS: YIELD
◊ YIELD
suspende a execução da thread atual
e permite que outra ocupe o
As flechas pontilhadas indicam swap.
processador.
O label das flechas indicam omotivo do swap:
Swap: escalonador do SO;
yield(): a chamada ao método causou a mudança.
:Main
new
t1:MinhaThread
new
start()
Início do run()
t2:MinhaThread
start()
swap
Início do run()
swap
yield()
yield()
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
28
Java THREADS: YIELD
◊ Exemplo de utilização de yield
class MinhaThread implements Runnable {
public void run() {
// a interface Runnable exige a implementação do método run
String name = Thread.currentThread().getName();
System.out.println(name + " rodando");
for (int i=0;i < 1000; i++) {
System.out.println(name + ": " + i);
// eh possivel passar o controle para outra thread implicitamente
Thread.yield();
}
System.out.println(name + " FIM ***");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("INICIO DA THREAD MAIN ***");
Thread t1 = new Thread(new MinhaThread(), "thread 1");
Thread t2 = new Thread(new MinhaThread(), "\t\tthread 2");
t1.start();
t2.start();
}
}
29
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
Java THREADS: YIELD
◊ Exercício: no exemplo das threads contadoras, habilite o
yield fazendo: java –jar JThreadContadoras.jar YIELD
Programação Paralela e Distribuída - Fundamentos/UTFPR Prof. Cesar Augusto Tacla
30
Java Threads: SLEEP
◊ Sleep: suspende a execução da thread por um período
Libera o processador para outras threads
Faz a thread dormir por milisegundos ou nanosegundos
Tempo de sleep não é preciso, depende do SO
No exemplo das threads contadoras, cada thread
dorme 2s a cada 3 contagens. Execute-o fazendo:
java –jar JThreadContadoras.jar NO 2000
if (i%3==0) {
try {
thread.sleep(2000); // dorme 2 seg
catch (InterruptedException e) {}
}
31
Java THREADS: SLEEP
◊ SLEEP
suspende a execução da thread atual por pelo menos x
milisegundos e permite que outra ocupe o processador.
:Main
new
t1:MinhaThread
new
start()
t2:MinhaThread
start()
Início do run()
swap
swap
Início do run()
sleep(2000)
Timed
waiting
swap
32
Java Threads: SLEEP
◊ Exercício [JAVA]: faça a simulação de um cruzamento
controlado por dois semáforos utilizando apenas sleep para
controlar os tempos de verde, amarelo e vermelho.
Observe que o sleep fará sinaleiros não sincronizados.
Para simplesmente executá-lo, ver próximo slide.
33
Sol. JAVARepositorio\JThreads\JCruzamento-v1
Java Threads: SLEEP
◊ Para executar o cruzamento fazer:
◊ Baixar o .jar de
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JCruzamento-v1/dist/
>java -jar JCruzamento.jar
Estado SEM1:VERMELHO
Estado SEM2:VERDE
Estado SEM1:VERDE
Estado SEM2:AMARELO
Estado SEM2:VERMELHO
Estado SEM1:AMARELO
Estado SEM2:VERDE
...
As linhas em destaque mostram que o semáforo SEM1
e o SEM2 ficaram verde ao mesmo tempo!!!
34
Java Threads: JOIN
◊ Thread.join(): permite que uma thread espere pelo
término de duas ou mais threads
:Main
new
t1:MinhaThread
new
start()
join (t1, t2)
t2:MinhaThread
start()
Início do run()
swap
waiting
Fim join (t1, t2)
swap
Início do run()
fim t1
fim t2
35
A thread main fica a espera de t1 e t2
Java Threads: JOIN
public static void main (String[] args) {
System.out.println("INICIO DA THREAD MAIN ***");
Thread t1 = new Thread(new MinhaThread(), "thread 1");
Thread t2 = new Thread(new MinhaThread(), "\t\tthread 2");
t1.start();
t2.start();
try {
t1.join(); // a thread main aguarda o término de t1
t2.join(); // a thread main aguarda o término de t2
} catch (InterruptedException e) {
System.out.println(“interrupcao");
}
System.out.println("*** As duas threads encerraram a
contagem ***");
// outras coisas da thread main
}
36
Java Threads: JOIN
◊ JOIN: “une” as execuções das threads
No exemplo das threads contadoras, para testar o
JOIN, faça:
java –jar JThreadContadoras.jar NO 2000 JOIN
37
Sumário
1e
Prioridade entre threads
38
Prioridade entre threads
◊ Qual thread é escolhida para rodar?
◊ Depende...
da implementação da JVM (Java Virtual Machine);
da prioridade da thread
da política/algoritmo de escalonamento do sistema operacional
(ex. round-robin = rodízio por fatia de tempo = quantum)
39
Prioridade entre threads
◊ Exemplo: escalonamento no Linux
[fonte http://www.inf.pucrs.br/~celso/SchedulerLinuxWindows.pdf]
Cada processo possui uma prioridade, recalculada dinamicamente.
O escalonador dá a CPU ao processo de maior prioridade
O escalonador é preemptivo
Para processos interativos (I/O bound) -> round-robin
Para processos tempo-real -> FCFS (first come, first served)
40
Prioridade entre Threads
◊ Windows (2000/NT/XP) – ESCALONAMENTO
[fonte http://www.inf.pucrs.br/~celso/SchedulerLinuxWindows.pdf]
No Windows 2000/XP o escalonador utiliza múltiplas filas e as threads
interativos (I/O bound) possuem prioridade sobre os CPU bound.
O escalonamento é baseado em prioridades. Cada thread possui uma
prioridade, que varia de 0 a 31 (0 é a menor e 31 a maior).
A prioridade 0 é atribuída a uma thread especial, chamada zero thread,
que é responsável por zerar as páginas livres no sistema. Somente esta
thread pode receber a prioridade 0.
As prioridades definem três classes de threads:
Real time: prioridades de 16 a 31;
Normal: prioridades de 0 a 15.
Existe ainda uma classe especial chamada idle, a de mais baixa
prioridade. Threads nesta classe somente executam quando não
existem outras threads aptas (portanto, threads dessa classe não
interferem na performance – não causam overhead).
41
Prioridade entre Threads
◊ Windows (2000/NT/XP) – ESCALONAMENTO
O escalonador escolhe sempre a thread de maior prioridade.
As threads da classe real time executam até terminar ou se bloquear
(FCFS).
As threads com prioridade normal (0 a 15) recebem fatias de tempo (RR).
no Windows 2000 professional, a fatia de tempo é de 20 ms (para
favorecer a interatividade).
no Windows 2000 Server, a fatia é de 120 ms (para gerar menos trocas
de contexto).
Cada thread recebe uma prioridade base ao ser criada. Para os processos
de tempo real (prioridade entre 16 e 31) esta prioridade não se altera.
Além disso, uma thread tem uma prioridade inicial que indica sua
prioridade relativa dentro do processo.
Threads com prioridade entre 0 e 15 têm a prioridade ajustada em tempo
de execução:
Preemptadas por operações de I/0 recebem um bônus de aumento,
que depende do periférico (ex. 1 para disco e 6 para teclado).
Preemptadas por esgotar o quantum: prioridade reduzida.
42
Prioridade entre threads
◊ Mapeamento de threads
Há de se considerar o mapeamento das threads da JVM para threads nativas do
sistema operacional. Por exemplo, a JavaHotSpot VM na Solaris mapeia uma thread
Java em uma thread nativa.
Maiores detalhes em http://java.sun.com/j2se/1.5.0/docs/guide/vm/thread-priorities.html
◊ As prioridades das Threads setadas no código Java são lógicas e dependem
da implementação da JVM:
public final void setPriority(int newPriority)
public final int getPriority()
MAX_PRIORITY = 10 constante inteira
MIN_PRIORITY = 1
constante inteira
NORM_PRIORITY = 5 prioridade atribuída por default
43
Prioridade entre threads
◊ Exercício: modificar a prioridade das threads contadoras e
observar efeito na execução. Os dois últimos parâmetros
modificam respectivamente as prioridades da thread 1 e 2.
Recorda-se que a prioridade deve estar no intervalo [1, 10]
No exemplo das threads contadoras, para testar o a
prioridade, faça:
java –jar JThreadContadoras.jar OFF 0 OFF 1 10
Prioridade thread 1
Prioridade thread 2
Código fonte e jar disponíveis em
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JThreadContadoras/
44
Prioridade entre threads
◊ Exercício: considere um simulador de corridas de fórmula
1 que simula uma disputa entre dois pilotos: Schumacker e
Barrichelo.
Cada carro funciona de forma independente
O tempo de cada volta é dado por um valor randômico. O
programa deve esperar por este tempo sem fazer nada para
então iniciar a próxima volta
Ao final da corrida (quando os dois carros completam 5 voltas), o
simulador mostra o tempo acumulado para cada um dos pilotos e
aponta o vencedor ou empate.
◊ Responda
Que comandos da linguagem Java você utilizaria para resolver
cada um dos itens acima?
JAVARepositorio\JThreads\JCarrosCorrida
45
Prioridade entre threads
◊ O código abaixo é uma solução do problema anterior. [JAVA] Altere o
programa atribuindo maior prioridade a uma das threads (Schumacker ou
Barrichelo). [TELEINFO] Execute o .jar for fun!
Código fonte e .jar disponíveis em
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JCarrosCorrida/
* No exemplo seguinte, simulamos dois carros de corrida: Schumacker e Barrichelo.
* Cada carro funciona de forma independente na sua thread e demora x milisegundos
* para percorrer um determinado trecho da pista (x é um valor aleatório).
* Para simular este tempo, utilizamos o método Sleep. Na thread Main aguardamos que
* os dois carros terminem a prova para encerrar a corrida. Isto é feito através do join.
*
* * Rodar a partir da linha de comando
* ===================================
* 1. Salve este arquivo em <dir>/jcarroscorrida/
* 2. Lance o shell: executar -> cmd
* 3. posicione no diretório <dir>
* 4. compile: javac jcarroscorrida/Main.java
* 5. execute: java -cp . jcarroscorrida/Main
*/
JAVARepositorio\JThreads\JCarrosCorrida
46
Sumário
1f
Compartilhamento de memória
47
Compartilhamento de memória
◊ Compartilhamento de memória é um subtópico de
comunicação inter-processos (IPC)
fila de mensagens (SO)
pipeline (SO) proc1 >> proc2 >> proc 3
área de memória compartilhada (SO) POSIX, threads
envio de mensagens (rede) CORBA, JRMI, RPC, MPI
◊ Threads se comunicam por compartilhamento de
memória
Atributos (membro de classe e de instância)
Objetos compartilhados
48
Exemplo de compartilhamento de memória
class AreaMem {
static String compartilhada= Thread.currentThread().getName();;
}
class Escritora extends Thread {
public void run() {
AreaMem.compartilhada = Thread.currentThread().getName();
}
}
public class Main {
public static void main(String[] args) {
Escritora E0 = new Escritora();
Escritora E1 = new Escritora();
E0.start();
E1.start();
System.out.println("Compartilhada = " + AreaMem.compartilhada);
}
}
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JCompartMemStaticSimples/
O atributo estático AreaMem.compartilhada é compartilhado entre as threads E0, E1 e main
49
Exercício
◊ Execute várias vezes o código do slide anterior
◊ Anote os valores impressos
◊ Qual a explicação?
50
Cenários de execução do exemplo
Um dos cenários possíveis de execução; o valor impresso é “main”
main:Thread
c=“main”
new
E0:Thread
E1:Thread
start()
start()
print c
run()
X
run()
c=“Thread-0”
c=“Thread-1”
X
X
51
Exemplo por atributo estático
public class Main extends Thread {
static int c = 0; // compartilhado
private int ini, fim; // nao compartilhados
public Main(int ini, int fim) {
this.ini = ini;
this.fim = fim;
}
public void run() {
System.out.println(Thread.currentThread().getName() + "
while (c >= ini && c <= fim) {
System.out.println(Thread.currentThread().getName()
c = (int)(Math.random()*10);
System.out.println(Thread.currentThread().getName()
}
System.out.println(Thread.currentThread().getName() + "
}
!!! wait ");
+ "
antes " + c);
+ " depois " + c);
!!! fim ");
public static void main(String[] args) {
new Main(0, 4).start();
new Main(5, 10).start();
}
}
JAVARepositorio\JThreads\JCompartMemStatic
52
Cenário de execução do exemplo
main:Main
<<create>>
Thread-0:Main
Thread-1:Main
start()
start()
swap
run()
0≤c≤4
c:=2
0≤c≤4
c:=5
X
swap
X
5 ≤ c ≤ 10
c:=6
5 ≤ c ≤ 10
c:=2
X
O atributo estático c
é compartilhado pelas
threadas
53
Exercício
Explique porque a seguinte
sequência de mensagens não é
possível
main:Main
<<create>>
Thread-0:Main
Thread-1:Main
start()
start()
swap
run()
0≤c≤4
c:=2
X
swap
run()
5 ≤ c ≤ 10
swap
0≤c≤4
c:=5
swap
X
5 ≤ c ≤ 10
c:=6
5 ≤ c ≤ 10
c:=2
X
54
Exercício
Objetivo: entender o
compartilhamento de memória por
atributos estáticos
◊ Para a classe abaixo
class Schedule
static int x = 0;
static int y = 0;
public static int op1() {
x = 1;
return y;
}
public static int op2() {
y = 2;
return 3*x;
}
Se uma thread chama op1 e outra, op2, que resultados podem ser retornados
pelos métodos op1 e op2?
(Vijay K. Garg, 2004, p. 15)
55
Exemplo por objeto compartilhado
class Conta {
int saldo = 0;
}
class Retirada extends Thread {
private Conta c;
public Retirada(Conta c) {
this.c = c;
}
public void run() {
int vlrs[] = {10, 20, 30, 40, 50, 60};
for (int i=0; i <vlrs.length; i++)
c.saldo -= vlrs[i];
}
}
Objeto compartilhado
class Deposito extends Thread {
private Conta c;
public Deposito(Conta c) {
this.c = c;
}
public void run() {
int vlrs[] = {40, 50, 60, 10, 20, 30};
for (int i=0; i <vlrs.length; i++)
c.saldo += vlrs[i];
}
}
public class Main {
public static void main(String[] args) {
Conta c = new Conta();
Thread d = new Deposito(c);
Thread r = new Retirada(c);
d.start();
r.start();
try {
d.join();
r.join();
} catch (InterruptedException e) { }
System.out.println("Saldo=" + c.saldo);
}
}
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JCompartMemObjetoCC/
56
Exercício
◊ Faça uma classe Java que faça busca paralela num array
de inteiros. A classe deve implementar o método:
public static int busca(int x, int[] A, int nThreads)
O método cria nThreads
Estas threads devem compartilhar o objeto A.
Cada thread busca pelo inteiro x em uma parte de A, por exemplo,
da posição 0 até a 10, outra da 11 a 20, ...
Se uma das threads encontra x, então retorna-se o índice i, tal que
A[i] = x
Caso contrário, o método retorna -1
Quando uma das threads encontra o número x, as outras devem
parar a busca!
sol. JAVARepositorio\JThreads\JBuscaParalela
57
Sumário
1g
Máquina de estados de uma thread
58
Estados de uma thread
As transições observadas até o momento estão em destaque
Object.wait(timeout)
Thread.join(timeout)
Thread.sleep(delay)
TIMED WAITING
Object.notify()
Object.notifyAll()
join thread termina
fim do sleep
Obteu lock
new()
NEW
start()
Escolhida pelo
scheduler Thread.yield()
swap do scheduler
RUNNING
Object.wait()
Thread.join()
BLOCKED
RUNNABLE
join threads terminam
Object.notify()
Object.notifyAll()
WAITING
TERMINATED
Fim do método run()
Synchronized(obj)
59
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.State.html
Estado de uma thread: detalhe do runnable
RUNNING
Escolhida pelo scheduler
Em runnable, a thread pode ser
escolhida pelo scheduler
para entrar em execução. Uma vez em
execução, pode liberar o processador
por yield ou por swap do scheduler.
Thread.yield()
swap do scheduler
RUNNABLE
60
Sumário
2
PROBLEMAS DE CONCORRÊNCIA
61
Sumário
2a
Problemas de Concorrência
62
Problemas de concorrência
◊ Processos compartilham dados
◊ Sincronizar acesso aos dados é necessário
◊ Exemplo
x é uma variável compartilhada (inicialmente zero)
Thread T0 faz x := x + 1
Thread T1 faz x := x + 1
x deve ser 2 ao final
◊ Porém, se x := x + 1 não for uma operação atômica...
63
RACE CONDITION: atualização perdida
◊ x = x + 1 em código de máquina (inicial x=0)
LD R, x load registrador R com x
INC R
incrementar R
ST R, x store R em x
◊ A execução de T0 e T1 é intercalada
P0: LD R, x
R=0
P0: INC R
R =1
0
10
10
Variável x
P1: LD R, x R = 0
P0: ST R, x
Registrador R
P1: INC R
R =1
P1: ST R, x
x =1
10
1
x =1
Resultado final: x = 1 problema da atualização perdida
64
Problemas de concorrência
◊ x := x + 1 deve ser executada atomicamente
◊ Região/Seção crítica necessida atomicidade
◊ Para garantir atomicidade, exclusão mútua
processos querem o recurso,
mas só um pode utilizá-lo, caso
contrário o recurso pode ficar
num estado inconsistente
Recurso
compartilhado
Processo 2
Processo 1
Quem ganha a disputa?
65
RACE CONDITION: atualização perdida
CC = Conta corrente
Saldo: R$ 100,00
Transação T1:
crédito de R$5,00
Transação T2:
crédito de 10% de juros
Situação desejada:
1) Aplica-se o juros
2) credita-se R$ 5,00
Funcionamento das transações
1)
2)
3)
s:=CC.getSaldo()
Crédito na variável s
CC.setSaldo(s)
Saldo da conta deve ser:
(R$100,00 * 1,1) + 5,00 = R$ 115,00
Problemas:
Leitura suja
Atualização perdida
66
RACE CONDITION: atualização perdida
Quando uma transação sobrescreve valores
produzidos por outra
TRANSAÇÃO T2
Juros de 10%
TRANSAÇÃO T1
Creditar R$ 5,00
S:= CC.getSaldo()
S:= S + 5
// R$100
// S = 105
S = CC.getSaldo( ); // R$100
S = S * 1,10;
// R$ 110,00
CC.setSaldo(S);
// R$ 110,00
CC.setSaldo(S) // R$105
Sobrescreve o valor produzido por T2
Saldo final = R$ 105,00
67
RACE CONDITION: leitura suja
Quando uma transação lê valores intermediários de
outro transação - atributos que estão sendo modificados
em outra transação
Saldo A = R$ 200,00
Saldo B = R$ 300,00
TOTAL = R$ 500,00
Transfere R$100,00 da
Conta A para a conta B
TRANSAÇÃO T1
A.retirar(100)
Após transferência
Saldo A = R$ 100,00
Saldo B = R$ 400,00
TOTAL = R$ 500,00
Relatório com o saldo total das
agências
TRANSAÇÃO T2
total = A.saldo( ); // R$100
total = total + B.saldo( ); // R$300
Mostrar total = R$ 400,00
B.depositar(100)
68
CONCORRÊNCIA
◊ Exemplo de leitura suja/atualização perdida: executar o código
abaixo e observar que o número apontado pelo contador central difere
da soma dos contadores locais devido aos problemas de leitura suja e
atualização perdida.
Códigos fonte e .jar disponíveis em
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JRaceConditionRoletas/
Contador central
160.000.000
Atualizado pelas
duas roletas de
forma concorrente
40.000.000
120.000.000
Roleta e contador local
69
Sumário
2b
Vivacidade: deadlock, livelock e starvation
70
Vivacidade
◊ VIVACIDADE: um pedido de uma thread para entrar/acessar
uma seção crítica será atendido mais cedo ou mais tarde
DEADLOCK: uma thread t1 bloqueia a espera de uma seção crítica
ocupada por t2 que, por sua vez, está bloqueada a espera da
seção crítica ocupada por t1 grafo wait-for cíclico
STARVATION: quando uma thread solicita entrada numa seção
crítica e nunca é atendida (ex. porque as outras tem maior
prioridade)
LIVELOCK: duas threads não conseguem avançar porque uma muda
seu estado em resposta à mudança de estado da outra (ex. duas
pessoas no corredor que sempre escolhem o mesmo lado para
desviarem).
71
Exemplo de deadlock
◊ DEADLOCK: filósofos podem bloquear-se.
?
?
Applet demo disponível em
http://www.doc.ic.ac.uk/~jnm/concurrency/classes/Diners/Diners.html /
72
Exemplo de starvation
◊ STARVATION: um dos filósofos nunca come porque o outro
tem maior prioridade.
Prioridade por
ser o mais sábio
73
Exemplo de livelock
◊ LIVELOCK: filósofos podem bloquear-se porque mudam de
estado continuament em função do outro.
74
Problema dos filósofos
1.
2.
Só um dos filósofos decide comer
Os dois decidem comer ao mesmo tempo, cada um pega um pauzinho
P1 c/ F1
Filósofo 1
termina de
comer
F1
F1
pega
decide
2 pauzinhos comer
P2 c/ F1
P1 c/ F21
Pauzinho 1
F1 e F2
pensam
Pauzinho 2
F2
decide
comer
F2
pega
2 pauzinhos
Filósofo 2
termina
de comer
P2 c/ F2
75
Problema dos filósofos
◊ Solução para o problema dos filósofos: coordenar as
ações
Um dos filósofos devem solicitar os recursos na ordem inversa dos
outros
Ex. todos pegam o objeto da esquerda e depois o da direita.
Facilmente visível com dois filósofos
76
Problema dos filósofos
◊ SOLUÇÃO: coordenar as ações. Inverter a ordem.
WAIT
77
Solução para filósofos
Primeiro o p1 depois o p2
Se os dois decidem comer ao mesmo tempo,
somente um deles conseguirá pegar o pauzinho
1
P1 c/ F1
P1 c/ F21
Pauzinho 1
Filósofo 2
termina
de comer
Filósofo 1
termina de
comer
P1 e P2
C/ F1
F1
decide
comer
F1 e F2
pensam
F2
decide
comer
P1 E P2
c/ F2
Pauzinho 2
78
Problema dos filósofos
◊ Exercício
Verificar se a solução apresentada funciona para 4 filósofos sendo o f2
aquele que pega na ordem invertida. Represente em um diagrama de
seqüência a situação na qual todos tentam pegar os pauzinhos ao mesmo
tempo.
f1
p1
p4
f2
f4
p3
p2
f3
79
Sumário
2c
Soluções aos problemas de concorrência
80
SOLUÇÕES PARA CONCORRÊNCIA
Como resolver os problemas de acesso à seção crítica?
◊ Exclusão mútua por hardware
Desabilitar interrupções
instruções de máquina atômicas de mais alto-nível
◊ Primitivas de sincronização
Semáforos
Monitores
monitor
81
MUTEX por HARDWARE
◊ Que soluções existem em hardware para o problema de
exclusão mútua (MUTEX)?
Desabilitar interrupções: antes de entrar na SC, o processo
desabilita as interruções
Em máquinas monoprocessador pode funcionar com alguns
incovenientes...
interrupções do clock (time-slice) ficam desabilitadas
mas, em máquinas multiprocessadores? É possível desabilitar
interrupções em todos os processadores?
Instruções atômicas mais abstratas fornecidas pelo hardware
Test and set
Swap
82
SEMÁFOROS
◊ SEMÁFORO (Dijkstra): é uma primitiva de sincronização de
acesso à seção crítica que soluciona o problema de busywait.
◊ API do sistema operacional (SO)
Disponível na API do S.O.
Java não oferece semáforos
◊ Dois tipos de semáforos
Binário
contador
83
SEMÁFORO BINÁRIO
◊ Semáforo binário:
Valor inicial: verdadeiro
Fila de processos em wait: vazia
◊ Operações básicas
P() wait
V() signal (notify)
84
Semáforo binário
T1:thread
S:SemaforoBinario
T2:thread
true
P( )
false
P( )
Na seção
crítica
V( )
true
false
wait
notify( )
Na seção
crítica
V( )
true
85
SEMÁFOROS
◊ Semáforo contador:
Valor inicial: valor inteiro = número de processos permitidos na SC
◊ Operações básicas
P() wait decrementa um contador
V() signal (notify) incrementa contador
Ver código
86
Semáforo contador
T1:thread
S:SemaforoContador
T2:thread
T3:thread
2
P( )
1
P( )
0
Na seção
crítica
P( )
V( )
1
wait
notify( )
0
V( )
1
Há dois recursos, neste caso o
semáforo é inicializado com 2
87
PRODUTOR-CONSUMIDOR
◊ Problema do Produtor-Consumidor
Solução utilizando semáforos
K=5
PRODUTOR
CONSUMIDOR
BUFFER COMPARTILHADO
88
PRODUTOR-CONSUMIDOR
◊ PRODUTOR-CONSUMIDOR Solução utilizando semáforos
entrada
4
3
2
5
1
...
saída
TAM -1
0
89
PRODUTOR-CONSUMIDOR
◊ Problemas
Exclusão mútua no acesso ao buffer
(ou o produtor ou o consumidor)
Consumidor não deve buscar itens quando o buffer está vazio
Produtor não pode produzir se buffer estiver cheio
SINCRONIZAÇÃO CONDICIONAL: Um processo aguarda que uma
condição se torne verdadeira antes de continuar suas operações.
Exemplos:
Consumidor aguarda a existência de um item
Produtor aguarda espaço no buffer para produzir
90
PRODUTOR-CONSUMIDOR
◊ Exercício (solução utilizando semáforos)
Baixe o código fonte
Faça o diagrama de sequência para o cenário seguinte:
O produtor produz um item (double)
O consumidor consome.
O consumidor tenta consumir um item que não existe.
Código fonte e .jar disponível em
JAVARepositorio/JThreads/JProdutorConsumidorSemaforos
91
SEMÁFOROS
◊ Outros problemas bem-conhecidos
Leitor-escritor em banco de dados
Não acessam o BD concorrentemente
Leitor e escritor
Dois escritores
Múltiplos leitores acessam concorrentemente
Filósofos
92
MONITOR LOCK
◊ MONITOR: mais alto nível e mais fácil de utilizar que
semáforo
◊ Java só trabalha com monitores
◊ Todo objeto em Java é um monitor
93
MONITOR LOCK
◊ Quando uma thread executa um bloco de código
sincronizado, ela fecha o acesso às demais. Outra thread
que tentar acessar a seção crítica (o bloco de código) não
conseguirá até que a primeira libere o acesso.
◊ Em java, o bloqueio é feito no objeto e não no método.
◊ Isto é útil quando duas ou mais threads devem atualizar
a mesma área de mémória (atributo compartilhado).
94
EXEMPLO MONITOR LOCK
T1:thread
obj:Compartilhado
T2:thread
Lock livre
método sincronizado( )
Lock ocupado
Na seção
crítica
método sincronizado( )
fim método
waiting
notify( )
Na seção
crítica
fim método
Lock livre
95
Exemplo em JAVA
◊ Problema das roletas e contador central
/**
* Contador é um objeto compartilhado pelas threads roleta 1 e roleta 2.
*/
class ContadorCentral {
protected int numPessoas=0;
/**
* O código que faz a atualização da variável numPessoas é uma seção crítica.
* Somente um processo (ou thread) pode executá-lo por vez. Para impedir que
* mais de uma thread atualize numPessoas, utiliza-se a palavra-chave
* synchronized.
**/
protected synchronized void somarNumPessoas(int n) throws InterruptedException
{
numPessoas += n;
}
}
Ao executar somarNumPessoas de uma certa instância de ContadorCentral o lock fica retido.
Qualquer outro método (se houvesse) da instância não poderia ser executado enquanto o
somarNumPessoas não terminasse (lock liberado).
JAVARepositorio\JThreads\JRaceConditionRoletasSol
96
Exemplo em JAVA: outra forma
◊ Problema das roletas e contador central (equivale ao anterior, só
muda a sintaxe)
/**
* Contador é um objeto compartilhado pelas threads roleta 1 e roleta 2.
*/
class ContadorCentral {
protected int numPessoas=0;
/**
* O código que faz a atualização da variável numPessoas é uma seção crítica.
* Somente um processo (ou thread) pode executá-lo por vez. Para impedir que
* mais de uma thread atualize numPessoas, utiliza-se a palavra-chave
* synchronized.
**/
protected void somarNumPessoas(int n) throws InterruptedException {
synchronized (this) {
numPessoas += n;
}
}
}
JAVARepositorio\JThreads\JRaceConditionRoletasSol
97
SINTAXE PARA SYNCHRONIZED
São construções equivalentes
public synchronized void metodo() {
….
….
….
}
public void metodo() {
synchronized (this) {
….
….
….
}
}
Métodos estáticos podem ser
sincronizados – equivale
a um lock de classe
98
MONITOR LOCK: SEMÂNTICA
A thread deve obter o
lock deste objeto para
entrar na SC
◊ Semântica
synchronized (object)
{
como
uma
seção
crítica
….
….
….
Lock é para objeto
(não para o bloco de
código ou método)
enterMonitor():
se obtém o lock
entra no monitor
se não aguarda;
exitMonitor():
libera o lock e
notifica processos
bloqueados
}
99
EXERCÍCIO
◊ Baixar o programa JRaceConditionRoletas do repositório e corrigir o
problema de condição de corrida na atualização do contador central
utilizando bloco de código synchronized.
Código fonte disponível em
JAVARepositorio/JThreads/JRaceConditionRoletas/
◊ Idem para o programa que atualiza saldo da conta corrente
Código fonte disponível em
JAVARepositorio/JThreads/JCompartMemObjetoCC/
FIM
Solução em RepositorioJAVA/JThreads/JRaceConditionRoletasSol
100
MONITOR LOCK: WAIT/NOTIFY
◊ Há situações onde, duas threads devem executar de forma
concorrente dois blocos de código sincronizados do
mesmo objeto.
◊ Mas foi dito que uma vez que uma thread pega o lock de
um objeto ela só o libera ao final do método!!!
◊ Foi uma meia verdade... ;-)
101
MONITOR LOCK: WAIT/NOTIFY
THREAD 1
tira
põe
THREAD 2
WAIT pedestal ≠ vazio
Tira peça
Notifica que tirou
WAIT pedestal vazio
Põe peça
Notifica que colocou
Pedestal
Objeto compartilhado
102
MONITOR LOCK: WAIT/NOTIFY
class Pedestal {
boolean livre = true;
}
class RoboProdutor implements Runnable {
Pedestal p;
RoboProdutor(Pedestal p) {
this.p = p;
}
public void run() {
while (true) {
synchronized (p) {
while (!p.livre) {
p.wait();
}
println("Peça colocada");
p.livre=false;
p.notifyAll();
}
}
}
}
class RoboConsumidor implements Runnable {
Pedestal p;
RoboConsumidor(Pedestal p) {
this.p = p;
}
public void run() {
while (true) {
synchronized (p) {
while (p.livre) {
p.wait();
}
println("Peça retirada");
p.livre=true;
p.notifyAll();
}
}
}
}
Catch e try foram omitidos
Wait libera o lock; Notify não libera o lock
JAVARepositorio\JThreads\JExemploWaitNotifyPedestal
103
EXEMPLO MONITOR LOCK
Produtor:Runnable
p:Pedestal
Consumidor:Runnable
Lock
Início do run()
synchronized(p)
Obtém o lock de p
Início do run()
Lock
synchronized(p)
“Peça Colocada”
p.livre = false
Livre=false
notifyAll( )
waiting pelo lock
fim bloco sync: libera o lock
synchronized(p)
Obtém o lock de p
wait p.livre
Lock
Lock
Lock
Obtém o lock
p.livre = true
Livre=true
“Peça Retirada”
104
EXERCÍCIO
◊ Baixe o código fonte dos robôs e pedestal
◊ Inclua mais um robô consumidor
◊ Identifique na mensagem impressa qual robô consumidor
que faz a retirada da peça
◊ Verifique se o programa funciona corretamente.
http://www.dainf.ct.utfpr.edu.br/~tacla/JAVARepositorio/JThreads/JExemploWaitNotifyPedestal/
105
MONITOR LOCK: WAIT, NOTIFY
◊ Cada monitor tem uma fila de processos bloqueados
◊ 3 métodos especiais podem ser usados dentro do monitor
synchronized
(object) {
….
object.wait();
….
object.notify();
….
object.notifyAll(
);
….
}
Thread Libera o lock do object e
passa ao estado waiting
Se a fila não estiver vazia, pega um
processo qualquer da fila e o
desbloqueia
Se a fila não estiver vazia,
desbloqueia todos os processos da
fila que vão disputar o lock – mas só
um será escolhido pelo escalonador
(ineficiente se houver muitas threads)
106
NOTIFY x NOTIFY ALL
◊ Utilizar notify no lugar de notify all somente quando as
duas condições abaixo forem verdadeiras:
1. Threads em waiting possuem mesma condição de espera (ex.
estahVazio). Todas as threads executam a mesma lógica quando
saem do wait.
2. One-in, one-out. A notificação sobre a variável utilizada na
condição habilita somente uma thread a prosseguir.
Fonte: Goetz, B. Java Concurrency in Practice, ed. Pearson Education,
2006, seção 14.2.4
107
Exemplo típico
synchronized(obj) {
while(<condição>)
{
try {
wait();
}catch (InterruptedException e) { }
}
// alguma coisa
notifyAll();
}
108
Métodosde bloco de código sincronizado
Usar somente em blocos de código sincronizado (caso
contrário, erro de execução IllegalMonitorStateException)
◊ Object.wait( ) libera o lock
◊ Object.wait(<t em ms>) libera o lock
◊ Object.notify()
◊ Object.notifyAll()
◊ Importante: não manipulam lock
Thread.yield() não libera o lock
Thread.sleep(<t em ms>) não libera o lock
Thread.suspend() não utilizar – deprecated
Thread.resume() não utilizar - deprecated
109
Tipos de monitores
◊ Há duas implementações clássicas de monitores
Hoare: o processo que faz a notificação é interrompido
Estilo Java: o processo que faz a notificação não é
necessariamente interrompido
110
Dois tipos de monitores
Processo 0
synchronized (object) {
….
object.wait();
Processo 1
synchronized (object) {
….
object.notify();
Qual processo continua a execução nesse ponto?
….
….
}
}
Somente um processo pode estar no monitor: 2 possibilidades
111
TIPO 1: MONITOR DE HOARE
Process 0
synchronized (object) {
….
object.wait();
Process 1
synchronized (object) {
….
object.notify();
….
}
….
}
Processo 0 assume a execução
assim que o 1 faz notify
112
Tipo 1: MONITOR DE HOARE
Process 0
synchronized (object) {
if (x != 1)
object.wait();
A condição de sincronização
(x=1) é seguramente verdadeira quando o processo
é notificado
Process 1
synchronized (object) {
x=1;
O processo que notifica
object.notify(); é interrompido
assert(x==1); // x é igual a 1
x++;
}
// x pode ser ≠ 0 neste ponto
}
No monitor HOARE, é possível fazer
condição sincronizada com if
113
TIPO 2: MONITOR ESTILO JAVA
Process 0
synchronized (object) {
….
object.wait();
Process 1
synchronized (object) {
….
object.notify();
// código
// código
}
….
}
No monitor estilo Java, o Processo 1 continua
a executar após o notify
114
Tipo 2: MONITOR JAVA
Process 0
synchronized (object) {
if (x != 1)
object.wait();
P0 realiza operações
assumindo x=1, sendo
que x pode ter outro
valor
Process 1
synchronized (object) {
x=1;
object.notify();
assert(x == 1); // x must be 1
x++;
}
assert(x==1); // falso
x++;
}
Processo 1 continua a executar e pode modificar o valor de x. A
sincronização condicional com um simples if pode não funcionar.
115
Tipo 2: MONITOR JAVA
Process 0
synchronized (object) {
while (x != 1)
Só sai do while
object.wait(); quando x=1
P0 realiza operações
assumindo x=1, sendo
que x será igual a 1
Process 1
synchronized (object) {
x=1;
object.notify();
assert(x == 1); // x must be 1
x++
}
assert(x==1); // verdadeiro
x++;
}
Para solucionar o problema do slide anterior, é preciso colocar um
while (também resolve o caso de interrupções espúrias).
116
Dois tipos de monitores
◊ O monitor Java é mais usual
Porém, é prudente verificar o tipo de monitor quando for utilizar
outra linguagem
◊ Código de sincronização é extremamente difícil de
debugar
Muitos bugs ficam escondidos durante anos sem que ninguém
perceba
Faça certo da primeira vez!
117
Resumo
◊ Por que necessitamos de primitivas de sincronização?
Busy waiting desperdiça ciclos de CPU
Primitivas de sincronização necessitam suporte do SO
◊ Semáforo:
Binário, contador
Produtor-consumidor
◊ Monitor:
Mais fácil e mais popular que semáforos
Dois tipos: Hoare e estilo Java
118
EXERCÍCIO
◊ Problema do barbeiro dorminhoco
Um barbeiro corta o cabelo de qualquer cliente.
Se não há clientes, o barbeiro tira uma soneca.
Há várias threads, uma para cada cliente.
Um cliente aguarda pelo barbeiro se há ao menos uma cadeira
vazia na barbearia,
Caso contrário, o cliente sai da barbearia imediatamente.
Se há uma cadeira disponível, então o cliente senta.
Se o barbeiro está dormindo, então o cliente acorda-o.
Existem <n> cadeiras na barbearia.
Faça um programa para a classe BarbeiroDorminhoco
utilizando monitor
119
Download