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