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.