Baixe o app para aproveitar ainda mais
Prévia do material em texto
Programação Paralela e Distribuída 04 - Primitivas de sincronização Prof. Laerte M. Rodrigues laerte.rodrigues@ifmg.edu.br Primitivas de sincronização I Muitas vezes em programas paralelos devemos controlar o acesso à seção critítica evitando condições de corrida I Controle de recursos também é crucial I Não precisamos implementar estes algoritmos pois os mesmo já existem I Semáforos e monitores são os recursos para programação concorrente para o controle deste tipo de situação Semáforos I Estratégia proposta por Dijkstra para resolver problemas de busy-wait I O semáforo têm 2 campos I value: Um valor de controle do semáforo I queue: Fila de threads que irão ter acesso ao semáforo I Quando value for 0, a thread que requisitar o recurso ficará bloqueada até outra liberá-la I Este processo é feito por 2 rotinas I P: Requisita o recurso, quando este não está disponível bloqueia o processo Semáforos I V: Libera o recurso quando este não é mais necessário I Semáforos binários (Com apenas 1 recurso) podem ser utilizados para controle de seção crítica I Também é conhecido como mutex I Na Pthreads os semaforos estão implementados na biblioteca semaphore.h I sem_t: É a estrutura de dados que faz o controle do semáforo I int sem_init(sem_t *sem, int pshared, unsigned int value): Inicializa a estrutura I sem_t *sem: Ponteiro para a estrutura do semáforo I int pshared: Sempre será 0 (Flag indicando se o semáforo será compartilhado entre processos) Semáforos I unsigned int value: Valor inicial do semáforo I Retorna 0 se a inicialização do semáforo for feita corretamente I int sem_wait(sem_t *sem): Implementação da rotina P I int sem_post(sem_t *sem): Implementação da rotina V I int sem_getvalue(sem_t *sem, int *valp): Retorna o valor atual do semáforo I sem_t *sem: Semáforo que será consultado I int *valp: Variável que será utilizada para receber o valor do semáforo Produtor-consumidor Produtor-consumidor I Neste problema temos um buffer circular que é compartilhado por 2 atores, o produtor e o consumidor I O produtor alimenta o buffer, sendo que este deve ser bloqueado se o buffer estiver cheio I O consumidor esvazia o buffer e o mesmo deve ser bloqueado se o buffer estiver vazio I O buffer deve ser circular pois os elementos têm comportamento de uma fila Produtor-consumidor Produtor-consumidor I1 #include <iostream > 2 #include <pthread.h> 3 #include <semaphore.h> 4 #include <unistd.h> 5 #include <ctime > 6 #include <cstdlib > 7 8 using namespace std; 9 10 #define BUFFER_SIZE 10 11 12 int buffer[BUFFER_SIZE ]; 13 int in = 0; // Indice de entrada do buffer 14 int out = 0; // Indice de saida do buffer 15 16 sem_t mutex; // Controle da secao critica 17 sem_t full; // Controle do buffer cheio 18 sem_t empty; // Controle do buffer vazio Produtor-consumidor 19 20 void *produtor(void *p) { 21 while (1) { 22 int r = rand() % 100; 23 24 sem_wait (&full); // Espera se o buffer estiver cheio 25 26 // Secao critica 27 sem_wait (&mutex ); 28 buffer[in] = r; 29 in = (in+1)% BUFFER_SIZE; 30 cout << "Produtor depositou " << r << endl; 31 sem_post (&mutex ); 32 // Fim da secao critica 33 34 sem_post (&empty ); // Sinaliza que buffer pode nao estar mais vazio 35 usleep(rand ()%1000); 36 } Produtor-consumidor 37 } 38 39 void *consumidor(void *p) { 40 while (1) { 41 sem_wait (&empty ); // Espera se o buffer estiver vazio 42 43 // Secao critica 44 sem_wait (&mutex ); 45 cout << "Cosumidor pegou " << buffer[out] << endl; 46 out = (out +1)% BUFFER_SIZE; 47 sem_post (&mutex ); 48 // Fim da secao critica 49 50 51 sem_post (&full); // Sinaliza possivel buffer 52 usleep(rand ()%1000); 53 } 54 } Produtor-consumidor 55 56 int main() { 57 pthread_t threads [5]; 58 59 srand(time(NULL )); 60 61 sem_init (&mutex ,0 ,1); 62 sem_init (&full ,0, BUFFER_SIZE ); 63 sem_init (&empty ,0 ,0); 64 65 pthread_create (& threads [0],NULL ,produtor ,NULL); 66 pthread_create (& threads [1],NULL ,produtor ,NULL); 67 pthread_create (& threads [2],NULL ,consumidor ,NULL); 68 pthread_create (& threads [3],NULL ,consumidor ,NULL); 69 pthread_create (& threads [4],NULL ,consumidor ,NULL); 70 71 for(int i=0;i<2;i++) { 72 pthread_join(threads[i],NULL); Produtor-consumidor 73 } 74 75 return 0; 76 } Problema do leitor-escritor I Controle de recursos em banco de dados compartilhados I Evitar o problema de ghost-read I Protocolo: I 2 ou mais leitores podem acessar a base concorrentemente I Sem conflito read-write: Um leitor e um escritor não podem acessar concorrentemente I Sem conflito write-write: 2 escritores não podem acessar a base concorrentemente I A idéia básica deste controle é I Quando existir um leitor, outro também pode acessar a base Problema do leitor-escritor I O escritor só pode acessar a base quando não existe nenhum leitor ou escritor I Na implementação, wlock é o semáforo binário que bloqueia leitores e escritores para o acesso I1 #include <iostream > 2 #include <pthread.h> 3 #include <semaphore.h> 4 #include <unistd.h> 5 #include <ctime > 6 #include <cstdlib > 7 #include <ctime > 8 9 using namespace std; 10 Problema do leitor-escritor 11 sem_t mutex; // Controle da secao critica 12 sem_t wlock; // Controle do buffer cheio 13 int num_readers = 0; 14 15 void *writer(void *p) { 16 cout << "Escritor criado" << endl; 17 sem_wait (&wlock ); 18 cout << "Escritor escrevendo ..." << endl; 19 usleep(rand ()%100); 20 cout << "Escritor terminou de escrever ..." << endl; 21 sem_post (&wlock ); 22 } 23 24 void *reader(void *p) { 25 cout << "Leitor criado" << endl; 26 27 sem_wait (&mutex ); 28 cout << "Leitor Entrado em processo de leitura ..." << endl; Problema do leitor-escritor 29 num_readers ++; 30 if(num_readers ==1) sem_wait (&wlock ); 31 sem_post (&mutex ); 32 33 usleep(rand ()%100); 34 35 sem_wait (&mutex ); 36 num_readers --; 37 if(num_readers ==0) sem_post (&wlock ); 38 cout << "Leitor liberando leitura ..." << endl; 39 sem_post (&mutex ); 40 } 41 42 int main() { 43 pthread_t tmp; 44 45 srand(time(NULL )); 46 Problema do leitor-escritor 47 sem_init (&mutex ,0 ,1); 48 sem_init (&wlock ,0 ,1); 49 50 while (1) { 51 if(rand ()%100 < 50) { 52 pthread_create (&tmp ,NULL ,writer ,NULL); 53 }else{ 54 pthread_create (&tmp ,NULL ,reader ,NULL); 55 } 56 } 57 58 return 0; 59 }
Compartilhar