Uma das coisas que mais me chamou atenção na epoca que fiz esta matéria foi exatamente este captulo. Nele vemos diversas meios que são super validos hoje para trabalhar a programação concorrente, resolvi postar este conteudo por que eu acho que se trata um importante assunto que muitos dos meus amigos no qual eu questiono e eles não tiveram a oportunidade de ver isto.
2. Introdução
O mundo real funciona concorrentemente: várias
atividades podem ser executadas em paralelo. Exemplo:
uma pessoa pode estar
respirando, e,
falando, e
escrevendo, e
lendo, etc.
Computadores também operam concorrentemente.
Exemplo: um computador pode estar
compilando um programa, e
recebendo uma mensagem, e,
imprimindo um arquivo, e,
tocando música, etc.
2
3. Objetivos
Reduzir o tempo total de processamento
múltiplos processadores
Aumentar confiabilidade e disponibilidade
processadores distribuídos
3
4. Atividades
Cada atividade possui uma seqüência própria de
operações
Programas independentes podem se encarregar de
Compilador: compilar um programa
Navegador: receber uma mensagem e exibir animação
Subsistema de e/s: imprimir um arquivo
Subsistema de áudio: tocar música
Multiprogramação: vários programas executam sob
controle do sistema operacional
4
5. Programação concorrente
Uma unidade concorrente é um componente de
um programa que não exige a execução
seqüencial, ou seja, que sua execução seja
realizada antes ou após a execução de outros
componentes do programa
O termo programação concorrente é usado no
sentido abrangente, para designar a programação
paralela e a programação distribuída
Concorrência relaciona-se com fluxo de
controle: em um programa, existe mais de um
fluxo de controle ativo.
5
6. Fluxo de execução
Execução seqüencial Execução concorrente
Comandos de controle de Cada tarefa é uma unidade de
fluxo de execução execução autônoma (um
Seqüencial
thread)
Condicional
Tarefas podem ser totalmente
Iterativo
independentes
Requisição de execução de Exemplo: execução de um
unidades mesmo método sobre dois
explícita:chamada de
objetos (da mesma classe)
métodos
implícita: ativação de
Tarefas podem necessitar
exceções comunicação
Programa controla a Programa não controla a
ordem de execução ordem de execução 6
7. Motivos para se estudar
Método para conceber soluções de
programa para problemas. Muitos
domínios são naturalmente concorrentes.
O grande uso de computadores de
múltiplos processadores.
7
8. Concorrência
Nível de instrução: executa 2 ou mais
instruções de máquina.
Nível de comando: executa 2 ou mais
comandos.
Nível de unidade: executa 2 ou mais
unidades de sub-programas.
Nível de programa: executa 2 ou mais
programas.
8
9. Concorrência
A execução concorrente de unidades de
programa pode ocorrer fisicamente em
processadores separados ou logicamente
usando alguma forma de tempo fatiado em
um sistema de computador de um único
processador.
9
10. Categorias
Para o programador e para o projetista da
linguagem as duas concorrências são a mesma
coisa.
O implementador da linguagem é que deve
fazer a correspondência da lógica com o
hardware subjacente.
10
11. Execução concorrente
Execução concorrente, também conhecida como execução
paralela, não significa execução simultânea
A execução de unidades concorrentes admite as seguintes
possibilidades:
Pseudo-paralela: Execução em um único processador;
Paralela: Execução em vários processadores que compartilham
uma memória;
Distribuída: Execução em vários processadores independentes, sem
compartilhamento de memória.
O programa geralmente não possui controle sobre a ordem e
o tempo de execução das unidades concorrentes
11
12. Mecanismos de programação
concorrente
Os mecanismos para programação concorrente
compreendem as construções que as linguagens
usam para:
indicar quais unidades são concorrentes
ativar e controlar um fluxo de execução concorrente
possibilitar a interação entre unidades concorrentes
Unidades concorrentes em programas (níveis)
Unidades que possuem várias tarefas ou processos
concorrentes
Procedimentos/funções, objetos
Comandos
12
13. Unidades concorrentes
Concorrência de procedimentos/funções
podem ser tarefas de uma mesma unidade
podem ser ativadas de forma implícita/explícita
Em ADA, a palavra Task identifica unidade concorrente,
como por exemplo: M
Procedure M;
T1 T2
Task t1;
Task t2; ----- end M;
A ativação das tarefas concorrentes é implícita: quando o
procedimento M é chamado, as unidades t1 e t2 iniciam
automaticamente sua execução concorrente
Precaução contra tarefas/processos órfãos
13
14. Unidades concorrentes: processos
A LP pode adotar um dos seguintes esquemas para
explicitar processos:
Uma construção que indica que aquela unidade é um processo.
Exemplo, Process MP< ….>
Uma construção que instancia uma unidade concorrente. Por
exemplo: New Process ...(<args>).
Ambos os esquemas acima
Modelo de objetos: herança de comportamento concorrente
Exemplo em Java:
class Thread {... void run()...}
class Concorre extends Thread{ ... }
Concorre oc=new Concorre(); Thread oc = new Thread();
14
15. Exemplo em Java
public class M extends Thread{
public static int n=10;
public void t1(){
System.out.println("Entrada T1: " + n);
for (int i=1; i>=50000;i++); //consome tempo
n=n+1;
}
public void t2(){
System.out.println("Entrada T2: " + n);
for (int i=1; i>=50000;i++); //consome tempo
n=n+2;
}
public void run(){
t1(); inicia execução
t2();
}
} 15
16. Unidades concorrentes:
mecanismos
A LP deve oferecer recursos para:
controlar a execução das unidades concorrentes
estabelecer prioridades e restrições temporais
permitir a comunicação entre unidades
Processos podem ser:
centralizados (ambiente local)
ou distribuídos (ambiente global)
Questões: comunicação entre os processos
16
17. Exemplo de concorrência de
instruções
procedure M; O ciclo de atualização da global N é decomposto:
n: integer;
task t1; t1: |___ fetch N ___|___n:=n+1___|___store n__|
n:= n+1;
task t2; t2: |___ fetch N ___|___n:=n+2___|___store n__|
n:= n+2;
begin
n:= 10; resultado:
cobegin n= 13, se Fetch N for feito após a sua atualização;
t1;t2; n= 12 ou 11, se Fetch N for feito por t1 e t2, com
coend; acesso simultâneo, antes de um Store N.
write(n);
end. 17
18. Concorrência no Nível de
Subprograma
Tarefa: unidade de um programa que pode estar em
execução concorrente com outras unidades do mesmo
programa. Pode oferecer um thread.
Pode ser iniciada implicitamente
A tarefa não precisa terminar para a unidade continuar
executando.
O controle pode ou não retornar à unidade que iniciou essa
execução.
Pode se comunicar pelas variáveis não-locais
compartilhadas, pela passagem de mensagens ou pelos
parâmetros.
18
19. Concorrência no Nível de
Subprograma
Tarefa disjunta: não se comunica ou não afeta
a execução de qualquer outra tarefa.
Sincronização: mecanismo que controla a
ordem de execução das tarefas.
Cooperação: quando uma tarefa A precisa
aguardar que a B termine alguma atividade para
que ela possa continuar a sua execução. Ex.
produtor-consumidor.
Competição: quando duas tarefas precisam usar
algum recurso e o seu uso não pode ser
simultâneo. Ex. semáforos, monitores
19
20. Concorrência no Nível de
Subprograma
Scheduler : gerencia o compartilhamento dos
processadores entre as tarefas.
Deadlock : Situação na qual duas ou mais unidades
concorrentes não conseguem prosseguir a execução
por que cada uma está aguardando que alguma das
outras faça alguma coisa
Livelock : Situação na qual uma unidade concorrente
não consegue terminar a execução ou entrar em uma
seção crítica por excesso de trabalho ou falta de
velocidade.
Difere de deadlock por estar ativa e não bloqueada ou
aguardando algo
20
21. Tarefas x subprogramas
Tarefas são unidades ( grupos de comandos, objetos,
processos) de execução concorrente com as seguintes
características:
Uma tarefa pode ser implicitamente iniciada
Quando uma unidade de programa inicia a execução de
uma tarefa, poderá ou não prosseguir a sua execução
Quando a execução de uma tarefa é completada o controle
pode não retornar o ponto de invocação
Tarefas podem exigir comunicação para fins de:
cooperação: T1 necessita um serviço de T2 para prosseguir
execução (aguarda serviço)
competição: T1 precisa um recurso que T2 está usando
(aguarda recurso)
21
22. Comunicação entre tarefas
A comunicação entre tarefas pode ser feita através de:
Variáveis não locais compartilhadas
Parâmetros
Passagem de mensagem
Recursos compartilhados devem ser protegidos
contra acessos simultâneos
Tarefa1
recurso
compartilhado Tarefa2
Tarefa3
22
23. Variáveis compartilhadas
Duas unidades
concorrentes fazem
operações sobre thread 1 thread 2
variáveis a e b, através ab() ba()
de métodos de uma
mesma classe
Problema:
inconsistência de dados a = 100 ; b = 200
Solução: garantir
ab(){a = a-b; } ba(){b = b-a; }
atomicidade de
execução das operações
23
24. Sem sincronismo: exemplo
class DoisMetodos {
static int a = 100, b = 200;
static void ab() {
exibeDados();
a = a-b; ChamaAB oab= new ChamaAB();
exibeDados(); ChamaBA oba = new ChamaBA();
}
static void ba() { oab.start();
exibeDados(); oba.start();
b =b-a;
exibeDados();
}
static void exibeDados(){
System.out.println(" a =" + a +"t" +" b =" + b +"t" +
Thread.currentThread().getName());
} }
24
25. Inconsistência de dados
/* um resultado
a =100 b =200 Thread-1
a =100 b =200 Thread-2 threads
a = -100 b =200 Thread-1 intercaladas
a = -100 b =300 Thread-2 */
/* outro resultado:
a =100 b =200 Thread-1
a = -100 b =200 Thread-1 OK! thread2
a = -100 b =200 Thread-2
a = -100 b =300 Thread-2*/
após thread1
/* mais um resultado
a =100 b =200 Thread-2
a =100 b =100 Thread-2
OK! thread1
a =100 b =100 Thread-1
a =0 b =100 Thread-1 */ após thread2
25
26. LP concorrentes: projeto
Como é feito o sincronismo de cooperação?
Exemplo: mecanismo de espera, no qual uma tarefa
aguarda que outra atinja um determinado ponto de
execução para estabelecer comunicação.
Como é feito o sincronismo de competição?
Exemplo: bloqueio de código de acesso a recursos
compartilhados (exclusão mútua)
Como e quando as tarefas iniciam a terminam sua
execução?
Exemplo: tarefas são explicitamente iniciadas e podem
terminar normalmente ou por interrupção explícita
26
27. Mecanismos de sincronização
Semáforos (Dijkstra)
Exigem memória compartilhada
Podem ser usados para cooperação e competição
Monitores (Brinch-Hansen)
Exigem memória compartilhada
Baseados em tipos abstrados de dados
Passagem de mensagens
Podem ser usados para programação distribuída
27
28. Exemplo: produtor x consumidor
Produtor Consumidor:
- produz item - busca item no buffer,
- coloca item no buffer, se não estiver vazio
se não estiver cheio - consome item
aguarda se cheio aguarda se vazio
BUFFER de ITENS
28
29. Semáforos
Um semáforo é uma estrutura de dados que
consiste de um contador e uma fila de tarefas
Possuem apenas duas operações:
Aguarda / Bloqueia ( primitiva P)
Continua / Libera (primitiva V)
Semáforos podem ser usados para
implementar guardas no código de acesso a
dados compartilhados
29
30. Semáforos: primitivas
Aguarda / Bloqueia: P(semáforo S)
se S.contador > 0 ( fila do semáforo S não vazia)
então decrementa S.contador
senão coloca a tarefa na S.fila, tenta transferir o controle para
alguma tarefa apta; se não existir tarefa apta, ocorre
deadlock
Continua / Libera: V (semáforo S)
se fila do semáforo S estiver vazia
então incrementa S.contador
senão coloca a tarefa como apta e transfere o controle para
uma tarefa da S.fila
30
31. Semáforos: produtor x consumidor
Process Produtor; Process Consumidor;
Var i: integer; Var i: integer;
begin begin
exclusão código
loop loop
crítico
produz(i); P(ocupados);
P(vazios); P(exclusão);
vazios P(exclusão); retira(i);
coloca(i); V(exclusão);
V(exclusão); V(vazios);
ocupados V(ocupados); consome(i);
end loop; end loop;
end; end;
31
32. Semáforos: deadlock
Process Produtor; Process Consumidor;
Var i: integer; Var i: integer; exemplo:
begin begin inverter ordem
loop loop
produz(i); P(exclusão);
P(vazios); P(ocupados);
P(exclusão); retira(i);
coloca(i); V(exclusão);
V(exclusão); V(vazios);
V(ocupados); consome(i);
end loop; end loop;
end; end;
32
33. Monitores
A idéia: encapsular os dados compartilhados e suas operações
para restringir o acesso
Um monitor é um TAD para dados compartilhados
Fornece sincronização de competição sem semáforos
Transfere a responsabilidade da sincronização ao sistema em
tempo de execução.
produtor operação operação
coloca retira consumidor
BUFFER de ITENS
33
34. Monitores: buffer
type buffer= monitor
var conteudo : array[...] of integer;
origem, destino: fila; {...}
procedure entry coloca (item:integer);
begin
if buffercheio then delay(origem);
{ coloca item no buffer }
continue(destino);
end;
procedure entry retira(var item:integer);
begin
if buffervazio then delay(destino);
{ retira elemento do buffer}
continue(origem);
end;
begin {corpo do monitor}end;
34
35. Monitores: buffer
Delay(fila): colocar o processo que a chama na fila
especificada e retirar seus direitos de acesso
exclusivo a estruturas de dados do monitor.
Execução suspensa.
Continue(fila): desconectar o processo que a chama
do monitor, liberando-o de ser acessado por outros
processos. Examina a fila especificada, se contiver
processo, ele será removido e sua execução
reiniciada.
35
36. Monitores: produtor x consumidor
{type} {type}
Produtor= Consumidor=
process (area: buffer); process (area=buffer);
var dado: integer; var dado: integer;
begin cycle
begin cycle
produz(dado); area.retira(dado);
area.coloca(dado); consome(dado);
end; end;
end; end;
36
37. Monitores: produtor x consumidor
Os tipos de dados declarados Buffer(monitor),
Produtor (process) e Consumidor(process)
devem ser :
instanciados
inicializados através de um comando init
init provoca a execução cíclica do Produtor e
do Consumidor , que usam o monitor Buffer
O monitor Buffer garante a exclusão mútua
das operações coloca e retira
37
38. Threads: o que são?
Definição básica: “ Fluxo de controle seqüencial isolado
dentro de um programa.”
Programas multithreaded: Múltiplos threads concorrentes de
execução num único programa, realizando várias tarefas “ao
mesmo” tempo.
Exemplo: programa do usuário + coleta de lixo
Diferentes threads podem executar em diferentes
processadores, se disponíveis, ou compartilhar um
processador único
Diferentes threads no mesmo programa compartilham um
ambiente global (memória, processador, registradores, etc.)
38
39. Algumas aplicações multithreaded
Programação Reativa : aplicação responde a eventos
de entrada.
Exemplo: interfaces com o usuário, onde cada evento
corresponde a uma ação
Programação Interativa: uma tarefa para fazer alguma
interação com o usuário, outra para exibir mensagens,
outra para fazer animação, etc..
Paralelismo físico/ distribuição: para tirar vantagem
de múltiplas CPUs centralizadas ou distribuídas
39
40. Criação de threads em Java
Criar uma subclasse da Implementar a
classe Thread interface Runnable;
public class MyClass public class MyClass
extends Thread { ... } extends Applet
class Thread implements Runnable {
... } interface
class Applet Runnable
class MyClass
class MyClass
40
41. Questões importantes em
Multithreading
Segurança: como sincronizar threads para que
elas não interfiram com uma outra
Longevidade: como evitar situações de
deadlock ou livelock para garantir que todos
os threads farão progresso
Desempenho: a mudança de contexto dos
diversos threads provoca queda de
desempenho (overhead)
41
42. Instanciação de objetos
concorrentes
classe
Execução
Estruturas de dados concorrente do
mesmo código
Métodos
RA1 RA2
Dados do
Dados do
Objeto2
Objeto1
42
43. Execução de threads
Cada thread possui um método run() que define a
atividade concorrente
Exemplo: public void run( ) {
O for (int count=0; count<1000; count++)
que?
System.out.println(nome); }
A atividade concorrente inicia quando é invocado o
método start() sobre um objeto.
Exemplo: public static void main(String[] arg) {....
Quando? um.start( );
dois.start( ); ......} 43
44. Classe Thread
Usada quando a classe a ser executada
concorrentemente não deriva de outra classe
Contém métodos para controlar a execução
Criação e execução:
Declarar uma nova classe que seja subclasse da classe
Thread
Sobrescrever o método run() com o código que será
executado pela thread
Instanciar a nova classe
Invocar seu método start(); o método rodará em seu
próprio thread de controle 44
45. Contexto da classe Thread
public class Thread
java.lang.Object
extends Object
implements Runnable
java.lang.Thread
Alguns métodos da classe Thread
start(): inicia a execução do Thread;
sleep(): suspende a execução por um determinado tempo
(especificado em milisegundos) e automaticamente recomeça a
execução;
destroy():destrói esta thread.
Demais métodos: jdk1.2.1/docs/api/java/lang/Thread.html
45
46. Exemplo de extensão Thread
class Piloto extends Thread{
private String nome;
public Piloto(String str){
nome = str;
}
public void run(){
System.out.println("****LARGADA ****");
System.out.println(”Primeira volta: " + nome);
for(int cont=0; cont<10000; cont++){};
System.out.println(nome + " -> Terminou a Corrida !!!");
}
} 46
47. Exemplo de execução
public class CorridaT{
public static void main(String[] args){
Piloto um = new Piloto("Rubinho");
Piloto dois = new Piloto("Schumacher");
Piloto tres = new Piloto(”Raikonnen");
um.start();
dois.start();
tres.start(); CorridaT
}
}
um dois tres
Quem terminará antes?
47
48. Resultado de uma execução
CorridaT
*** LARGADA ***
*** LARGADA *** um dois tres
*** LARGADA ***
Primeira volta:Rubinho
Primeira volta:Schumacher
Primeira volta: Raikonnen
Rubinho -> Terminou a Corrida !!!
Raikonnen -> Terminou a Corrida !!!
Schumacher -> Terminou a Corrida !!!
48
49. Resultado de outra execução
*** LARGADA ***
Primeira volta:Rubinho
Rubinho -> Terminou a Corrida !!!
*** LARGADA ***
Primeira volta:Schumacher
*** LARGADA ***
Schumacher -> Terminou a Corrida !!!
Primeira volta: Raikonnen
Raikonnen -> Terminou a Corrida !!!
CorridaT
um dois tres
49
50. Interface Runnable
Usada quando não se pode herdar da classe Thread,
pois há necessidade de herança de alguma outra classe
possui apenas o método run()
Cria-se um objeto da classe base Thread, porém o
código a ser executado está descrito na classe do
usuário(derivada + ancestrais).
Criação e execução:
Declarar uma nova classe que implementa a
interface Runnable
Sobrescrever o método run()
Criar um objeto da classe Thread.
Exemplo: Thread um = new Thread(this);
50
51. Exemplo de implementação
Runnnable (1)
class PilotoR implements Runnable{
private String nome;
public PilotoR(String str){
nome = str;
}
public void run(){
System.out.println("*** LARGADA ***");
System.out.println(" Primeira volta:" + nome);
for(int cont=0; cont<10000; cont++) {};
System.out.println(nome + " -> Terminou a Corrida !!!");
}
} 51
52. Exemplo de implementação
Runnnable (2)
public class CorridaR{
public static void main(String[] args){
PilotoR um = new PilotoR("Rubinho");
PilotoR dois = new PilotoR("Schumacher");
PilotoR tres = new PilotoR(" Raikonnen ");
new Thread(um).start();
new Thread(dois).start();
new Thread(tres).start();
}
}
52
53. Estados de Threads
new
blocked
Sleep
done sleeping
No decorrer da start
execuç ão,
threads podem wait
alterar seu sleep Waiting I/O
running
estado: I/O done
- ativo
- inativo destroy
dead
- encerrado
53
54. Exemplo de sleep
class PrintThread extends Thread {
private int sleepTime;
public PrintThread (String name) { // construtor
super(nome); // nome do thread: construtor de Tread
sleepTime=(int)(Math.random() * 5000); // 0-5 sec
System.out.println(“Name: “+ getName() + “; sleep “ + sleepTime);
public void run ( ){
try{
System.out.println(getName() + “going to sleep”);
Thread.sleep (sleepTime) ;}
catch ( InterruptedException exception) {
System.out.println(exception.toString()); }
54
55. Exceção: sleep
try {
System.out.println(getName() + “going to sleep”);
Thread.sleep (sleepTime) ; método sleep pode
} disparar exceção*
catch ( InterruptedException exception)
{ nome da exceção
System.out.println(exception.toString());
}
* se outro thread chama o método interrupt durante sleep
55
56. Prioridades
Cada thread possui uma Thread de mais alta
prioridade (entre 1 e 10) prioridade apta a executar:
Default: prioridade = 5 faz com que o thread de
Prioridade transmitida por menor prioridade ceda o
herança processador
seja executada até que
Threads de igual prioridade
cedem processador por: termine a sua execução,
chamada de yield ou,
tenha a sua execução
time-slicing
suspensa (sleep/wait...)
56
57. Resumo de estados de threads
A execução do thread depende do ambiente de execução
(sistema operacional)
New threads: thread criado com new mas ainda não está
rodando
Runnable threads: Depois de chamado o método start(), o
thread está apto a ser executada (depende da disponibilidade do
sistema)
Blocked threads: um thread entra no estado bloqueado quando
ocorre
chamada aos métodos sleep(), suspend() ou wait()
espera por I/O
Dead threads: execução encerrada ( o objeto thread é destruído)
57