Monday, May 11, 2009

"Banheiro da Balada" : como controlar entrada de homens e mulheres?

Neste exercício, propomos uma solução para sincronizar o acesso ao banheiro de uma "balada". Como normalmente um único banheiro está disponível para ambos os sexos utilizarem, faz-se necessário desenvolver uma solução que sincronize o acesso de homens e mulheres, com algumas restrições. Caso o banheiro esteja vazio, qualquer pessoa pode entrar. As seguintes devem ser do mesmo sexo, até que o banheiro se esvazie novamente, dando oportunidade para alguém do sexo oposto entrar.

A seguir apresentamos o código-fonte da solução proposta seguido de testes que compravam o bom-funcionamento do programa.


// banheiro da balada

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>

#define N_MULHERES 5
#define N_HOMENS 5

// estados do banheiro
#define VAZIO 0
#define COM_MULHER 1
#define COM_HOMEM 2

pthread_mutex_t mutex_banheiro;
int homens_no_banheiro = 0;
int mulheres_no_banheiro = 0;
int estado = 0;

char *homem_nome[N_HOMENS] = {"Abraham", "Bill", "Carl", "David", "Stri"};
char *mulher_nome[N_MULHERES] = {"Alice", "Pri", "Julia", "Yoko", "Pam"};

int dummy[5];

void *homem(void *arg);
void *mulher(void *arg);

void mulher_quer_entrar(int id);
void mulher_quer_sair(int id);
void homem_quer_entrar(int id);
void homem_quer_sair(int id);

void error_exit(const char*);

int main() {

srand(time(NULL));

int res;
pthread_t mulher_thread[N_MULHERES], homem_thread[N_HOMENS];
void *thread_result;
int index;

//init dummy array
for (index = 0; index < 5; index++){
dummy[index]=index;
}

// iniciar mutex
res = pthread_mutex_init(&mutex_banheiro, NULL);
if(res != 0) error_exit("Inicializacao do mutex falhou");


// criar threads
for (index = 0; index < N_MULHERES; index ++) {
res = pthread_create(&mulher_thread[index],NULL,mulher, (void *)&dummy[index]);
if (res != 0) error_exit("Thread creation failed");
}
for (index = 0; index < N_HOMENS; index ++) {
res = pthread_create(&homem_thread[index],NULL,homem, (void *)&dummy[index]);
if (res != 0) error_exit("Criacao de thread falhou");
}

// join todos threads. assim, esperamos todos threads criados
// terminarem sua execução

for (index = 0; index < N_MULHERES; index++) {
res = pthread_join(mulher_thread[index],&thread_result);
if (res != 0) error_exit("Thread join falhou");
}

for (index = 0; index < N_HOMENS; index++) {
res = pthread_join(homem_thread[index],&thread_result);
if (res != 0) error_exit("Thread join falhou");
}

// kill semaphores, mutexes
pthread_mutex_destroy(&mutex_banheiro);


return 1;
}

void *mulher(void *arg){
int id = *(int *) arg;

sleep(rand() % 4); // antes de tentar entrar pela 1a vez

mulher_quer_entrar(id);
sleep(rand()% 4); // dentro do banheiro
mulher_quer_sair(id);

pthread_exit("exiting thread.\n");

}

void *homem(void *arg){
int id = *(int *) arg;

sleep(rand() % 4); // antes de tentar entrar pela 1a vez

homem_quer_entrar(id);
sleep(rand()% 4); // dentro do banheiro
homem_quer_sair(id);

pthread_exit("exiting thread.\n");
}

void mulher_quer_entrar(int id) {

printf("%s quer entrar no banheiro.\n.", mulher_nome[id]);
while (1) {
pthread_mutex_lock(&mutex_banheiro);
if (estado != COM_HOMEM) {
estado = COM_MULHER;
mulheres_no_banheiro++;
printf("%s entra no banheiro, agora com %d mulheres.\n",
mulher_nome[id], mulheres_no_banheiro);
pthread_mutex_unlock(&mutex_banheiro);
break;
}
pthread_mutex_unlock(&mutex_banheiro);
}
}

void mulher_quer_sair(int id) {

printf("%s quer entrar no banheiro\n.", mulher_nome[id]);
pthread_mutex_lock(&mutex_banheiro);
mulheres_no_banheiro--;
if (mulheres_no_banheiro == 0){
estado = VAZIO;
printf("%s sai do banheiro, agora vazio.\n",
mulher_nome[id]);
}else{
printf("%s sai do banheiro, agora com %d mulheres.\n",
mulher_nome[id], mulheres_no_banheiro);
}
pthread_mutex_unlock(&mutex_banheiro);

}

void homem_quer_entrar(int id) {

printf("%s quer entrar no banheiro\n.", homem_nome[id]);
while (1) {
pthread_mutex_lock(&mutex_banheiro);
if (estado != COM_MULHER) {
estado = COM_HOMEM;
homens_no_banheiro++;
printf("%s entra no banheiro, agora com %d homens.\n",
homem_nome[id], homens_no_banheiro);
pthread_mutex_unlock(&mutex_banheiro);
break;
}
pthread_mutex_unlock(&mutex_banheiro);
}
}

void homem_quer_sair(int id) {
printf("%s quer sair do banheiro\n.", homem_nome[id]);

pthread_mutex_lock(&mutex_banheiro);
homens_no_banheiro--;
if (homens_no_banheiro == 0){
estado = VAZIO;
printf("%s sai do banheiro, agora vazio.\n",
homem_nome[id]);
}else{
printf("%s sai do banheiro, agora com %d homens.\n",
homem_nome[id], homens_no_banheiro);
}
pthread_mutex_unlock(&mutex_banheiro);

}

void error_exit(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}



O teste a seguir descreve uma possível sequência de utilização do banheiro. Observe que os resultados estão de acordo com o esperado.



Bill quer entrar no banheiro
.Yoko quer entrar no banheiro.
.Pri quer entrar no banheiro.
.Bill entra no banheiro, agora com 1 homens.
Pam quer entrar no banheiro.
.Julia quer entrar no banheiro.
.Alice quer entrar no banheiro.
.Carl quer entrar no banheiro
.Stri quer entrar no banheiro
.Carl entra no banheiro, agora com 2 homens.
Stri entra no banheiro, agora com 3 homens.
Abraham quer entrar no banheiro
.Abraham entra no banheiro, agora com 4 homens.
Abraham quer sair do banheiro
.Abraham sai do banheiro, agora com 3 homens.
Bill quer sair do banheiro
.Bill sai do banheiro, agora com 2 homens.
Carl quer sair do banheiro
.Carl sai do banheiro, agora com 1 homens.
David quer entrar no banheiro
.Stri quer sair do banheiro
.David entra no banheiro, agora com 2 homens.
Stri sai do banheiro, agora com 1 homens.
David quer sair do banheiro
.David sai do banheiro, agora vazio.
Pam entra no banheiro, agora com 1 mulheres.
Yoko entra no banheiro, agora com 2 mulheres.
Pri entra no banheiro, agora com 3 mulheres.
Alice entra no banheiro, agora com 4 mulheres.
Julia entra no banheiro, agora com 5 mulheres.
Julia quer entrar no banheiro
.Julia sai do banheiro, agora com 4 mulheres.
Pam quer entrar no banheiro
.Pam sai do banheiro, agora com 3 mulheres.
Yoko quer entrar no banheiro
.Yoko sai do banheiro, agora com 2 mulheres.
Pri quer entrar no banheiro
.Pri sai do banheiro, agora com 1 mulheres.
Alice quer entrar no banheiro
.Alice sai do banheiro, agora vazio.

No comments:

Post a Comment