aula5 - condicoes

22
MC4002 – Programação Paralela 3º Quadrimestre / 2014 Aula 5 Condicionais Prof. Raphael Y. de Camargo [email protected]

description

aula5 - condicoes.pdf

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.

Parte II

Condições

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);

}

Parte II

Modelo Mestre-Escravo

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

Parte I

Exercícios para Entregar

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.