Vous êtes sur la page 1sur 11

Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

developerWorks Brasil Itens Tcnicos Software livre Biblioteca tcnica

Aprendendo a usar a estrutura OpenMP com GCC


A estrutura Open Multiprocessing (OpenMP) uma especificao extremamente eficiente, que ajuda a aproveitar os
benefcios de sistemas com mais de um processador com aplicativos C, C++ e Fortran. Este artigo explica como usar
os recursos do OpenMP em cdigo C++ e traz exemplos que podem ajudar o leitor a comear a usar o OpenMP.

Arpan Sen trabalha como engenheiro chefe no desenvolvimento de software no segmento de mercado de automao de design eletrnico.
Ele trabalhou em vrias verses do UNIX, incluindo Solaris, SunOS, HP-UX e IRIX, alm de Linux e Microsoft Windows por vrios anos.
Possui um grande interesse por tcnicas de otimizao do desempenho de software, teoria de grfico e computao paralela. Arpan possui
ps-doutorado em sistemas de software. possvel entrar em contato com ele atravs do email arpansen@gmail.com

08/Out/2012

A estrutura OpenMP uma maneira eficiente de fazer programao


simultnea em C, C++ e Fortran. O GNU Compiler Collection (GCC) verso
4.2 tem suporte para o padro OpenMP 2.5, enquanto o 4.4 tem suporte Desenvolva e implemente
para o padro OpenMP 3, mais recente. Outros compiladores, como o seu prximo aplicativo na
plataforma de cloud do
Microsoft Visual Studio, tambm tm suporte para OpenMP. Neste artigo, IBM Bluemix.
voc aprender a usar pragmas de compilador da estrutura OpenMP, a
Comece seu
encontrar suporte para algumas das interfaces de programao de trial gratuito
aplicativos (APIs) que ela fornece e a test-la com alguns algoritmos
paralelos. Este artigo usa GCC 4.2 como o compilador preferencial.

O seu primeiro programa de OpenMP Introduo


Um timo recurso do OpenMP que no
Vamos comear com um simples programa para exibir a frase
necessrio nada alm da instalao
Hello, World!, que inclui um pragma adicional. A Listagem 1 mostra padro do GCC. Programas com
o cdigo. OpenMP devem ser compilados com a
opo -fopenmp.
Lista 1. Hello World com OpenMP
#include <iostream>
int main()
{
#pragma omp parallel
{
std::cout << "Hello World!\n";
}
}

Quando o cdigo da Listagem 1 compilado e executado com g++, uma nica mensagem Hello, World!
deve ser exibida no console. Agora, recompile o cdigo com a opo -fopenmp. A Listagem 2 mostra a
sada.
Lista 2. Compilando e executando o cdigo com o comando -fopenmp
tintin$ g++ test1.cpp -fopenmp
tintin$ ./a.out
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

1 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

O que aconteceu? A mgica de #pragma omp parallel funciona apenas quando a opo -fopenmp
do compilador especificada. Internamente, durante a compilao, o GCC gera o cdigo para criar o
mximo nmero de encadeamentos possvel no tempo de execuo, com base no hardware e na
configurao do sistema operacional. A rotina de incio de cada encadeamento o cdigo no bloco aps
o pragma. Esse comportamento chama-se paralelizao implcita. Na sua essncia, OpenMP consiste
em um conjunto de pragmas eficientes que livram o desenvolvedor da obrigao de incluir muitos
cdigos repetidos. (Para comparao, confira como seria uma implementao do que voc acaba de
fazer em [pthreads], os encadeamentos da Interface de Sistema Operacional Porttil (POSIX).) Como eu
estou usando um computador com um processador Intel Core i7, com quatro ncleos fsicos e dois
ncleos lgicos por ncleo fsico, a sada da Listagem 2 parece adequada (8 encadeamentos = 8
ncleos lgicos).

Agora vamos ver mais detalhes sobre pragmas paralelos.

Brincando com OpenMP paralelo


Para controlar o nmero de encadeamentos, basta usar o argumento num_threads do pragma. Aqui
est novamente o cdigo da Listagem 1 com o nmero de encadeamentos disponveis especificados
como 5 (como mostra a Listagem 3).
Lista 3. Controlando o nmero de encadeamentos com num_threads
#include <iostream>
int main()
{
#pragma omp parallel num_threads(5)
{
std::cout << "Hello World!\n";
}
}

Em vez da abordagem num_threads, aqui est uma alternativa para alterar o nmero de
encadeamentos executando o cdigo. Essa tambm a primeira API do OpenMP que voc ir usar:
omp_set_num_threads. Essa funo definida no arquivo de cabealho omp.h. No necessrio
vincular outras bibliotecas para que o cdigo na Listagem 4 funcione apenas -fopenmp.
Lista 4. Uso de omp_set_num_threads para ajuste fino da criao de encadeamentos
#include <omp.h>
#include <iostream>
int main()
{
omp_set_num_threads(5);
#pragma omp parallel
{
std::cout << "Hello World!\n";
}
}

O OpenMP tambm usa variveis de ambiente externas para controlar seu comportamento. possvel
alterar o cdigo na Listagem 2 para imprimir apenas Hello World! seis vezes, definindo a varivel
OMP_NUM_THREADS para 6. A Listagem 5 mostra a execuo.

Lista 5. Usando variveis de ambiente para ajustar o comportamento do OpenMP


tintin$ export OMP_NUM_THREADS=6
tintin$ ./a.out
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

Voc j descobriu todas as trs facetas do OpenMP: pragmas do compilador, APIs do tempo de

2 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

execuo e variveis de ambiente. O que acontece se usarmos a varivel de ambiente e a API do tempo
de execuo? A API tem precedncia mais alta.

Um exemplo prtico
O OpenMP usa tcnicas de paralelizao implcita, e possvel usar pragmas, funes explcitas e
variveis de ambiente para instruir o compilador. Vamos examinar um exemplo no qual OpenMP pode
ser de grande ajuda. Considere o cdigo da Listagem 6.
Lista 6. Processamento sequencial em um loop for
int main( )
{
int a[1000000], b[1000000];
// ... some initialization code for populating arrays a and b;
int c[1000000];
for (int i = 0; i < 1000000; ++i)
c[i] = a[i] * b[i] + a[i-1] * b[i+1];
// ... now do some processing with array c
}

Claramente, possvel dividir o loop for e executar em mais de um ncleo. O clculo de qualquer c[k]
independente dos outros elementos do array c. A Listagem 7 mostra como o OpenMP ajuda a fazer
isso.
Lista 7. Processamento paralelo em um loop for com o pragma parallel for
int main( )
{
int a[1000000], b[1000000];
// ... some initialization code for populating arrays a and b;
int c[1000000];
#pragma omp parallel for
for (int i = 0; i < 1000000; ++i)
c[i] = a[i] * b[i] + a[i-1] * b[i+1];
// ... now do some processing with array c
}

O pragma parallel for ajuda a dividir a carga de trabalho do loop for em mais de um
encadeamento. Cada encadeamento pode ser executado em um ncleo diferente, o que reduz
significativamente o tempo total de clculo. A Listagem 8 prova isso.
Lista 8. Entendendo omp_get_wtime
#include <omp.h>
#include <math.h>
#include <time.h>
#include <iostream>

int main(int argc, char *argv[]) {


int i, nthreads;
clock_t clock_timer;
double wall_timer;
double c[1000000];
for (nthreads = 1; nthreads <=8; ++nthreads) {
clock_timer = clock();
wall_timer = omp_get_wtime();
#pragma omp parallel for private(i) num_threads(nthreads)
for (i = 0; i < 1000000; i++)
c[i] = sqrt(i * 4 + i * 2 + i);
std::cout << "threads: " << nthreads << " time on clock(): " <<
(double) (clock() - clock_timer) / CLOCKS_PER_SEC
<< " time on wall: " << omp_get_wtime() - wall_timer << "\n";
}
}

Na Listagem 8, o cdigo aumenta continuamente o nmero de encadeamentos para medir quanto tempo
o loop for interno leva para ser executado. A API omp_get_wtime retorna o tempo em segundos a
partir de algum ponto arbitrrio, porm consistente. Portanto, omp_get_wtime() - wall_timer
retorna o tempo real para execuo do loop for. A chamada do sistema clock() usada para estimar
o tempo de uso do processador para todo o programa ou seja, o tempo de uso de processador dos
encadeamentos individuais somado antes de a chamada informar o nmero final. No meu computador
Intel Core i7, a Listagem 9 mostra as informaes exibidas.

3 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

Lista 9. Nmeros para a execuo do loop for interno


threads: 1 time on clock(): 0.015229 time on wall: 0.0152249
threads: 2 time on clock(): 0.014221 time on wall: 0.00618792
threads: 3 time on clock(): 0.014541 time on wall: 0.00444412
threads: 4 time on clock(): 0.014666 time on wall: 0.00440478
threads: 5 time on clock(): 0.01594 time on wall: 0.00359988
threads: 6 time on clock(): 0.015069 time on wall: 0.00303698
threads: 7 time on clock(): 0.016365 time on wall: 0.00258303
threads: 8 time on clock(): 0.01678 time on wall: 0.00237703

Embora o tempo de processador seja quase o mesmo em todas as execues (como deveriam ser,
exceto por algum tempo adicional para criar os encadeamentos e o comutador de contexto), o que nos
interessa o tempo real. Ele reduzido progressivamente medida que o nmero de encadeamentos
aumenta, dando a entender que os dados esto sendo calculados pelos ncleos em paralelo. Uma nota
final sobre a sintaxe do pragma: #pragma parallel for private(i) significa que a varivel de loop
i deve ser tratada como um armazenamento local de encadeamento, com cada encadeamento tendo
uma cpia da varivel. A varivel local do encadeamento no inicializada.

Sees crticas com OpenMP


Voc no achou que o OpenMP ia cuidar das sees crticas sozinhos, achou? Claro, no necessrio
criar explicitamente uma mutex, mas ainda preciso especificar a seo crtica. Aqui est a sintaxe:
#pragma omp critical (optional section name)
{
// no 2 threads can execute this code block concurrently
}

O cdigo que vem depois de pragma omp critical pode apenas ser executado por um nico
encadeamento em um dado momento. Alm disso, optional section name um identificador global,
e dois encadeamentos no podem executar sees crticas com o mesmo identificador global ao mesmo
tempo. Considere o cdigo da Listagem 10.
Lista 10. Mais de uma seo crtica com o mesmo nome
#pragma omp critical (section1)
{
myhashtable.insert("key1", "value1");
}
// ... other code follows
#pragma omp critical (section1)
{
myhashtable.insert("key2", "value2");
}

Com base nesse cdigo, podemos supor com segurana que as duas inseres de hashtable nunca
acontecero simultaneamente, pois os nomes da seo crtica so os mesmos. Isso um pouco
diferente da maneira com que voc est acostumado a lidar com sees crticas usando pthreads, que
so, em grande parte, caracterizadas pelo uso (ou abuso) de bloqueios.

Bloqueios e mutexes com OpenMP


Curiosamente, OpenMP tem suas prprias verses de mutexes (ento no se trata apenas de pragmas).
Seja bem-vindo ao omp_lock_t, definido como parte do arquivo de cabealho omp.h. As operaes de
mutex no estilo pthread so iguais at os nomes das APIs so semelhantes. H cinco APIs que o
desenvolvedor deve conhecer:

omp_init_lock: Essa deve ser a primeira API a acessar omp_lock_t. usada para inicializao.
Observe que, logo aps a inicializao, considera-se que o bloqueio no foi definido.
omp_destroy_lock: Essa API destri o bloqueio. O bloqueio deve estar no estado no definido para
que essa API seja chamada, o que significa que no possvel chamar omp_set_lock e depois fazer

4 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

uma chamada para destruir o bloqueio.


omp_set_lock: Essa API define omp_lock_t ou seja, o mutex adquirido. Se um encadeamento
no puder definir o bloqueio, ele continuar a aguardar at que possa.

omp_test_lock: Essa API tenta bloquear se o bloqueio estiver disponvel, e retorna 1 em caso de
sucesso e 0 em caso de fracasso. Essa uma API sem bloqueio ou seja, essa funo no faz o
encadeamento aguardar para definir o bloqueio.

omp_unset_lock: Essa API libera o bloqueio.

A Listagem 11 mostra uma implementao trivial de uma fila legada de um encadeamento estendida
para lidar com multiencadeamento usando bloqueios do OpenMP. Observe que isso pode no ser o ideal
para todas as situaes. O exemplo apenas uma ilustrao rpida.
Lista 11. Usando OpenMP para estender uma fila de um encadeamento
#include <openmp.h>
#include "myqueue.h"

class omp_q : public myqueue<int> {


public:
typedef myqueue<int> base;
omp_q( ) {
omp_init_lock(&lock);
}
~omp_q() {
omp_destroy_lock(&lock);
}
bool push(const int& value) {
omp_set_lock(&lock);
bool result = this->base::push(value);
omp_unset_lock(&lock);
return result;
}
bool trypush(const int& value)
{
bool result = omp_test_lock(&lock);
if (result) {
result = result && this->base::push(value);
omp_unset_lock(&lock);
}
return result;
}
// likewise for pop
private:
omp_lock_t lock;
};

Bloqueios aninhados
Outros tipos de bloqueios fornecidos pelo OpenMP so variaes do omp_nest_lock_t. So
semelhantes a omp_lock_t, com a vantagem de que podem ser bloqueados vrias vezes pelo
encadeamento que j est realizando o bloqueio. Cada vez que o bloqueio aninhado readquirido pelo
encadeamento que o contm usando omp_set_nest_lock, um contador interno aumentado. O
bloqueio liberado pelo encadeamento quando uma ou mais chamadas para omp_unset_nest_lock
finalmente reconfiguram o contador do bloqueio interno para 0. Aqui esto as APIs usadas para
omp_nest_lock_t:

omp_init_nest_lock(omp_nest_lock_t* ): Essa API inicializa o contador de aninhamento


interno para 0.

omp_destroy_nest_lock(omp_nest_lock_t* ): Essa API destri o bloqueio. Um chamado para


essa API em um bloqueio com contagem de aninhamento interno diferente de zero resulta em
comportamento indefinido.
omp_set_nest_lock(omp_nest_lock_t* ): Essa API semelhante a omp_set_lock, mas o

5 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

encadeamento pode chamar a funo mais de uma vez enquanto mantm o bloqueio.
omp_test_nest_lock(omp_nest_lock_t* ): Essa API uma verso sem bloqueio de
omp_set_nest_lock.

omp_unset_nest_lock(omp_nest_lock_t* ): Essa API libera o bloqueio quando o contador


interno 0. Do contrrio, o contador diminudo com cada chamada para esse mtodo.

Controle de baixa granularidade sobre a execuo de tarefas


Voc j viu que todos os encadeamentos executam o bloco de cdigos aps pragma omp parallel
em paralelo. possvel categorizar ainda mais o cdigo dentro desse bloco para ser executado por
encadeamentos selecionados. Considere o cdigo da Listagem 12.
Lista 12. Aprendendo a usar o pragma de sees paralelas
int main( )
{
#pragma omp parallel
{
cout << "All threads run this\n";
#pragma omp sections
{
#pragma omp section
{
cout << "This executes in parallel\n";
}
#pragma omp section
{
cout << "Sequential statement 1\n";
cout << "This always executes after statement 1\n";
}
#pragma omp section
{
cout << "This also executes in parallel\n";
}
}
}
}

O cdigo que vem antes de pragma omp sections, mas logo aps pragma omp parallel,
executado por todos os encadeamentos em paralelo. O bloco que vem depois de pragma omp
sections classificado ainda mais em subsees individuais usando pragma omp section. Cada
bloco pragma omp section est disponvel para ser executado por um encadeamento individual. No
entanto, as instrues individuais dentro do bloco de seo so sempre executadas em sequncia. A
Listagem 13 mostra a sada do cdigo da Listagem 12.
Lista 13. Sada do cdigo da Listagem 12
tintin$ ./a.out
All threads run this
All threads run this
All threads run this
All threads run this
All threads run this
All threads run this
All threads run this
All threads run this
This executes in parallel
Sequential statement 1
This also executes in parallel
This always executes after statement 1

Na Listagem 13, temos novamente oito encadeamento sendo criados inicialmente. Desses oito
encadeamentos, h trabalho suficiente para apenas trs deles no bloco pragma omp sections. Na
segunda seo, especificamos a ordem na qual as instrues de impresso so executadas. esse o
motivo para usar o pragma sections. Se for necessrio, possvel especificar a ordem dos blocos de
cdigos.

6 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

Entendendo as diretivas firstprivate e lastprivate em conjunto


com loops paralelos
Anteriormente, voc viu o uso de private para declarar o armazenamento local de encadeamentos.
Ento como inicializar as variveis locais de encadeamento? Talvez sincroniz-las com a varivel no
encadeamento principal antes de continuar com as operaes? nessa situao que a diretiva
firstprivate til.

A diretiva firstprivate
Ao usar firstprivate(variable), possvel inicializar a varivel em um encadeamento para o valor
que ela tinha em main. Considere o cdigo da Listagem 14.
Lista 14. Usando a varivel local do encadeamento que no est sincronizada com o
encadeamento principal
#include <stdio.h>
#include <omp.h>

int main()
{
int idx = 100;
#pragma omp parallel private(idx)
{
printf("In thread %d idx = %d\n", omp_get_thread_num(), idx);
}
}

Aqui est a sada que eu recebi. Seus resultados podem ser diferentes.
In thread 1 idx = 1
In thread 5 idx = 1
In thread 6 idx = 1
In thread 0 idx = 0
In thread 4 idx = 1
In thread 7 idx = 1
In thread 2 idx = 1
In thread 3 idx = 1

A Listagem 15 mostra o cdigo com a diretiva firstprivate. A sada, como era esperado, imprime idx
inicializado para 100 em todos os encadeamentos.
Lista 15. Usando a diretiva firstprivate para inicializar as variveis locais do encadeamento
#include <stdio.h>
#include <omp.h>

int main()
{
int idx = 100;
#pragma omp parallel firstprivate(idx)
{
printf("In thread %d idx = %d\n", omp_get_thread_num(), idx);
}
}

Observe tambm que usamos o mtodo omp_get_thread_num( ) para acessar o ID de um


encadeamento. Isso diferente do ID de encadeamento que o comando top do Linux mostra. Esse
esquema apenas uma maneira de o OpenMP acompanhar as contagens de encadeamento. Outra
nota sobre a diretiva firstprivate, caso voc queira us-la no seu cdigo C++: a varivel que a
diretiva firstprivate usa um construtor de cpias para inicializar-se a partir da varivel do
encadeamento principal. Portanto, ter um construtor de cpias privado em uma classe invariavelmente
resulta em coisas ruins. Vamos agora passar para a diretiva lastprivate, que , de certa forma, o
reverso da moeda.

A diretiva lastprivate
Em vez de inicializar uma varivel local de encadeamento com os dados do encadeamento principal,

7 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

agora queremos sincronizar os dados do encadeamento principal com aqueles gerados pelo ltimo loop
executado. O cdigo na Listagem 16 executa um loop for paralelo.
Lista 16. Usando um loop for paralelo sem sincronizao de dados com o encadeamento
principal
#include <stdio.h>
#include <omp.h>

int main()
{
int idx = 100;
int main_var = 2120;

#pragma omp parallel for private(idx)


for (idx = 0; idx < 12; ++idx)
{
main_var = idx * idx;
printf("In thread %d idx = %d main_var = %d\n",
omp_get_thread_num(), idx, main_var);
}
printf("Back in main thread with main_var = %d\n", main_var);
}

No meu computador de desenvolvimento, com oito ncleos, o OpenMP cria seis encadeamentos para o
bloco parallel for. Cada encadeamento, por sua vez, responsvel por duas iteraes do loop. O
valor final de main_var depende do ltimo encadeamento executado e, portanto, o valor de idx nesse
encadeamento. Em outras palavras, o valor de main_var no depende do ltimo valor de idx, mas no
valor de idx no encadeamento executado por ltimo. O cdigo na Listagem 17 mostra isso.
Lista 17. O valor de main_var depende do ltimo encadeamento executado
In thread 4 idx = 8 main_var = 64
In thread 2 idx = 4 main_var = 16
In thread 5 idx = 10 main_var = 100
In thread 3 idx = 6 main_var = 36
In thread 0 idx = 0 main_var = 0
In thread 1 idx = 2 main_var = 4
In thread 4 idx = 9 main_var = 81
In thread 2 idx = 5 main_var = 25
In thread 5 idx = 11 main_var = 121
In thread 3 idx = 7 main_var = 49
In thread 0 idx = 1 main_var = 1
In thread 1 idx = 3 main_var = 9
Back in main thread with main_var = 9

Execute o cdigo na Listagem 17 algumas vezes para convencer-se de que o valor de main_var no
encadeamento principal sempre depende do valor de idx no ltimo encadeamento executado. E se
quisermos sincronizar o valor do encadeamento principal com o valor final de idx no loop? nessa
parte que aqui que entra a diretiva lastprivate, como mostra a Listagem 18. Assim como no cdigo
da Listagem 17, execute o cdigo da Listagem 18 algumas vezes para convencer-se de que o valor final
de main_var no encadeamento principal 121 (idx o valor do final do contador de loop).
Lista 18. Usando a diretiva lastprivate para sincronizao
#include <stdio.h>
#include <omp.h>

int main()
{
int idx = 100;
int main_var = 2120;

#pragma omp parallel for private(idx) lastprivate(main_var)


for (idx = 0; idx < 12; ++idx)
{
main_var = idx * idx;
printf("In thread %d idx = %d main_var = %d\n",
omp_get_thread_num(), idx, main_var);
}
printf("Back in main thread with main_var = %d\n", main_var);
}

A Listagem 19 mostra a sada da Listagem 18.


Lista 19. Sada do cdigo na Listagem 18 (observe que o valor de main_var always 121 no

8 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

encadeamento principal)
In thread 3 idx = 6 main_var = 36
In thread 2 idx = 4 main_var = 16
In thread 1 idx = 2 main_var = 4
In thread 4 idx = 8 main_var = 64
In thread 5 idx = 10 main_var = 100
In thread 3 idx = 7 main_var = 49
In thread 0 idx = 0 main_var = 0
In thread 2 idx = 5 main_var = 25
In thread 1 idx = 3 main_var = 9
In thread 4 idx = 9 main_var = 81
In thread 5 idx = 11 main_var = 121
In thread 0 idx = 1 main_var = 1
Back in main thread with main_var = 121

Uma observao final: para que um objeto C++ tenha suporte para o operador lastprivate,
necessrio que o mtodo operator= esteja disponvel publicamente na classe correspondente.

Ordenao por intercalao (merge sort) com OpenMP


Vamos observar um exemplo prtico no qual o conhecimento sobre OpenMP ajuda a economizar tempo
de execuo. Essa no uma verso muito otimizada do algoritmo merge sort, mas o suficiente
para mostrar as vantagens de usar OpenMP no cdigo. A Listagem 20 mostra o cdigo de exemplo.
Lista 20. Ordenao por intercalao usando OpenMP
#include <omp.h>
#include <vector>
#include <iostream>
using namespace std;

vector<long> merge(const vector<long>& left, const vector<long>& right)


{
vector<long> result;
unsigned left_it = 0, right_it = 0;

while(left_it < left.size() && right_it < right.size())


{
if(left[left_it] < right[right_it])
{
result.push_back(left[left_it]);
left_it++;
}
else
{
result.push_back(right[right_it]);
right_it++;
}
}

// Push the remaining data from both vectors onto the resultant
while(left_it < left.size())
{
result.push_back(left[left_it]);
left_it++;
}

while(right_it < right.size())


{
result.push_back(right[right_it]);
right_it++;
}

return result;
}

vector<long> mergesort(vector<long>& vec, int threads)


{
// Termination condition: List is completely sorted if it
// only contains a single element.
if(vec.size() == 1)
{
return vec;
}

// Determine the location of the middle element in the vector


std::vector<long>::iterator middle = vec.begin() + (vec.size() / 2);

vector<long> left(vec.begin(), middle);


vector<long> right(middle, vec.end());

// Perform a merge sort on the two smaller vectors

if (threads > 1)
{
#pragma omp parallel sections
{
#pragma omp section
{

9 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

left = mergesort(left, threads/2);


}
#pragma omp section
{
right = mergesort(right, threads - threads/2);
}
}
}
else
{
left = mergesort(left, 1);
right = mergesort(right, 1);
}

return merge(left, right);


}

int main()
{
vector<long> v(1000000);
for (long i=0; i<1000000; ++i)
v[i] = (i * i) % 1000000;
v = mergesort(v, 1);
for (long i=0; i<1000000; ++i)
cout << v[i] << "\n";
}

Usando oito encadeamentos para executar esse merge sort, a durao do tempo de execuo que eu
obtive foi de 2,1 segundos, enquanto um nico encadeamento deu 3,7 segundos. A nica coisa que se
deve lembrar aqui que preciso ter cuidado com o nmero de encadeamentos. Eu comecei com oito
encadeamentos. Sua experincia pode ser diferente, de acordo com a configurao do seu sistema. No
entanto, sem a contagem explcita de encadeamentos, voc acabaria criando centenas, seno milhares,
deles, com altas chances de que o desempenho do sistema decasse. Alm disso, o pragma sections,
discutido anteriormente, foi bem utilizado com o cdigo merge sort.

Concluso
Assim acaba o artigo. Ns avanamos bastante aqui: voc conheceu os pragmas paralelos do OpenMP;
aprendeu diferentes maneiras de criar encadeamentos; ficou convencido das melhorias em desempenho
de tempo, sincronizao e controle de baixa granularidade que o OpenMP oferece; e terminou com uma
aplicao prtica do OpenMP com merge sort. Mas ainda h muito para estudar, o melhor lugar para
isso o site do projeto OpenMP. No deixe de consultar a seo Recursos para mais detalhes.

Recursos Programa Global de


Aprender Empreendedorismo da IBM
Faa parte do programa que
No deixe de conferir o site do projeto OpenMP. busca por empreendedores que
ajudam a modificar a maneira
Para mais informaes sobre como melhorar o desempenho da ordenao como o mundo funciona.
por intercalao, leia Shared Memory, Message Passing, and Hybrid Merge Demos IBM Bluemix
Sorts for Standalone and Clustered SMPs de Atanas Radenski. Confira a srie de demos sobre a
plataforma PaaS da IBM,
Zona de AIX e UNIX do developerWorks: A zona da IBM para AIX e contedo 100% em portugus
UNIX contm vrias informaes relacionadas a todos os aspectos da Cursos EAD
administrao de sistemas AIX, alm expandir suas habilidades no UNIX. Capacite-se nas tecnologias IBM
sem custo
Iniciante em AIX e UNIX? Visite a pgina Iniciante no AIX e UNIX para saber
mais.

Livraria de tecnologia: Encontre livros sobre este e outros tpicos tcnicos na


livraria de tecnologia.

Discutir
Siga o developerWorks no Twitter.

10 de 11 27/04/2017 11:48
Aprendendo a usar a estrutura OpenMP com GCC https://www.ibm.com/developerworks/br/aix/library/au-aix-openmp-fra...

Blogs do developerWorks: Confira nossos blogs e participe da comunidade


do developerWorks.

Participe dos fruns AIX e UNIX:


AIX 5Lfrum tcnico
Frum AIX for Developers
Cluster Systems Management
IBM Support Assistant
Ferramentas de desempenhotcnico
Mais fruns AIX e UNIX

11 de 11 27/04/2017 11:48

Vous aimerez peut-être aussi