Buscar

Interface Hardware-Software - 15 AulaIHS Open MP

Prévia do material em texto

Interface Hardware-Software 
OpenMP 
Aumento de Desempenho dos Processadores 
 Ao longo dos anos, processadores aumentaram o poder de 
processamento 
– Aumento da frequencia 
– Pipeline 
– Superescalar 
 
 Mais recentemente, o aumento do desempenho foi 
alcançado através do suporte em HW à execução paralela 
(real) de diferentes tarefas 
– Hardware multithreading 
– Multicores 
 
Hardware Multi-Threading 
 Abordagem multi-thread 
– Aumentar utilização de recursos de hardware permitindo que 
múltiplas threads possam executar virtualmente de forma 
simultânea em único processador 
– Compartilhamento de unidades funcionais 
 
 Objetivos 
– Melhor utilização de recursos (cache e unidades de execução 
são compartilhadas entre threads) 
– Ganho de desempenho (em média 20%) 
– Baixo consumo de área (< 5% da área do chip) 
Simultaneous Multi-Threading (SMT) 
 SMT é uma política de multi-threading para processadores 
superescalares com escalonamento dinâmico de threads e 
instruções 
– Escalonamento de instruções de threads diferentes 
– Instruções de threads diferentes podem executar 
paralelamente desde que haja unidades funcionais livres 
– Explora paralelismo ao nível de instrução (Instruction Level 
Parallelism - ILP) 
– Explora paralelismo ao nível de threads ( Thread Level 
Parallelism – TLP) 
 
 Hyper-Threading é um caso de de SMT proposto pela Intel 
– Disponível em processadores Xeon, Pentium 4- HT, Atom, 
Intel i7 
Multicores 
 Microprocessadores multicores 
– Mais de um processador por chip 
 
 Requer programação paralela 
para uma melhoria efetiva 
– Hardware executa múltiplas 
instruções paralelamente 
 Transparente para o 
programador 
– Difícil de 
 Programar visando 
desempenho 
 Balancear carga de trabalho 
Chapter 7 — Multicores, Multiprocessors, and Clusters — 6 
Processamento Paralelo - Hardware e Software 
 Software sequencial/concorrente pode executar 
em hardware serial/paralelo 
– Desafio: fazer uso efetivo de hardware paralelo 
Software 
Sequencial Concorrente 
Hardware 
Serial 
Multiplicação de 
matrizes em Java no 
Intel Pentium 4 
Windows Vista 
no Intel 
Pentium 4 
Paralelo 
Multiplicação de 
matrizes em Java no 
AMD Athlon 
Phenom II 
Windows Vista 
no AMD Athlon 
Phenom II 
Programação Paralela 
 Desenvolver software para executar em HW paralelo 
 
 Necessidade de melhoria significativa de desempenho 
– Senão é melhor utilizar processador com único core rápido, 
pois é mais fácil de escrever o código 
 
 Dificuldades 
– Particionamento de tarefas (Balanceamento de carga) 
– Coordenação 
– Comunicação 
 
Modelos de Comunicação 
 Nos computadores atuais, 2 modelos de comunicação 
entre núcleos são utilizados: 
– Memória Compartilhada (Mais utilizada em arquiteturas 
convencionais) 
– Passagem de Mensagens (Memória Distribuída) 
 
 
Memória Compartilhada Passagem de Mensagens 
Chapter 7 — Multicores, Multiprocessors, and Clusters — 9 
Memória Compartilhada 
 Shared memory multiprocessor 
Mesmo espaço de memória é compartilhado pelos 
diferentes processadores 
Comunicação é feita através de variáveis 
compartilhadas 
Comunicação com Memória Compartilhada 
 Variáveis compartilhadas contêm os dados que são 
comunicados entre um processador e outro 
 
 Processadores acessam variáveis via loads/stores 
 
 Acesso a estas variáveis deve ser controlado 
(sincronizado) 
– Uso de locks (semáforos) 
– Apenas um processador pode adquirir o lock em um 
determinado instante de tempo 
 
 
Chapter 7 — Multicores, Multiprocessors, and Clusters — 11 
Passagem de Mensagens 
 Message Passing 
Processadores compartilham dados enviando 
explicitamente os dados (mensagem) 
Comunicação é feita através de primitivas de 
comunicação (send e receive) 
Comunicação com Message Passing 
 Cada processador tem seu espaço de endereçamento 
privado 
 
 Processadores mandam mensagens utilizando esquema 
parecido ao de acessar um dispositivo de Entrada/Saída 
– Processador que aguarda mensagem é interrompido 
quando mensagem chega 
 
 Sincronização de acesso aos dados é feita pelo próprio 
programa 
– Programador é responsável para estabelecer os pontos de 
comunicação com as primitivas send e receive 
 
 
 
OpenMP 
 OpenMP( Open Multi-Processor) é uma API que dá 
suporte ao modelo de programação (comunicação) 
paralelo de memória compartilhada 
 
 Padronizada pelo consórcio OpenMP ARB(OpenMP 
Architecture Review Board) 
– AMD, Intel, Cray, HP, Oracle, Nvidia, NEC, etc 
– Roda em Linux, Windows, Mac OS X, Solaris, etc 
 
 Programação pode ser feita em C, C++ ou Fortran 
 
 
 
Camadas de SW e OpenMP 
Fonte: http://openmp.org/mp-documents/omp-hands-on-SC08.pdf 
Objetivos de OpenMP 
 Padronização da utilização do modelo de programação de 
memória compartilhada para diferentes plataformas 
 
 Provimento de uma camada de SW enxuta para programar 
plataformas com memória compartilhada 
– Poucas diretivas e funções para programação paralela 
 
 Facilidade de uso deste modelo de programação 
– Permite a paralelização incremental de um código sequencial 
com poucas diretivas 
 Portabilidade 
– API em C, C++ e Fortran 
– Maioria das plataformas no mercado aceitam Linux e 
Windows 
 
 
Suporte ao Modelo de Memória Compartilhada 
 Threads tem acesso a 
mesma memória global 
compartilhada 
 Dados podem ser 
compartilhados ou 
privados 
 Dados privados podem ser 
apenas acessados pelas 
threads que são as donas 
 Transferência de dados são 
transparentes ao 
programador 
 Sincronização acontece, 
mas boa parte é implícita 
Paralelismo Suportado por OpenMP 
 Paralelismo através de threads 
– Quantidade de threads não precisa ser igual a quantidade 
de cores 
 
 Programador consegue explicitar que partes do código 
são paralelizados 
– Pode explicitar vários níveis de paralelismo 
 
 Utiliza o modelo de execução paralela fork-join 
– Uma thread master pode criar várias threads para executar 
em paralelo 
– Quando todas as threads filhas completam as tarefas, 
sincronizam e terminam a execução, deixando a thread 
master 
 
 
 
Modelo Fork e Join 
Fonte: 
http://www.nic.uoregon.edu/iwomp2005/iwomp2005_tutorial_openmp_rvdp.pdf 
Estrutura Típica de Um Programa OpenMP 
Região Paralela 
Região 
Sequencial 
Pode vir seguido de mais 
regiões paralelas ou 
sequenciais 
Início 
Fim 
 Thread master (inicial,0) é 
onde a execução do 
programa se inicia e 
termina 
 Thread master cria um time 
(conjunto) de threads que 
vão executar algo em 
paralelo (fork) 
 Quando todos os threads 
de um time chegam ao final 
da região paralela, todos 
menos o master terminam 
(join) 
Componentes de OpenMP 
Fonte: 
http://www.nic.uoregon.edu/iwomp2005/iwomp2005_tutorial_openmp_rvdp.pdf 
Exemplo de OpenMP: Hello World Paralelo 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int nthreads, tid; 
 
/* Região Paralela, é dado um fork para um time de threads*/ 
#pragma omp parallel private(nthreads, tid) 
 { 
 /* Obtém o número da thread*/ 
 tid = omp_get_thread_num(); 
 printf("Hello World da thread = %d\n", tid); 
 
 /* Somente o thread master faz isto */ 
 if (tid == 0){ 
 nthreads = omp_get_num_threads(); 
 printf(“Quantidade de threads = %d\n", nthreads); 
 } 
 
 }/* No fim é dado um join */ 
} 
Diretiva que indica o começo 
de uma região paralela 
Função da API (omp.h) 
Saída da Execução do Hello World Paralelo 
4 threads criadas que 
executam o mesmo código 
Algumas Considerações Sobre a 
Paralelização em OpenMP 
 A quantidade de threads criadas pode ser configurada 
– Variáveis de ambiente, diretivas e chamadas de funções 
 A ordem de execução das threads é determinada pelo S.O 
- A cada execução a ordem pode mudar 
 Se threads diferentes acessam o mesmo dado, OpenMP não 
garante sozinho o acesso na ordem correta do dado 
– Programador deve explicitar onde haverá a sincronização 
 Pode haver diferentes níveis de paralelização (aninhamento) 
O Que Deve Ser Feito para Usar OpenMP? 
 No caso de C/C++ ter um compilador que possua a 
biblioteca libgomp 
– Importante ter também a biblioteca libpthread (Linux) ou 
libwinpthread (Windows) 
 
 Colocar no código um #include <omp.h> 
 
 Configurar a compilação e a link-edição 
– Colocar –fopenmp na opção de compilação do gcc 
Configurando a Compilação no CodeBlocks 
gcc deve compilar com esta 
opção 
Configurando a Link-Edição no CodeBlocks 
Deve incluir o caminho da 
biblioteca na link-edição 
Diretivas de OpenMP 
 Boa parte das construções de OpenMP são diretivas de 
compilação 
– Instruem a forma de execução do código como por exemplo: 
paralelização, serialização e sincronização 
– Se não colocar a opção de compilação –fopenmp, a diretiva é 
simplesmente ignorada 
 Uma região paralela sob a diretiva é delimitada por chaves 
{ } 
– Possibilidade de haver outras diretivas dentro das chaves 
 Forma Geral: 
 #pragma omp diretiva [claúsula[cláusula]] 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Exemplo de Diretiva Parallel : Hello World 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int nthreads, tid; 
 
#pragma omp parallel private(nthreads, tid) 
 { 
 
 tid = omp_get_thread_num(); 
 printf("Hello World da thread = %d\n", tid); 
 if (tid == 0){ 
 nthreads = omp_get_num_threads(); 
 printf(“Quantidade de threads = %d\n", nthreads); 
 } 
 
 } 
} 
Cláusula que indica que as 
threads terão suas próprias 
cópias de variáveis nthreads 
e tid 
Delimitação da região 
paralela 
Cláusulas OpenMP 
 Diretivas podem vir seguidas de cláusulas 
 
 Cláusulas são usadas para especificar informações 
adicionais à diretiva utilizada 
 
 Pode-se utilizar várias cláusulas em uma mesma 
instância de diretiva 
 
 Certas cláusulas só podem ser utilizadas para algumas 
diretivas específicas 
 
 
 
 
Tipos de Cláusulas para a Diretiva Parallel 
Exemplo de Diretiva Parallel : Hello World 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int nthreads, tid; 
 
#pragma omp parallel num_threads(5) private(nthreads, tid) 
 { 
 
 tid = omp_get_thread_num(); 
 
 printf("Hello World da thread = %d\n", tid); 
 if (tid == 0){ 
 nthreads = omp_get_num_threads(); 
 printf(“Quantidade de threads = %d\n", nthreads); 
 } 
 
 } 
} 
Cláusula que indica que as 
threads terão suas próprias 
cópias de variáveis nthreads 
e tid 
Cláusula que indica a 
quantidade de threads 
desejada 
Diretivas de Work-Sharing 
 
 O processamento é distribuído entre as threads, ou seja o 
trabalho é realizado conjuntamente pelas threads 
 
 Estas diretivas devem estar presentes dentro de regiões 
paralelas 
 
 Não podem criar novas threads dentro das áreas 
limitadas por estas diretivas 
 
 
 
 
 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Diretiva for 
 Serve para distribuir as iterações de um laço entre as 
threads 
– Naturalmente deve existir um laço logo após este tipo de 
diretiva 
– O laço deve ser do tipo for 
 A diretiva for não deve vir seguida de chaves { } 
 
 Assim como outras diretivas, eles permitem o uso de 
cláusulas 
 Forma Geral: 
 
#pragma omp for [claúsula[cláusula]] 
Exemplo de Diretiva for : Soma Matriz 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int A[2][2] = {{1,2},{3,4}}; 
 int B[2][2] = {{5,6},{7,8}}; 
 int C[2][2]; 
 int i,j,tid; 
 #pragma omp parallel private(j,tid) 
 { 
 #pragma omp for 
 for(i=0; i < 2; i++) { 
 for(j=0; j < 2; j++){ 
 tid = omp_get_thread_num(); 
 C[i][j] = A[i][j] + B[i][j]; 
 printf("thread %d calculou \ 
 C[%d][%d]=%d\n",tid,i,j,C[i][j]); 
 } 
 } 
 } 
} 
Variável de controle do loop 
(i) é privada por padrão, 
haverá uma thread alocada 
para calcular o valor de cada 
linha 
Importante para que 
uma thread não interfira 
no valor de j de outra 
thread 
Saída da Execução da Soma Matriz 
Combinando parallel e for 
São equivalentes 
 As duas diretivas podem ser combinadas na mesma linha 
– Naturalmente deve existir um laço logo após este tipo de 
diretiva 
– O laço deve ser do tipo for 
 
 
Exemplo de parallel e for : Soma Matriz 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int A[2][2] = {{1,2},{3,4}}; 
 int B[2][2] = {{5,6},{7,8}}; 
 int C[2][2]; 
 int i,j,tid; 
 #pragma omp parallel for private(j,tid) 
 for(i=0; i < 2; i++) { 
 for(j=0; j < 2; j++){ 
 tid = omp_get_thread_num(); 
 C[i][j] = A[i][j] + B[i][j]; 
 printf("thread %d calculou \ 
 C[%d][%d]=%d\n",tid,i,j,C[i][j]); 
 } 
 } 
 
} 
Não precisa de chaves para 
delimitar área 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Diretivas sections e section 
 A diretiva sections serve para listar blocos de código que 
serão processados por threads separadas 
– Cada bloco deve vir precedido da diretiva section 
 
 As diretivas sections e section são delimitadas por chaves 
{ } 
 
 Caso uma thread seja muito rápida, ela pode executar 
mais de uma section 
– Ou ainda, se o número de threads definido pelo programador 
for menor do que o número de section 
 
Formas Gerais de sections e section 
#pragma omp sections [claúsula[cláusula]] 
{ 
 #pragma omp section 
 {código} 
 #pragma omp section 
 {código} 
} 
Exemplo de sections : Quantidade de Pares 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
#define N 1000 
int main(){ 
 int matriz[N]; 
 int i,tid, valorInicial = 1, contaPar = 0; 
//Inicializando a matriz 
 for (i = 0; i < N; i++) { 
 matriz[i] = valorInicial; 
 valorInicial += 3; 
 } 
Exemplo de sections : Quantidade de Pares 
 #pragma omp parallel private(i,tid) num_threads(2){ 
 #pragma omp sections reduction(+:contaPar) 
 { 
 #pragma omp section 
 { 
 for(i = 0; i < N/2; i++) 
 if (matriz[i] % 2 == 0) 
 contaPar++; 
 } 
 #pragma omp section 
 { 
 for(i = N/2; i < N; i++) 
 if (matriz[i] % 2 == 0) 
 contaPar++; 
 } 
 } 
 } 
 printf("\nQuantidade de pares = %d\n",contaPar); 
} 
Cláusula que garante 
que os valores das 
cópias locais de 
contaPar sejam 
depois combinadas 
em um único valor 
global 
Sincronização 
 Em um ambiente onde o processamento é paralelo, muitas 
vezes precisamos de sincronização para garantir a 
corretude da execução do código 
– Evitar “race conditions” 
 
 Algumas situações onde sincronização se faz necessário: 
– Acesso a variáveis compartilhadas, onde toda thread deve 
enxergar o valor atualizado da variável 
– Execução ordenada de trechos de código 
 
 OpenMP possui várias diretivas que possibilitam a 
sincronização entre threads diferentes 
 Devem ser usadas com cautela, pois sincronização é 
custosa e afeta o desempenho 
 
Formas de Sincronização 
 As duas formas mais comuns de sincronização são: 
 
Barreira (Barrier): cada thread 
espera em um ponto de 
execução (barreira) até que as 
outras threads cheguem 
Exclusão Mútua : Define um 
bloco de código (região crítica) 
onde apenas uma thread pode 
executar em um instante de 
tempo 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Quando Usar Barreiras (Barriers) 
Suponham que tivéssemos estes dois 
trechos de código e que o loop estivesse 
sendo executado em paralelo sobre i 
if (num_thread % 2 == 0) { 
 fator1 = fator1 + 1; 
} else { 
 fator2 = fator2 + 1; 
} 
for (i = 0; i < N; i++) 
 a[i] = i * fator2 * fator1; 
Dependência de dados pode gerar erros 
Usando Barreiras (Barriers) 
for (i = 0; i < N; i++) 
 a[i] = a[i]* fator1 * fator2 
Espera! 
Todas as threads precisam saber o valor de 
fator, antes de proceder ao loop 
Barreira 
Cada thread espera no ponto da barreira e só 
continua quando todas as threads tiverem 
atingido este ponto 
if (num_thread % 2 == 0) { 
 fator1 = fator1 + 1; 
} else { 
 fator2 = fator2 + 1; 
} 
Diretiva barrier 
 Serve para colocar uma barreira de sincronização 
– Cada thread deve esperar as outras quando encontrada esta 
diretiva 
 Forma Geral: 
 
#pragma omp barrier 
Exemplo de barrier 
#include <omp.h> 
#define N 20 
int main(){ 
 int i, num_thread,a[N], fator1 =0,fator2=0; 
 
 #pragma omp parallel private(num_thread)shared(fator1,fator2) 
 { 
 num_thread = omp_get_thread_num(); 
 if (num_thread % 2 == 0) 
 fator1++; 
 else 
 fator2++; 
 #pragma omp barrier 
 
 #pragma omp for 
 for(i=0; i < N; i++) { 
 a[i] = i * fator1 * fator2; 
 printf("a[%d] = %d ",i,a[i]); 
 
 } 
 } 
Cláusula opcional que 
declara que fator1 e 
fator2 são 
compartilhadas entre 
threads 
Todas as threads devem 
chegar neste ponto para 
proceder ao resto do 
código 
Barreiras Implícitas 
 Nem sempre precisamos da diretiva barrier para 
especificar uma barreira 
 
 Em várias situações há barreiras implícitas consideradas 
pelo compilador: 
– Fim de regiões paralelas 
– Construções work-sharing como for possuem barreiras 
implícitas ao final do loop, excetuando-se quando se coloca a 
cláusula nowait na diretiva 
 
#pragma omp for 
for (i = 0; i < N; i++) { 
 d[i] = a[i] + b[i]; 
} 
Barreira 
implícita 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Diretiva critical 
 Serve para colocar delimitar uma região crítica 
– Só uma thread por vez pode entrar na região crítica 
– As demais esperam para entrar (barreira implícita) 
 Bastante útil para atualização de variáveis compartilhadas 
– Garante a consistência de dados 
 Forma Geral: 
 
#pragma omp critical [name] 
{código} 
 name é opcional, mas regiões críticas com o mesmo nome 
são tratados como a mesma região crítica 
 
Exemplo de critical 
#include <omp.h> 
int main() { 
 int fator1 =0; 
 int tid; 
 #pragma omp parallel num_threads(5) private(tid) shared(fator1) 
 { 
 tid = omp_get_thread_num(); 
 
 #pragma omp critical 
 { 
 fator1++; 
 printf("\nThread %d executando\n",tid); 
 printf("\nValor de fator1 = %d\n",fator1); 
 
 } 
 
 } 
 
 
 return 0; 
} 
Variável compartilhada 
entre threads 
Garante a consistência 
na atualização do dado 
e fluxo correto de 
execução do código 
Saída do Programa SEM critical 
Não gera o resultado 
esperado 
Saída do Programa COM critical 
Tipos de Diretivas de OpenMP 
 Básica de Paralelismo 
– parallel 
 Divisão de dados/tarefas entre threads (work-sharing) 
– for (loop) 
– section 
– single 
– task 
 Sincronização 
– barrier 
– master 
– critical 
– atomic 
– ordered 
 
Diretivas master e single 
 Diretiva single especifica que somente uma thread executa 
o que está delimitada pela diretiva 
– Escolha da thread é aleatória 
– Restante das threads esperam enquanto a thread termina a 
execução do código delimitado (barreira implícita), exceto 
quando há uma cláusula nowait 
 Diretiva master especifica que somente a thread master 
executa o código delimitado pela diretiva 
– Outras threads podem continuar a executar o restante do 
código (não há barreira implícita) 
 Formas Gerais: 
 
#pragma omp master 
{código} 
#pragma omp single[cláusulas] 
{código} 
Comportamento de single 
Fonte: 
http://www.nic.uoregon.edu/iwomp2005/iwomp2005_tutorial_openmp_rvdp.pdf 
Funções da API de OpenMP 
 OpenMP oferece várias funções que 
podem ser chamadas 
– Para controlar e ver o status do 
ambiente de execução paralela 
– Pode-se configurar a quantidade de 
threads dinamicamente além de 
sincronizar acesso a regiões críticas 
 
 Estas funções tem precedência sobre 
as respectivas variáveis de ambiente 
 
Sumário das Funções na API 
Nome Funcionalidade 
omp_set_num_threads Estabelece a quantidade de threads 
omp_get_num_threads Retorna a quantidade de threads 
omp_get_thread_num Retorna o id da thread 
omp_get_num_procs Retorna a quantidade de processadores 
omp_get_wtime Retorna o tempo do “wall clock” 
omp_get_wtick Retorna o número de segundos entre os 
ticks do clock 
omp_init_lock Associa um lock (semáforo) com uma 
variável 
omp_destroy_lock Desassocia um lock de uma variável 
 
omp_set_lock Adquire o semáforo, senão bloqueia 
omp_unset_lock Libera o semáforo 
omp_test_lock Testa e adquire o semáforo 
Exemplo de Utilização das Funções da API 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int A[4][2] = {{1,2},{3,4},{5,6},{7,8}};int B[4][2] = {{5,6},{7,8},{9,10},{11,12}}; 
 int C[4][2]; 
 int i,j,tid; 
 omp_set_num_threads(2); 
 #pragma omp parallel for private(j) 
 for(i=0; i < 4; i++) { 
 for(j=0; j < 2; j++){ 
 tid = omp_get_thread_num(); 
 C[i][j] = A[i][j] + B[i][j]; 
 printf("thread %d calculou \ 
 C[%d][%d]=%d\n",tid,i,j,C[i][j]); 
 } 
 } 
 
} 
Estabelece 2 threads 
Retorna o id da thread 
Saída do Programa com 2 threads 
Precedência de Diretivas 
#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
int main(){ 
 int A[4][2] = {{1,2},{3,4},{5,6},{7,8}}; 
 int B[4][2] = {{5,6},{7,8},{9,10},{11,12}}; 
 int C[4][2]; 
 int i,j,tid; 
 omp_set_num_threads(2); 
 #pragma omp parallel for private(j) num_threads(4) 
 for(i=0; i < 4; i++) { 
 for(j=0; j < 2; j++){ 
 tid = omp_get_thread_num(); 
 C[i][j] = A[i][j] + B[i][j]; 
 printf("thread %d calculou \ 
 C[%d][%d]=%d\n",tid,i,j,C[i][j]); 
 } 
 } 
 
} 
Estabelece 2 threads 
Neste caso, a 
precedência é da 
diretiva com 4 threads 
Saída do Programa com 4 threads 
Funções de Lock 
 Locks oferecem uma flexibilidade 
maior em relação a regiões críticas 
(diretiva critical) 
– Permitem que as threads que não 
adquiriram o lock façam outras 
coisas enquanto esperam 
 
 Variáveis de lock devem ser 
manipuladas através das funções 
apropriadas de OpenMP 
 Locks devem ser inicializados 
– Comportamento indefinido caso 
não sejam inicializados 
 
Exemplo de Utilização de Funções de Locks 
#include <omp.h> 
#include <windows.h> 
int main(){ 
 int tid; 
 omp_lock_t lck; 
 omp_init_lock(&lck); 
 omp_set_num_threads(3); 
 #pragma omp parallel shared(lck) private(tid) 
 { 
 tid = omp_get_thread_num(); 
 while (!omp_test_lock(&lck)) { 
 
 printf("\nThread %d esperando lock \n",tid); 
 Sleep(3); 
 } 
 printf("\nThread %d adquiriu lock\n",tid); 
 Sleep(5); 
 printf("\nThread %d liberou lock\n",tid); 
 omp_unset_lock(&lck); 
 } 
} 
Lock deve ser inicializado 
Testa e adquire o lock 
Enquanto não adquire, 
faz outra coisa 
Libera o lock 
Saída do Programa com Locks 
Thread 0 adquiriu o lock, e 
threads 1 e 2 fazem outra 
coisa enquanto esperam 
Algumas Variáveis de Ambiente OpenMP 
Nome Funcionalidade 
OMP_NUM_THREADS Estabelece a quantidade de threads 
OMP_DYNAMIC Habilita/Desabilita se a quantidade de 
threads pode ser ajustada dinamicamente 
pelo ambiente de execução 
OMP_NESTED Habilita/Desabilita o aninhamento de 
paralelismo 
 Existem muitas variáveis de ambiente que podem modificar 
o ambiente de execução 
 Quando há uma cláusula de diretiva ou função da API que 
tem a mesma funcionalidade, estes tem maior precedência 
sobre as variáveis de ambiente 
– Cláusulas > Funções > Variáveis de ambiente 
 Alguns exemplos de variáveis de ambiente:

Continue navegando