Baixe o app para aproveitar ainda mais
Prévia do material em texto
Programação Paralela e Distribuída 02 - Processamento Paralelo com PThreads Prof. Laerte M. Rodrigues laerte.rodrigues@ifmg.edu.br Concorrência ou paralelismo potencial I Dado uma determinada tarefa computacional podemos dividí-la em sub-partes I Cada uma destas sub-partes podem ter independência de atividades entre si I O Resultado de uma tarefa não depende necessariamente de outra I Considere a tarefa dividida em partes como abaixo Concorrência ou paralelismo potencial I Podemos fazer com que t2, t3 e t4 sejam executadas em paralelo (considerando que estas têm independência) I Em termos práticos o tempo de relógio da execução do programa paralelo para o sequencial é menor pois I As tarefas t2, t3 e t4 serão executadas simultâneamente Concorrência ou paralelismo potencial I O ESFORÇO COMPUTACIONAL será o mesmo I Existem diversas formas de explorar o paralelismo em programas I Operações de I/O I Ocorrência assíncrona de eventos I ... Processos multithreading I Um processo multithreading nada mais é que um programa capaz de criar threads para seus fins de execução I Não utilizam apenas a thread principal I Uma thread é uma execução sequencial dentro de um processo I Cada thread possui seu próprio contexto I Recursos podem ser compartilhados entre si I Variáveis, ponteiros para arquivos, conexões com banco e rede... I Vantagens Processos multithreading I Facilita a estruturação do programa em múltiplas partes de execução I Elimina espaço de enderaçamento múltiplo I Processos não compartilham o mesmo endereço de memória I Trocas de contexto mais eficientes e mecanismos de sincronização são mais simples I Desvantagem I Partilha de recursos exigem grandes cuidados do programador POSIX Threads I A biblioteca Pthreads pertence à família POSIX (Portable Operation System Interface) I Define um conjunto de rotinas para o uso de threads no sistema operacional I As definições desta biblioteca encontram-se no cabeçalho pthreads.h I A implementação está no libpthreads.so I A compilação do programa PThread necessita da inclusão da biblioteca pthread POSIX Threads I Parâmetro -lpthread I A biblioteca PThreads já vêm disponível com o pacote de construção de programas do UNIX I Ubuntu: sudo apt-get install build-essential I Fedora: sudo dnf install @development-tools Hello World Threads! I Para criarmos threads utilizamos a função pthread_create com a assinatura I int pthread_create(pthread_t* th, pthread_attr_t* attr, void* (*routine)(void*), void *args); I pthread_t* th → Identificador da Thread I pthread_attr_t* attr → Atributos para inicialização da thread I Podemos definir informações como prioriodade, escopo, formas de escalonamento entre outros Hello World Threads! I void* (*routine)(void*) → Função que será executada pela Thread, deve retornar void * e ter um parâmetro de mesmo tipo I void *args → Ponteiro para o argumento a ser passado para a thread I A função retorna 0 se a construção da thread ocorreu com sucesso ou o código de erro da construção da mesma e o primeiro parâmetro da função é definida como NULL Hello World Threads! 1 #include <pthread.h> 2 #include <iostream > 3 4 #define NUM_THREADS 10 5 6 using namespace std; 7 8 void *helloworld_threads(void *p) { 9 cout << "Hello! I’m the thread " << (int)p << endl; 10 } 11 12 int main() { 13 pthread_t threads[NUM_THREADS ]; 14 15 for(int i=0;i<NUM_THREADS;i++) { 16 pthread_create (& threads[i],NULL ,helloworld_threads ,new int(i)); 17 } 18 Hello World Threads! 19 return 0; 20 } I Para compilar e executar o programa basta usar o comando I g++ hello.cpp -O3 -lpthread -o hello I ./hello Joinable threads I Ao tentar colocar uma mensagem após o laço for o o mesmo pode não ocorre de forma satisfatória I Threads, quando são criadas têm sua linha de execução independente ao da thread principal I Nestes casos é necessário esperar a execução de TODAS as threads sejam liberadas para dar continuidade à execução do programa Joinable threads I Sendo assim, é necessário sinalizar ao sistema que a execução do programa só dará continuidade no momento em que a Thread Terminar I A função pthread_join têm este fim I int pthread_join(thread_t* th,void *ret); I thread_t* th → Thread ID que será juntada à main I void *ret → Valor de retorno da thread I Retorna 0 caso a thread for juntada com sucesso, senão retorna o código de erro Joinable threads I Também é possível definir a thread como separada das demais (detached) I Neste caso, a thread irá liberar os recursos quando ela terminar sua execução independentemente das demais I int pthread_detached(pthread_t *th); I Pode-se adiquirir o Thread ID da thread corrente I pthread_t pthread_self(); Joinable threads 1 #include <pthread.h> 2 #include <iostream > 3 4 #define NUM_THREADS 10 5 6 using namespace std; 7 8 void *helloworld_threads(void *p) { 9 cout << "Hello! I’m the thread " << *(int*)p << endl; 10 } 11 12 int main() { 13 pthread_t threads[NUM_THREADS ]; 14 15 // Cria as threads 16 for(int i=0;i<NUM_THREADS;i++) { 17 pthread_create (& threads[i],NULL ,helloworld_threads ,new int(i)); 18 } Joinable threads 19 20 // Identifica sincronizacao 21 for(int i=0;i<NUM_THREADS;i++) { 22 pthread_join(threads[i],NULL); 23 } 24 25 cout << "End of task!" << endl; 26 27 return 0; 28 } Multiplicação de matrizes 1 #include <pthread.h> 2 #include <iostream > 3 4 using namespace std; 5 6 int A[][3] = { 7 {3,5,7}, 8 {8,6,1}, 9 {9,0,3} 10 }; 11 12 int B[][3] = { 13 {3,5,7}, 14 {8,6,1}, 15 {9,0,3} 16 }; 17 Multiplicação de matrizes 18 int C[][3] = { 19 {0,0,0}, 20 {0,0,0}, 21 {0,0,0}, 22 }; 23 24 25 struct Arg { 26 int linha; 27 int coluna; 28 }; 29 30 31 void *calcula_celula(void *p) { 32 Arg *arg= (Arg*)p; 33 34 for(int x=0;x<3;x++) { 35 C[arg ->linha ][arg ->coluna] += A[arg ->linha ][x]*B[x][arg ->coluna ]; Multiplicação de matrizes 36 } 37 } 38 39 int main() { 40 41 // Uma thread para cada celula 42 pthread_t threads [9]; 43 44 // Constroi as threads 45 for(int i=0;i<3;i++) { 46 for(int j=0;j<3;j++) { 47 Arg *arg = new Arg(); 48 arg ->linha = i; 49 arg ->coluna = j; 50 51 pthread_create (& threads[i*3+j],NULL ,calcula_celula ,arg); 52 } 53 } Multiplicação de matrizes 54 55 // Sinaliza join 56 for(int i=0;i<9;i++) { 57 pthread_join(threads[i],NULL); 58 } 59 60 // Imprime resposta 61 for(int i=0;i<3;i++) { 62 for(int j=0;j<3;j++) { 63 cout << C[i][j] << " "; 64 } 65 66 cout << endl; 67 } 68 69 return 0; 70 } Exercício I Construa um programa em paralelo que calcule a determinante de uma matriz I A soma das diagonais deve ser armazenada em um vetor temporário
Compartilhar