quinta-feira, 7 de maio de 2009

O Problema dos Leitores e Escritores

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

Nenhum comentário:

Postar um comentário