aula5 - condicoes
description
Transcript of aula5 - condicoes
MC4002 – Programação Paralela3º Quadrimestre / 2014
Aula 5Condicionais
Prof. Raphael Y. de [email protected]
2
Mutexes● A biblioteca pthreads fornece suporte a mutexespthread_mutex_t mutex;
pthread_mutex_init (mutex,attr)
pthread_mutex_destroy (mutex)
pthread_mutex_lock (mutex)
pthread_mutex_trylock (mutex)
pthread_mutex_unlock (mutex)
Exemplo onde várias threads incrementam um mesmo contador:
Modelo Produtor-ConsumidorNeste caso as threads produtoras e consumidoras são
diferentes
Uso de buffer de tamanho fixo
É preciso controlar o tamanho do buffer através de operações de sincronização
Exemplos: servidor web
4
Produtor-Consumidor com Condição de CorridaO produtor chama
while (1) { while (count == BUFFER_SIZE) ; // não faz nada buffer[in] = geraItem();in = (in + 1) % BUFFER_SIZE;count++;
}
O consumidor chama while (1) {while (count == 0)
; // não faz nadanextConsumed = buffer[out];out = (out + 1) % BUFFER_SIZE;count--; // controla o nº de itens no BUFFERconsomeItem (nextConsumed);
}
in
out
BUFFER
(Ex.: 37%10=7)
5
Condição de Corridacount++ poderia ser implementado (em assembly) como register1 = count tid = register1 register1 = register1 + 1 count = register1
Considere esta seqüência de execuções intercaladas:thread 0 → executa register1 = count {register1 = 0}thread 0 → executa tid = register1 {tid = 0} thread 0 → executa register1 = register1 + 1 {register1 = 1}thread 1 → executa register2 = count {register2 = 0}thread 1 → executa tid = register2 {tid = 0}thread 1 → executa register2 = register2 + 1 {register2 = 1} thread 0 → executa count = register1 {count = 1} thread 1 → executa count = register2 {count = 1}
Ambas as threads obtêm o mesmo identificador!
6
Exercício para Aula1. Modifique o programa prod-cons-nomutex.c para que ele uso o modelo produtor-consumidor com mutexes, de modo a eliminar a condição de corrida.Use um buffer de tamanho 10.
8
CondiçõesO problema do exemplo anterior é que ele utiliza o conceito de espera ocupada, o que usa desnecessariamente o processador.
Condições: - São usadas quando desejamos que uma ou mais threads esperem até serem sinalizadas por outra thread.
Uma condição pode entrar em estado de espera com o comando:pthread_cond_wait (condition,mutex)
Uma thread em modo de espera pode ser acordada:pthread_cond_signal (condition)
Ou, para o caso em que se deseja acordar todas as threads:pthread_cond_broadcast (condition)
9
CondiçõesCondições precisam ser definidas e criadas:
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_cond_init (condition,attr)
pthread_cond_destroy (condition)
Note que cada condição deve estar sempre associada a um mutex e as comandos sleep e wake up só podem ser chamados de dentro do mutex.
10
Exemplopthread_mutex_t mutex;
pthread_cond_t cond;
void *PrintHello(void *param)
{
printf("Hello World from second thread!\n");
// DO STUFF
pthread_mutex_lock (&mutex);
pthread_cond_signal (&cond);
pthread_mutex_unlock (&mutex);
// DO STUFF
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t t;
pthread_mutex_init (&mutex,NULL);
pthread_cond_init (&cond,NULL);
pthread_mutex_lock (&mutex);
pthread_create(&t,NULL,PrintHello,NULL);
pthread_cond_wait (&cond, &mutex);
pthread_mutex_unlock (&mutex);
printf("Hello World from main thread!\n");
pthread_exit(NULL);
}
11
Condição de CorridaO produtor chamawhile (1) { while (count == BUFFER_SIZE) ; // não faz nada buffer[in] = geraItem();in = (in + 1) % BUFFER_SIZE;count++;
}
O consumidor chama while (1) {while (count == 0) ; // não faz nadanextConsumed = buffer[out];out = (out + 1) % BUFFER_SIZE;count--; // controla o nº de itens no BUFFERconsomeItem (nextConsumed);
}
in
out
BUFFER
(Ex.: 37%10=7)
12
Exercício para Aula2. Modifique o programa produtor-consumidor para utilizar condições e, assim, eliminar a espera ocupada.DICAS:- Você precisará de 2 condições, 1 para o produtor e 1 para o consumidor.- O produtor deverá dormir sempre que o buffer estiver cheio. Ele será acordado pelo consumidor logo após este consumir um item e liberar espaço no buffer.- O consumidor deverá dormir sempre que o buffer estiver vazio. Ele será acordado pelo produtor quando o buffer passar a ter pelo menos um item.
13
Condições e BarreirasBarreiras permitem a criação de pontos de sincronização entre as threads de um programa. Pode ser útil em diversos casos:- Aplicação de múltiplos filtros em uma imagem- Multiplicação de várias matrizes- Codificação e decodificação de vídeos, etc.
Retirado de http://www.cs.albany.edu/~sdc/CSI500/Fal11/Classes/C08/TanBarrierFig.jpg
14
Condições e BarreirasBarreiras podem ser criadas utilizando um mutex, um contador e um condicional:
pthread_mutex_lock (mutex)
chegaram++;
if ( chegaram < N_THREADS )
pthread_cond_wait (cond,mutex)
else {
pthread_cond_broadcast (cond)
chegaram = 0;
}
pthread_mutex_unlock (mutex)
15
Exercícios para Aula3. Modifique o programa disponível em workers.c para que inicialmente todas as threads sejam lançadas. Em seguida, cada thread deve dormir por um tempo aleatório, entre 1 e 2 segundos e, em seguida, imprimir uma mensagem na tela avisando que estão prontas:Thread 0: prontaThread 1: pronta
Depois que todas as threads estiverem prontas, elas podem começar o seu trabalho, Thread 0: realizando tarefas Thread 1: realizando tarefas
Após realizar o trabalho, cada thread finaliza sua execução.
16
Controle de Leitores ConcorrentesVocê está implementando um sistemas para controle de acesso a um banco de dados (BD). O acesso aos dados é de apenas leitura e, para evitar a sobrecarga do BD, apenas K threads leitoras podem acessar o banco de dados de cada vez. As threads leitoras acessam o banco de dados através do método leitor(). O código abaixo implementa um controle de acesso sequencial, onde uma thread acessa o banco de dados por vez.
mutex db; // variável global
void leitor () {
lock(db);
leBancoDeDados(); // realiza o acesso ao BD
unlock(db);
}
17
Exercício4. Modifique o pseudo-código abaixo da função leitor() para que ela realmente implemente a política descrita acima de permitir K acessos simultâneos ao BD.Lembre-se que você não deve utilizar espera ocupada. Utilize condicionais para fazer as threads que estão aguardando para serem atendidas dormir. Use os métodos lock(mutex), unlock(mutex), wait(mutex, cond) e signal(cond), onde mutex e cond são as variáveis do tipo mutex e condicionais.
mutex db; // variável global
void leitor () {
lock(db);
leBancoDeDados(); // realiza o acesso ao BD
unlock(db);
}
Modelo Mestre-EscravoThread Mestre cria trabalhadores para executar tarefas e
controla sua execução
→ Usado quando a complexidade de cada tarefa gerada é imprevisível e variada.
→ Funciona melhor quando as tarefas são independentes
Função da thread mestre é fornecer tarefas para as demais threads e coordenar sua execução
Exemplos: Servidor Web, SETI@Home, etc.
20
5. O programa fatora-mestreSimples.c, lança uma thread mestre e outras k threads que funcionam como escravas.
A comunicação é feita por uma variável global proximo, que contem o próximo número a ser fatorado. É inicializada em -1
A thread mestre permanece em um laço onde gera os números a serem fatorados e coloca em próximo.
Cada thread escrava possui um laço, onde em cada iteração ela obtém o próximo número a fatorar e realiza seu trabalho. Ela termina quando a thread mestre indica que não existem mais números a fatorar, colocando o valor -1 em proximo.
O programa não possui os comandos de sincronização, de modo que ele não funciona corretamente. Corrija o programa.
Exercício
22
Exercícios para Entregar1. Entregue a implementação mestre-escravo do problema da Fatoração, conforme enunciado do exercício anterior.
2. Modifique o programa readers.c para que 10 leitores possam acessar o banco de dados de cada vez.Para verificar se seu programa está funcionando corretamente, ele deve demorar em torno de 1 segundo para executar. Verifique usando o comando time.