Lista 1 Resolvida
De BCC Wiki
Lista: Lista 1 PDF
Tabela de conteúdo |
Exercício 1
a
Versão com Threads
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define N ? /* Define o valor de N, substituir ? */
int array[N];
int c = 0;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
void soma(int x){
/* Regi�o Cr�tica */
pthread_mutex_lock(&mut);
c = c + array[x];
pthread_mutex_unlock(&mut);
}
int main(){
int i;
pthread_t ids[N];
/* Inicializa o vetor para testes
for (i = 0; i < N; i ++){
array[i] = i;
}*/
for (i = 0; i < N; i++){
pthread_create(&ids[i],NULL,soma,i);
}
for (i = 0; i < N; i++){
pthread_join(ids[i],NULL);
}
printf("Results is %d\n",c);
return 0;
}
Versão com OpenMP
#pragma omp parallel for reduction(+:c)
for (c=i=0; i < N; i++)
{
c = c + a[i];
}
Exercício 2
(a) O número máximo de processadores é 3, porque as linhas 3-5, 6-8 e 9-10 não têm dependências verdadeiras então podem ser paralelizadas, a sequência de execução pode ser
thread 1 2 3
1
2
3 4 5
sync 6 7 8
sync 9 10 11
sync 12
havendo sincronização antes de cada linha marcada com sync
Fiz de outra maneira, usando Ordenação Topológica
thread 1 2 3
1
2 4 7
8 3 5
9 6 10
11 12
(b) O tempo de execução é 6, dado pelo número de linhas da tabela anterior
(c) A aceleração é S(3) = T(1) / (ts + tp/3) => S(3) = 12 / (3 + 9/3) = 12 / 6 = 2
Exercício 3
É chamada de verdadeira porque é a única que não pode ser desfeita. A anti-depêndencia pode ser desfeita inserindo uma nova variável, por exemplo
c = a + d; a = b;
pode virar uma dependência verdadeira inserindo a variável k
k = a; a = b; c = k + d;
e a dependência de saída se vier sozinha não faz sentido e pode ser desfeita facilmente
Por exemplo:
a = b; a = c;
é uma dependência de saída que pode ser trocado por
a = c;
Se não estiver sozinha ela vem acompanhada das outras duas depêndencias
Por exemplo:
a = b; k = a + 3; a = c;
Que é transformado numa dependência verdadeira usando o mesmo mecanismo da anti-paralela
a = b; d = a; a = c; k = d + 3;
Exercício 4
O custo correspondente na memória compartilhada é dado pelo barramento da memória, de quão rápido os dados são enviados da memória sendo compartilhada até o cache do processador que vai executar o trecho de código
Exercício 5
To-Do
Exercício 6
Os programas Embarrasing Parallel são programas que não é necessário nenhum grande empenho em segmentar o programa em um grande número de tarefas paralelizáveis e não há nenhuma dependência essencial entre estas tarefas paralelizáveis.
Exercício 7
To-Do
Exercício 8
To-Do
Exercício 9
Semáforo x Busy Waiting
Um Busy Waiting faz uma verificação repetidamente para a modificação de uma determinada variável ou recurso. Um exemplo é a captura de eventos de um teclado ou a espera por uma trava se destravar.
Um semáforo recebe um valor máximo de quantos processos podem acessar um recurso e consiste de duas operações: wait e signal. O wait decrementa o valor do semáforo, e se este valor for 0, o processo é posto para dormir. O signal incrementa o valor do semáforo. Se o valor for 0, e houver algum processo dormindo, acorda o processo adormecido. Caso contrário, incrementa o valor do semáforo.
O Busy Waiting parece gastar mais CPU, por se tratar de uma verificação "exaustiva". Porém, no caso de um BW, a atualização acontece mais rápido.