Esse problema simula a sistemática de acesso à um banco de dados. Existem diversos diversos leitores e escritores buscando ler/modificar um dado compartilhado. É necessário então que quando um escritor estiver atualizando o dado, nenhum outro leitor ou escritor possa acessar aquele dado, visto que os escritores podem acabar acessando um dado desatualizado e os escritores podem moficar um dado antigo, modificá-lo e sobescrever o dado atualizado por outro escritor.
A solução ideal deve permitir que vários leitores possam acessar o dado ao mesmo tempo, mas quando um escrito esta atualizando o dado nenhum outro processo deve ter acesso.
A sulução utilizaou dois mutex, uma para pegar acesso exclusivo ao dado, impossiblitando que dois escritores modifiquem ao mesmo tempo; e outro para acessar uma variável que conta o número de leitores lendo ou querendo ler o dado. Dessa forma, esse ultimo mutex controla o acesso dos escritores ao dado.
O código da solução é mostrado abaixo:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#define N_ESC  3  //número de escritores
#define N_LEIT 4 //número de leitores
pthread_t t_escritores[N_ESC]; //vetor de threads para escritores
pthread_t t_leitores[N_LEIT]; //vetor de threadas para leitores
pthread_mutex_t mutex;   //mutex para acesso de rc
pthread_mutex_t acesso_d;   //mutex para acesso do dado
int dados_lidos[N_LEIT];  //vetor que quarda o dado lido
int dado = 0;     //dado à ser lido e escrito
int n_le = 0;                    //número de threads lendo ou querendo ler
void *leitor(void *id);
void *escritor(void *id);
void ler_dado(int leitor);
void utilizar_dado_lido(int leitor);
void pensar_dado(int escritor);
void escrever_dado(int escritor);
main(){
 
 //variáveis para controle de loop e validação da criação de threads e mutexes
 int res;
 void *resultado_thread_leit[N_LEIT];
 void *resultado_thread_esc[N_ESC];
 
 //criação de mutexs
 res = pthread_mutex_init(&mutex, NULL);
 if (res!= 0 ){
  perror("\nFalha na criacao do mutex de acesso a n_le");
  exit(EXIT_FAILURE); 
 } 
 
 res = pthread_mutex_init(&acesso_d, NULL);
 if (res!= 0 ){
  perror("\nFalha na criacao do mutex de acesso ao dados");
  exit(EXIT_FAILURE); 
 } 
 
 int aux[N_ESC];
 int j;
 //criação das threads dos escritores
 for (j = 0 ; j<N_ESC; j++)
 {
  aux[j] = j;    
  res = pthread_create(&t_escritores[aux[j]], NULL, escritor, (void *)&aux[j]); 
  if (res!= 0 ){
  perror("\nFalha na criacao da thread");
  exit(EXIT_FAILURE); 
  }   
 }
 //criação de threadas dos leitores
 int aux2[N_LEIT];
 for (j = 0 ; j<N_LEIT; j++)
 {
  aux2[j] = j;   
  res = pthread_create(&t_leitores[aux2[j]], NULL, leitor, (void *)&aux2[j]); 
  if (res!= 0 ){
  perror("\nFalha na criacao da thread");
  exit(EXIT_FAILURE); 
  }    
 }
 
 //link das threads
 for (j = 0 ; j<N_ESC; j++)
 {  
  res = pthread_join(t_escritores[j], &resultado_thread_esc[j] );    
  if (res!= 0 )
  {
  perror("\nFalha no thread join do consumidor" );
  exit(EXIT_FAILURE);
  }
  
 }
 
 for (j = 0 ; j<N_LEIT; j++)
 {  
  res = pthread_join(t_leitores[j], &resultado_thread_leit[j] );    
  if (res!= 0 )
  {
  perror("\nFalha no thread join do consumidor" );
  exit(EXIT_FAILURE);
  }  
 }
 return 0;
 
}
//função da thread do leitor
void *leitor(void *id)
{
 int i = *(int *)id;
   while (1) {             //loop infinito
        pthread_mutex_lock(&mutex);         //pega acesso à n_le
        n_le = n_le + 1;           //acrecentando numero que estão lendo ou querendo ler
        if (n_le == 1) pthread_mutex_lock(&acesso_d);    //ve se é o primeiro leitor
        pthread_mutex_unlock(&mutex);            //libera acesso à n_le
        ler_dado(i);      //le o dado
        pthread_mutex_lock(&mutex);          //pega acesso exclusivo à n_le
        n_le = n_le +(-1);            //reduz o numero que está lendo
        if (n_le == 0) pthread_mutex_unlock(&acesso_d);  //se for o último libera o acesso ao dado para escrita
        pthread_mutex_unlock(&mutex);            //libera acesso à n_le
        utilizar_dado_lido(i);       //região não crítica
    }
}
void *escritor(void *id)
{
 int i = *(int *)id;
   while (1) {             //loop infinito
        pensar_dado(i);       //região não crítica
        pthread_mutex_lock(&acesso_d);            //pega acesso exclusivo ao dado
        escrever_dado(i);     //modifica o dado
        pthread_mutex_unlock(&acesso_d);       //libera acesso
    }
}
void ler_dado(int leitor)
{
 dados_lidos[leitor] = dado; //salva o dado no vetor de dados lidos
 printf("\nLeitor %d leu dado: %d", leitor, dados_lidos[leitor]); 
 
} 
void utilizar_dado_lido(int leitor)
{
 printf("\nLeitor %d utilizando dado", leitor); 
 sleep(rand()%5); //demora até 5 s para utilizar o dado
 //sleep(1.f);
}
void pensar_dado(int escritor)
{
 printf("\nEscritor %d pensando em dado", escritor);
 sleep(rand()%5); //demora até 5 s para pensar no dado 
 
}
void escrever_dado(int escritor)
{
 dado = dado + escritor; //soma o dado ao número do escritor
 printf("\nEscritor %d escreveu novo dado: %d", escritor, dado);
}
Para facilitar a forma de verificar se o código é válido foi definido que os escritores, ao acessar o dado, fará somente somar o dado antigo ao número do escritor. Assim, para verificar se está funcionando basta ver que o dado acessado pelpos leitores sempre cresce de acordo com o número do ultimo escritor que o modificou. O resiltado abaixo confirma o funciomento correto:
Escritor 0 pensando em dado
Escritor 1 pensando em dado
Escritor 2 pensando em dado
Leitor 0 leu dado: 0
Leitor 0 utilizando dado
Leitor 0 leu dado: 0
Leitor 0 utilizando dado
Leitor 1 leu dado: 0
Leitor 1 utilizando dado
Leitor 1 leu dado: 0
Leitor 1 utilizando dado
Leitor 2 leu dado: 0
Leitor 2 utilizando dado
Leitor 3 leu dado: 0
Leitor 3 utilizando dado
Escritor 1 escreveu novo dado: 1
Escritor 1 pensando em dado
Leitor 1 leu dado: 1
Leitor 1 utilizando dado
Escritor 1 escreveu novo dado: 2
Escritor 1 pensando em dado
Escritor 2 escreveu novo dado: 4
Escritor 2 pensando em dado
Escritor 2 escreveu novo dado: 6
Escritor 2 pensando em dado
Leitor 2 leu dado: 6
Leitor 2 utilizando dado
Escritor 0 escreveu novo dado: 6
Escritor 0 pensando em dado
Leitor 0 leu dado: 6
Leitor 0 utilizando dado
Leitor 0 leu dado: 6
Leitor 0 utilizando dado
Leitor 1 leu dado: 6
Leitor 1 utilizando dado
Escritor 0 escreveu novo dado: 6
Escritor 0 pensando em dado
Escritor 1 escreveu novo dado: 7
Escritor 1 pensando em dado
Leitor 0 leu dado: 7
Leitor 0 utilizando dado
Leitor 3 leu dado: 7
Leitor 3 utilizando dado
Escritor 0 escreveu novo dado: 7
Escritor 0 pensando em dado
Escritor 1 escreveu novo dado: 8
Escritor 1 pensando em dado
Leitor 1 leu dado: 8
Leitor 1 utilizando dado
Leitor 1 leu dado: 8
Leitor 1 utilizando dado
Leitor 2 leu dado: 8
Leitor 2 utilizando dado
Escritor 2 escreveu novo dado: 10
Escritor 2 pensando em dado
Leitor 3 leu dado: 10
Leitor 3 utilizando dado
Leitor 3 leu dado: 10
Leitor 3 utilizando dado
Escritor 1 escreveu novo dado: 11
Escritor 1 pensando em dado
Leitor 0 leu dado: 11
Leitor 0 utilizando dado
Leitor 1 leu dado: 11
Leitor 1 utilizando dado
Escritor 2 escreveu novo dado: 13
Escritor 2 pensando em dado
Leitor 2 leu dado: 13
Leitor 2 utilizando dado
Escritor 0 escreveu novo dado: 13
Escritor 0 pensando em dado
Escritor 1 escreveu novo dado: 14
Escritor 1 pensando em dado
Leitor 0 leu dado: 14
Leitor 0 utilizando dado
Escritor 1 escreveu novo dado: 15
Escritor 1 pensando em dado
Leitor 0 leu dado: 15
Leitor 0 utilizando dado
Leitor 2 leu dado: 15
Leitor 1 leu dado: 15
Leitor 1 utilizando dado
Leitor 2 utilizando dado
Leitor 3 leu dado: 15
Leitor 3 utilizando dado
Leitor 0 leu dado: 15
Leitor 0 utilizando dado
Escritor 0 escreveu novo dado: 15
Escritor 0 pensando em dado
Escritor 1 escreveu novo dado: 16
Escritor 1 pensando em dado
Escritor 2 escreveu novo dado: 18
Escritor 2 pensando em dado
Leitor 2 leu dado: 18
Leitor 2 utilizando dado
Leitor 2 leu dado: 18
Leitor 2 utilizando dado
Leitor 2 leu dado: 18
quinta-feira, 7 de maio de 2009
Assinar:
Postar comentários (Atom)
 
Nenhum comentário:
Postar um comentário