Processos e Concorrência
processo: modelo de execução sequencial
“programa em execução”
código, dados globais, pilha de execução
estrutura presente em qualquer sistema operacional concorrência
modelo de linhas "simultâneas" de execução concorrência e distribuição
aplicações distribuídas envolvem a execução concorrente de processos em várias máquinas
uso de concorrência local:
atendimento a comunicações concorrentes
sobreposição de comunicação e processamento
Concorrência
multiprocesso
espaços de endereçamento isolados
processos leves com compartilhamento de globais multitasking preemptivo
multithreading
multitasking cooperativo
co-rotinas ou outras construções
Computac¸ ˜ao Distribu´ıda – p.2/29
Processos
exemplo criação posix: modelo de clones - fork
comunicação por troca de mensagens
Threads
várias linhas de execução compartilham globais com escalonamento preemptivo
surgido de estudos de sistemas operacionais dificuldades de sincronização
exemplos: threads em C (posix) e em Java
Computac¸ ˜ao Distribu´ıda – p.4/29
exemplo multithreading: Java
public class ThreadsDorminhocas {
public static void main(String[] args) { new ThreadDorminhoca("1");
new ThreadDorminhoca("2");
new ThreadDorminhoca("3");
new ThreadDorminhoca("4");
}
}
exemplo multithreading: Java
class ThreadDorminhoca extends Thread { int tempo_de_sono;
public ThreadDorminhoca(String id) { super(id);
tempo_de_sono = (int) (Math.random() * 5000);
System.out.println("Tempo de sono da thread "+id+
": "+tempo_de_sono+"ms");
start();
}
public void run() { try {
sleep(tempo_de_sono);
} catch(InterruptedException exception) { System.err.println(exception);
}
System.out.println("thread "+getName()+" acordou!");
} }
Computac¸ ˜ao Distribu´ıda – p.6/29
condições de corrida
class Conta {
private int saldo;
public Conta (int ini) { saldo = ini;
}
public int veSaldo() { return saldo;
}
public void deposita(int dep) {
for (int i=0; i<dep; i++) { // artificial!!
saldo++;
} } }
. preempção!!
condições de corrida
public class ThreadsEnxeridas {
public static void main(String[] args) { int repet = 20;
Conta cc = new Conta(0);
(new ThreadEnxerida("1", cc, repet)).start();
(new ThreadEnxerida("2", cc, repet)).start();
(new ThreadEnxerida("3", cc, repet)).start();
(new ThreadEnxerida("4", cc, repet)).start();
} }
Computac¸ ˜ao Distribu´ıda – p.8/29
Sincronização
o problema de regiões críticas e a garantia de exclusão mútua
soluções por protocolos de entrada e saída espera ocupada
problemas com justiça
sinc. sem primitivas: exemplo
bool in1 = false, in2 = false; int last = 1;
process CS1 { while (true) {
in1 = true; last = 1; /* entry protocol */
while (in2 and last == 1) skip;
critical section;
in1 = false; /* exit protocol */
noncritical section;
} }
process CS2 { while (true) {
in2 = true; last = 2; /* entry protocol */
while (in1 and last == 2) skip;
critical section;
in2 = false; /* exit protocol */
noncritical section;
}
} Computac¸ ˜ao Distribu´ıda – p.10/29
métodos sincronizados
class Conta {
private int saldo;
public Conta (int ini) { saldo = ini;
}
synchronized public int veSaldo() { return saldo;
}
synchronized public void deposita(int dep) { for (int i=0; i<dep; i++) { // artificial!!
saldo++;
} } }
Sincronização
exclusão mútua
garantia de que trechos de código não estarão em execução ao mesmo tempo
corte de alguns entrelaçamentos
razoavelmente fácil de resolver com elegância condições ou cooperação
condições necessárias para execução ... dificuldades...
Computac¸ ˜ao Distribu´ıda – p.12/29
Semáforos
operações P e V
exclusão mútua e condições definições e implementações
noção de justiça
deadlock e starvation
Monitores
exclusão mútua automática
entendimento de chamadas aninhadas variáveis de condição
Computac¸ ˜ao Distribu´ıda – p.14/29
Threads em C: interface Posix Threads
API padrão
implementada como biblioteca ou como parte do SO modelo básico de sincronização: monitores
provisão também de semáforos
Threads em C: interface Posix Threads
exemplos bobo.c
Computac¸ ˜ao Distribu´ıda – p.16/29
Monitores – Dificuldades
semântica de chamadas entre operações protegidas dificuldade de lidar com filas de condições
simplificação Java: uma única fila por “monitor”
políticas de sinalização sinaliza e espera
sinaliza e continua
thread que recebe sinal vai para fila de entrada
sinalização funciona como “dica”
Política sinaliza e continua
mais comum: usada em Java e pthreads mais coerente do ponto de vista da thread sinalizadora
não há garantia de que a thread sinalizada será primeira a executar
while (not cond) wait(fila_cond);
Computac¸ ˜ao Distribu´ıda – p.18/29
exemplo: leitores e escritores
monitor RW_Controller { int nr = 0, nw = 0;
cond oktoread; cond oktowrite;
procedure request_read() {
while (nw > 0) wait(oktoread);
nr = nr + 1;
}
procedure release_read() { nr = nr - 1;
if (nr == 0) signal(oktowrite); #awaken one writer }
procedure request_write() {
while (nr > 0 || nw > 0) wait(oktowrite);
nw = nw + 1;
}
procedure release_write() { nw = nw - 1;
signal(oktowrite); #awaken one writer and signal_all(oktoread); #all readers
um exemplo mais simples: barreira
monitor controlaGupo { ...
int qtosNoGrupo;
int chegaram;
synchronized void barreira (void) { chegaram++;
if (chegaram<qtosNoGrupo) wait();
else {
chegaram = 0;
notifyAll();
} } ...
}
Computac¸ ˜ao Distribu´ıda – p.20/29
Muitas outras propostas
condições para execução fora do código ...
bibliotecas específicas para paralelismo OpenMP
www.llnl.gov/computing/tutorials/openMP/
...
OpenMP
pragmas indicam diretivas de paralelismo pragma se aplica a comando seguinte
variáveis por default compartilhadas entre threads mesmo as locais!
suporte à paralelização de loops e operações de redução
Computac¸ ˜ao Distribu´ıda – p.22/29
OpenMP: paralelização com diretivas
#include <omp.h>
main () {
int nthreads, tid;
/* Fork a team of threads giving them their own copies of variables */
#pragma omp parallel private(tid) {
/* Obtain and print thread id */
tid = omp_get_thread_num();
printf("Hello World from thread = %d\n", tid);
/* Only master thread does this */
if (tid == 0) {
nthreads = omp_get_num_threads();
printf("Number of threads = %d\n", nthreads);
}
} /* All threads join master thread and terminate */
OpenMP: loops paralelos
diretiva para for: restrições à sintaxe do comando
#include <omp.h>
#define N 1000
#define CHUNKSIZE 100 main () {
int i, chunk;
float a[N], b[N], c[N];
/* Some initializations */
for (i=0; i < N; i++) a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;
#pragma omp parallel for shared(a,b,c,chunk) private(i) \ schedule(static,chunk)
for (i=0; i < n; i++) c[i] = a[i] + b[i];
}
escalonamento: static, dynamic, guided, runtime
Computac¸ ˜ao Distribu´ıda – p.24/29
OpenMP: sincronização
diretiva critical garante exclusão mútua
#pragma omp parallel shared(x) {
#pragma omp critical x = x + 1;
} /* end of parallel section */
diretiva barrier
#pragma omp barrier newline
diretiva flush
#pragma omp flush (list)
OpenMP: Reduções
#include <omp.h>
main () {
int i, n, chunk;
float a[100], b[100], result;
/* Some initializations */
n = 100; chunk = 10; result = 0.0;
for (i=0; i < n; i++) {
a[i] = i * 1.0; b[i] = i * 2.0;
}
#pragma omp parallel for default(shared) private(i) \ reduction(+:result)
for (i=0; i < n; i++)
result = result + (a[i] * b[i]);
printf("Final result= %f\n",result);
}
Computac¸ ˜ao Distribu´ıda – p.26/29
OpenMP: reduções permitidas
x = x op expr
x = expr op x (except subtraction) x binop = expr
x++, ++x, x--, --x
item op: +, *, -, /, &, ˆ, |, &&, ||
binop: $+, *, -, /, &, ˆ, |$
OpenMP: paralelismo funcional
...
#pragma omp parallel shared(a,b,c) private(i) {
#pragma omp sections nowait {
#pragma omp section
for (i=0; i < N/2; i++) c[i] = a[i] + b[i];
#pragma omp section
for (i=N/2; i < N; i++) c[i] = a[i] + b[i];
} /* end of sections */
} /* end of parallel section */
Computac¸ ˜ao Distribu´ıda – p.28/29