. OpenMP
[!tip] Nao cai na prova
API portável para threads em sistemas multiprocessadores de memória compartilhada.
Padroniza paralelismo em grão fino (laços). Paralelizar parcialmente seções do código que podem ser intensos ao processamento.
Usando em C
main () {
#pragma omp parallel for \
shared(A)private(i)
for (i = 1; i <= 12; i++) {
[...]
}
}neste exemplo
- A (vetor) é compartilhado entre as $i$ threads geradas
- i (iterador) é privado entre as threads, ou seja, cada valor de $i$ representa uma thread
Para criar novas threads, o usuário define uma região paralela:
- Threads Workers são disparados;
- Mestre é parte dos Workers;
- Threads saem ao final da região paralela (sleep);
- Modelo Fork-Join.
Criando threads
A diretiva parallel (define região paralela) pode receber cláusulas de execução
#pragma omp parallel num_threads (quantity) {
// code
}OpenMP funciona em memoria compartilhada, sendo o modo padrao compartilhado entre todas as threads.
Fora isso, pode ter variaveis privativas para cada thread. Ou ter valores iniciais comuns (firstprivate) ou ainda valor final comum (lastprivate)
Exclusão Mútua
Pode ser feita de 2 formas:
- região critica (critical)
#pragma omp parallel {
...
#pragma omp critical(left) // left eh um semaforo
A[i] += Alocal
...
}- execução atomica É aplicada apenas no comando seguinte. Otimizam a exclusão mútua se o hardware permitir.
#pragma omp parallel
{
#pragma omp atomic
A[i] += Alocal
}- execução sequencial (ordered)
Garante, além da exclusão mútua, obriga também a execução sequencial do laço. Especialmente aplicável para saida e entrada de dados
#pragma omp parallel
{
#pragma omp ordered
A[i] += Alocal
}- barreira de sincronismo (barrier)
#pragma omp parallel
{
...
#pragma omp barrier
...
}Diretivas
DO
deve estar em um trecho paralelo Divide as iteracoes entre as threads
#pragma omp parallel shared(a,b,c, chunk)private(i)
{
#pragma omp for schedule(dynamic, chunk) nowait
for (i-0; i < N; i++)
c[i] = a[i] + b[i];
}schedule (escalonamento das threads)
Pode ser static, dynamic, guided, runtime
static - define tamanho do chunk automaticamente, bem definido (i.e, i = 1..4, 5..8, 9…12), sempre nessa ordem entre as $t_i$.
static, 4 - tamanho do chunk settado;
dynamic, x - cada thread pega x iterações do laço, sem ordem de thread, escalona de acordo com liberdade de execução da thread.
guided, x - todo término de informação é trocada com a thread mestre nas outras schedules, nesse caso, ele evita essas trocas.
runtime, x - escolhido em tempo de execucao -> tem que ser decidido externamente a compilacao, ou seja, pode ser alterado durante a execucao caso necessario, alterando a variavel run-sched-var;
é importante setar o número de threads do omp (.env)
$ export OMP_NUM_THREADS=8
omp_set_num_threads(int);
