Relatório CES-33: Alexandre Couto Albizzati

INSTITUTO TECNOLÓGICO DE AERONÁUTICA
Aluno: Alexandre Couto Albizzati
Prof: Yano

Introdução

Os problemas abaixo são relacionados ao tema Comunicação Interprocessos. As principais questões relacionadas a esses temas são se os processos são capazes de passar e receber as informações e se elas serão passadas e recebidas na ordem correta.
Os problemas implementados abaixo foram implementados com threads/processos em paralelo e as principais dificuldades encontradas foram as corridas críticas e os deadlocks.
A implementação correta de problemas com semáforos deve ser feita cuidadosamente, e os testes devem estar presentes para evitar erros despercebidos.

Programa 1

Este programa explora os conceitos de comunicação interprocessos, visando desenvolver o problema do produtor e consumidor usando pipes. Para isso implementou-se além das pipes comandos "forks", para gerar processos pais e filhos que servissem como produtores e consumidores.
O código-fonte encontra-se abaixo:

#include <stdio.h>
#include<string.h>
#define READ 0 /* The index of the read end of the pipe */
#define WRITE 1 /* The index of the write end of the pipe */
 
void comunicar(void);
int fd [2], bytesRead;
char* phrase = "A mensagem transmitida!!";
 
int main (){
 
/* Comunicação entre os processos */
  while(1){
     pipe (fd); /*Create an unnamed pipe */
     comunicar();
     sleep(2);
  }
return 0;
}
 
void comunicar(void){
  char message [100];
  int item;
 
  if(fork()==0){ /* Child, writer */
    close(fd[READ]); /* Close unused end */
    write (fd[WRITE],phrase, strlen (phrase) + 1); /* include NULL*/
    item = getpid();
    printf("Produtor %d enviou uma mensagem!\n",item);
    close (fd[WRITE]); /* Close used end*/
  }
  else{/* Parent, reader*/
    close (fd[WRITE]); /* Close unused end */
    bytesRead = read (fd[READ], message, 100);
    item = getpid();
    printf("Consumidor %d recebeu a mensagem!\n",item);
    printf ("Read %d bytes: %s\n", bytesRead, message); /* Send */
    close (fd[READ]); /* Close used end */
  }
}

Um dos resultados obtidos com esse programa foi o apresentado abaixo:

alexandre@alexandre-laptop:~$ ./programa1
Produtor 6497 enviou uma mensagem!
Consumidor 6496 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6497 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Produtor 6499 enviou uma mensagem!
Produtor 6498 enviou uma mensagem!
Consumidor 6496 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Produtor 6502 enviou uma mensagem!
Produtor 6501 enviou uma mensagem!
Produtor 6503 enviou uma mensagem!
Consumidor 6496 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6498 recebeu a mensagem!
Produtor 6500 enviou uma mensagem!
Consumidor 6499 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6497 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Read 25 bytes: A mensagem transmitida!!
Produtor 6504 enviou uma mensagem!
Produtor 6505 enviou uma mensagem!
Produtor 6507 enviou uma mensagem!
Produtor 6508 enviou uma mensagem!
Produtor 6506 enviou uma mensagem!
Produtor 6509 enviou uma mensagem!
Produtor 6510 enviou uma mensagem!
Produtor 6511 enviou uma mensagem!
Consumidor 6503 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6499 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6498 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6501 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6496 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6500 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6502 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6497 recebeu a mensagem!
Read 25 bytes: A mensagem transmitida!!
Consumidor 6505 recebeu a mensagem!
Produtor 6513 enviou uma mensagem!
Produtor 6515 enviou uma mensagem!
Produtor 6516 enviou uma mensagem!
Produtor 6518 enviou uma mensagem!
Produtor 6519 enviou uma mensagem!
Produtor 6520 enviou uma mensagem!
Produtor 6521 enviou uma mensagem!
Produtor 6517 enviou uma mensagem!

ctrl+C

Uma observação interessante foi que quando foi implementado pela primeira vez, o programa não continha o sleep(2) na main. Isso fez com que o programa criasse tantos processos por meio do fork que o computador travou!
Até que o presente aluno entendesse o que estava acontecendo, ele teve de reiniciar o computador algumas vezes…

Programa 2 - O Problema do Jantar dos Filósofos

O Problema do Jantar dos Filósofos é um problema clássico de comunicação interprocessos. O problema é descrito da seguinte maneira: Há 5 filósofos sentados a uma mesa circular. Para cada filósofo, há um prato de macarrão. As únicas coisas que um filósofo faz são pensar e comer. Os filósofos precisam, para comer o macarrão, de dois garfos. Mas entre cada um dos pratos há um garfo, tendo dessa forma apenas 5 garfos sobre a mesa. O problema é sincronizar a ação dos filósofos de modo que todos possam, alternadamente, comer, sem que nenhum fique bloqueado, morrendo de fome.
Este problema serve para modelar uma situação em que há muitos processos competindo para ter direito de acesso exclusivo a um recurso limitado.

Philosphers.jpg

A solução implementada foi utilizando threads. Criou-se uma thread philosopher que irá modelar o comportamento do filósofo. Esta thread segue o comportamento "pensar, pegar garfos, comer, colocar os garfos na mesa", num loop infinito.
O código-fonte implementado e comentado é mostrado abaixo:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
#define N 5
#define LEFT (i+4)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
 
int state[N];
sem_t mutex;
sem_t s[N];
typedef char* string;
string nomes[5] = {"Epicuro (1)","Wittgeinstein (2)","Schopenhauer (3)","Godel (4)","Kant (5)"};  // Nomes dos filósofos
 
// Protótipos das funções
void eat(int i);
void think(int i);
void take_forks(int i);
void put_forks(int i);
void test(int i);
 
void eat(int i)
{
 sleep(i);               // Tempo de comer do filósofo i
}
 
void think(int i)
{
 sleep(i+1);             // Tempo de pensar do filósofo i
}
 
// Thread do filósofo
void * philosopher(void *a)
{
   int k = *(int *)a;
   while (1)
    {
    // Comportamento do filósofo
       think(k);
       take_forks(k);
       eat(k);
       put_forks(k);
    }
}
 
void take_forks(int i)
{
   sem_wait(&mutex);     // Entra na região critica
   state[i] = HUNGRY;    // Define o estado como com fome
   test(i);              // Verifica se pode pegar os garfos para comer
   sem_post(&mutex);     // Libera a região critica
   sem_wait(&s[i]);      // Se o filosofo não pegou os garfos deve esperar
}
 
void put_forks(int i)
{
    // Liberar os garfos na mesa
   sem_wait(&mutex);     // Entra na regiao critica
   state[i] =  THINKING; // Define o estado como pensando
   test(LEFT);         // Verifica se o filósofo à esquerda pode pegar os garfos para comer
   test(RIGHT);         // Verifica se o filósofo à direita pode pegar os garfos para comer
   sem_post(&mutex);     // Sai da regiao critica
}
    // Funções para imprimir os estados
void imprime_estados(int k)
{
   if(state[k] == HUNGRY) printf("HUNGRY\n");
   if(state[k] == EATING) printf("EATING\n");
   if(state[k] == THINKING) printf("THINKING\n");
}
 
void imprime()
{
   printf("Epicuro(1): ");
   imprime_estados(0);
   printf("Wittgeinstein(2): ");
   imprime_estados(1);
   printf("Schopenhauer(3): ");
   imprime_estados(2);
   printf("Godel(4): ");
   imprime_estados(3);
   printf("Kant(5): ");
   imprime_estados(4);
   printf("\n");
}
 
void test(i)
{
       if(state[i]==HUNGRY && state[LEFT]!=EATING && state[RIGHT]!=EATING) // Se está faminto e os vizinhos não estão comendo...
        {
           state[i] = EATING;       //... entao come
           imprime();               // imprime estado de todos os filósofos nesse instante
       sem_post(&s[i]);         // impede-se de ser bloqueado, pois pode pegar os garfos
        }
}
 
int main()
{
    pthread_t filosofos[N];   // Declara os filosofos
    sem_init(&mutex,0,1);     // Inicia o semaforo mutex
    int aux[5];    
 
    int j;
    for(j=0;j<5;j++)
      {
         sem_init(&s[j],0,0);  // Inicia os semaforos de cada filosofo
      }
 
    for(j=0;j<5;j++)
    {
         aux[j] = j;
             pthread_create(&filosofos[j],NULL,philosopher,(void*)&aux[j]);  // Cria os filosofos
    }
 
    pthread_join(filosofos[0],NULL);    // Força a main a esperar até que a thread filosofos[0] encerre-se (no caso é infinita)
 
return 0;
}

Com esta implementação podemos ver, na execução, que os filósofos executam os seus procedimentos sem que nenhum fique travado para sempre. Os resultados de um exemplo de execução são mostrados abaixo:

programa2.png

Percebemos que o resultado é o esperado: nunca há dois filósofos consecutivos comendo e além disso, na maior parte do tempo, encontramos dois filósofos comendo ao mesmo tempo (o que aproveita o fato de que até dois filósofos podem comer ao mesmo tempo).

Programa 3 - O Problema da Barbearia

O Problema da Barbearia é outro problema clássico de sistemas operacionais.
A descrição do problema á a seguinte: Há um barbeiro numa barbearia com n cadeiras. Se não há nenhum cliente para ser atendido, o barbeiro senta sobre a sua cadeira e adormece. Se um cliente chega e o barbeiro está dormindo, deve acordá-lo. Se outros clientes forem chegando, e o barbeiro estiver atendendo alguém, eles vão se sentando nas cadeiras disponíveis. Caso todas as cadeiras estejam ocupadas, eles vão embora. O desafio é programar o barbeiro e os clientes sem que eles caiam em condições de corrida.
Este problema possui muitas aplicações práticas, em situações em que há muita coisa a ser processada (muitos clientes esperando) e um recurso limitado (um único barbeiro).
O código-fonte implementado e comentado é mostrado abaixo:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
 
# define CHAIRS 5
 
sem_t customers, barbers, mutex;  // Declaração dos semáforos. Os valores da inicialização estão na main
int waiting = 0;                  // Variável com o numero de clientes esperando
 
void cut_hair()
{
  printf("Cortei teu cabelo!\n");sleep(3);          // Corta o cabelo, com um atraso
}
 
void get_haircut(int id_cliente)
{
  printf("Cliente %d atendido.\n", id_cliente,waiting);  // É atendido pelo barbeiro
}
void * barber(void* a)
{
   while (1)
  {
    sem_wait(&customers);      // Dorme se customers = 0
    sem_wait(&mutex);          // Entra na região critica (acesso a waiting)
    waiting = waiting - 1;     // Um cliente a menos esperando
    sem_post(&barbers);        // Acorda um cliente para ser atendido
    sem_post(&mutex);          // Sai da região critica
    cut_hair();                // Corta o cabelo
  }
}
 
void * customer(void *a)
{
   int k = *(int *) a;         // Passagem dos parametros
   sem_wait(&mutex);           // Entra na região critica (acesso a waiting)
   if(waiting < CHAIRS)        // Se há cadeiras disponiveis...
    {
       waiting = waiting + 1;  // Mais um cliente esperando
       printf("Estou esperando. Sou o %d. Tamanho da fila: %d\n", k,waiting); // imprime mensagem
       sem_post(&customers);   // Acorda o barbeiro, se preciso
       sem_post(&mutex);       // Libera a região critica (acesso a waiting)
       sem_wait(&barbers);     // Dorme, esperando para ser atendido se não ha barbeiro disponivel
       get_haircut(k);         // Recebe o corte de cabelo
    }else{                     // Se o cliente chega e não há cadeiras disponiveis...
       sem_post(&mutex);       // ... vai embora
    }
 
    pthread_exit(NULL);
}
 
int main()
{
   sem_init(&customers,0,0);  // customers começa sendo 0
   sem_init(&barbers,0,0);    // barbers começa sendo 0
   sem_init(&mutex,0,1);      // mutex começa sendo 1
   int id_cliente = 0;   
 
   pthread_t *clientes;
   pthread_t barbeiro;
   pthread_create(&barbeiro,NULL,barber,NULL);
 
   while(1)
    {
        clientes = (pthread_t*) malloc(sizeof(pthread_t));         // aloca um ponteiro pra thread
    pthread_create(clientes,NULL,customer,(void*)&id_cliente); // cria um cliente
        srand(time(NULL));
        sleep(rand()%2 + 1);                                       // espera um tempo
    id_cliente++;                           // incrementa o id_cliente
    }
 
// O join nao eh necessario pois temos um loop infinito na main
 
return 0;
}

O comportamento do barbeiro é inicialmente dormindo. Quando um cliente chega, ele verifica se há cadeiras disponíveis, se houver, aumenta a variável waiting, protegida por mutex. Apresenta uma mensagem, acorda o barbeiro com um up(&customers), libera a região critica de mutex e dorme esperando para ser atendido. Paralelamente, quando o barbeiro foi acordado, ele requer a região critica, se não conseguir, dorme até que possa que seja acordado por algum cliente. Quando acordar, requer a região critica de waiting (mutex), decrementa o numero de clientes esperando e então acorda um cliente para ser atendido, sai da região critica e atende o cliente.
É interessante nota que cada thread customer, diferentemente da thread barber, não possuem um loop infinito, pois são atendidos somente uma vez.
Os resultados obtidos no terminal de comandos para este problema são mostrados abaixo:

alexandre@alexandre-laptop:~$ ./programa3
Estou esperando. Sou o 0. Tamanho da fila: 1
Cortei teu cabelo!
Cliente 0 atendido.
Estou esperando. Sou o 1. Tamanho da fila: 1
Cortei teu cabelo!
Cliente 1 atendido.
Estou esperando. Sou o 2. Tamanho da fila: 1
Cortei teu cabelo!
Cliente 2 atendido.
Estou esperando. Sou o 3. Tamanho da fila: 1
Estou esperando. Sou o 4. Tamanho da fila: 2
Cliente 3 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 5. Tamanho da fila: 2
Cliente 4 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 6. Tamanho da fila: 2
Estou esperando. Sou o 7. Tamanho da fila: 3
Cortei teu cabelo!
Cliente 5 atendido.
Estou esperando. Sou o 8. Tamanho da fila: 3
Cliente 6 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 9. Tamanho da fila: 3
Estou esperando. Sou o 10. Tamanho da fila: 4
Cortei teu cabelo!
Cliente 7 atendido.
Estou esperando. Sou o 11. Tamanho da fila: 4
Cliente 8 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 12. Tamanho da fila: 4
Estou esperando. Sou o 13. Tamanho da fila: 5
Cliente 9 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 14. Tamanho da fila: 5
Cortei teu cabelo!
Cliente 10 atendido.
Estou esperando. Sou o 15. Tamanho da fila: 5
Cliente 11 atendido.
Cortei teu cabelo!
Estou esperando. Sou o 17. Tamanho da fila: 5
Cortei teu cabelo!
Cliente 12 atendido.
Estou esperando. Sou o 18. Tamanho da fila: 5
Cortei teu cabelo!
Cliente 13 atendido.
^C
alexandre@alexandre-laptop:~$

É necessário pressionar ctrl+c para que o programa finalize, já que é infinito.
Percebemos que inicialmente, o barbeiro atende os clientes na ordem em que eles chegam. Mas quando o tamanho da fila estabiliza em 5 (que é o numero de cadeiras da barbearia), ele começa a "perder" clientes, pois eles chegam e vão embora.

Programa 4 - Problema dos Leitores e Escritores

Este é mais um problema com grande relevância prática. Sua principal aplicação é a modelagem de acesso a um banco de dados. Quando se acessa um banco de dados, é interessante que muitos leitores possam acessá-lo simultaneamente, contudo, deseja-se que quando alguém vá escrever nele, este escritor tenha direito de exclusividade, para evitar erros.
O código-fonte é mostrado abaixo:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
 
void le_texto(int);                      // Protótipos das funções
void interpreta_texto(int);
void pensa_novo_texto(int);
void escreve_novo_texto(int);
 
pthread_mutex_t mutex, caderno;       // Declarações dos semáforos
int rc = 0;   // numero de processos lendo ou querendo ler
 
void le_texto(int a){
  printf("Leitor %d: Lendo caderno (Regiao critica)\n",a);
  srand(time(NULL));
  sleep(rand()%2 + 1);
}
 
void interpreta_texto(int a){
  printf("Leitor %d: Interpretando (Regiao não-critica)\n",a);
  srand(time(NULL));
  sleep(rand()%2 + 1);
}
 
void pensa_novo_texto(int a){
  printf("Escritor %d: Pensando em novo texto (Regiao não-critica)\n",a);
  srand(time(NULL));
  sleep(rand()%2 + 1);
}
 
void escreve_novo_texto(int a){
  printf("Escritor %d: Escrevendo no caderno (Região critica)\n",a);
  srand(time(NULL));
  sleep(rand()%2 + 1);
}
 
void * reader(void *a)
{
 int k = *(int *)a;              // Converte para o int
 
 while(1)
  {
    pthread_mutex_lock(&mutex);            // Obtem acesso à região critica rc
    rc++;                                               // Mais um leitor
    if(rc==1) pthread_mutex_lock(&caderno);  // Obtém acesso exclusivo aos leitores na região critica caderno
    pthread_mutex_unlock(&mutex);        // Sai da região critica rc
    le_texto(k);      // acessa dados em região critica
 
    // Leitor quer sair
    pthread_mutex_lock(&mutex);            // Obtem acesso a regiao critica rc
    rc--;                                                  // Um leitor a menos
    if(rc==0) pthread_mutex_unlock(&caderno);  // Abre o acesso à região critica caderno
    pthread_mutex_unlock(&mutex);                 // Sai da região critica rc
    interpreta_texto(k);      // acesso em região não-critica
  }
}
 
void * writer(void *a)
{
int k = *(int *)a;
 while(1)
  {
    pensa_novo_texto(k);    // produz texto
    pthread_mutex_lock(&caderno);  // obtém acesso exclusivo ao caderno
    escreve_novo_texto(k);           // escreve no caderno
    pthread_mutex_unlock(&caderno);   // libera o caderno
  }
}
 
int main(){
   pthread_mutex_init(&mutex,NULL);     // inicia os mutexes
   pthread_mutex_init(&caderno,NULL);
   int leitor[] = {1, 2, 3, 4, 5};
   int escritor[] = {1, 2, 3};
 
   pthread_t leitores[5];                // declara as threads
   pthread_t escritores[3];
   int j;
   for(j=0;j<3;j++)
     {
    pthread_create(&escritores[j],NULL,writer,(void*)&escritor[j]);            // inicia as threads de escritores
     }
 
   for(j=0;j<5;j++)
     {
    pthread_create(&leitores[j],NULL,reader,(void*)&leitor[j]);                  // inicia as threads de leitores
     }
 
   pthread_join(leitores[0],NULL);  // A main espera mulheres[0] terminar antes de finalizar.
 
return 0;
}

Os resultados obtidos foram obtidos no terminal:

alexandre@alexandre-laptop:~$ ./programa4
Escritor 1: Pensando em novo texto (Regiao não-critica)
Escritor 2: Pensando em novo texto (Regiao não-critica)
Escritor 3: Pensando em novo texto (Regiao não-critica)
Leitor 1: Lendo caderno (Regiao critica)
Leitor 2: Lendo caderno (Regiao critica)
Leitor 3: Lendo caderno (Regiao critica)
Leitor 4: Lendo caderno (Regiao critica)
Leitor 5: Lendo caderno (Regiao critica)
Leitor 1: Interpretando (Regiao não-critica)
Leitor 2: Interpretando (Regiao não-critica)
Leitor 3: Interpretando (Regiao não-critica)
Leitor 4: Interpretando (Regiao não-critica)
Leitor 5: Interpretando (Regiao não-critica)
Escritor 1: Escrevendo no caderno (Região critica)
Escritor 2: Escrevendo no caderno (Região critica)
Escritor 1: Pensando em novo texto (Regiao não-critica)
Escritor 3: Escrevendo no caderno (Região critica)
Escritor 2: Pensando em novo texto (Regiao não-critica)
Escritor 2: Escrevendo no caderno (Região critica)
Escritor 3: Pensando em novo texto (Regiao não-critica)
Escritor 1: Escrevendo no caderno (Região critica)
Escritor 2: Pensando em novo texto (Regiao não-critica)
Leitor 5: Lendo caderno (Regiao critica)
Leitor 4: Lendo caderno (Regiao critica)
Leitor 3: Lendo caderno (Regiao critica)
Leitor 2: Lendo caderno (Regiao critica)
Leitor 1: Lendo caderno (Regiao critica)
Escritor 1: Pensando em novo texto (Regiao não-critica)
Leitor 5: Interpretando (Regiao não-critica)
Leitor 4: Interpretando (Regiao não-critica)
Leitor 3: Interpretando (Regiao não-critica)
Leitor 1: Interpretando (Regiao não-critica)
Escritor 3: Escrevendo no caderno (Região critica)
Leitor 2: Interpretando (Regiao não-critica)
Leitor 3: Lendo caderno (Regiao critica)
Leitor 5: Lendo caderno (Regiao critica)
Leitor 4: Lendo caderno (Regiao critica)
Leitor 2: Lendo caderno (Regiao critica)
Escritor 3: Pensando em novo texto (Regiao não-critica)
Leitor 1: Lendo caderno (Regiao critica)
Leitor 3: Interpretando (Regiao não-critica)
Leitor 5: Interpretando (Regiao não-critica)
Leitor 4: Interpretando (Regiao não-critica)
Leitor 2: Interpretando (Regiao não-critica)
Escritor 1: Escrevendo no caderno (Região critica)
Leitor 1: Interpretando (Regiao não-critica)
^C

Uma tela de outro teste é apresentada abaixo:

programa4.png

Exercicio 1

A implementação do exercício 1 da prova é mostrado abaixo:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
 
pthread_mutex_t mutex_homem, mutex_mulher, mutex_banheiro;
int homem = 0;   // numero de homens
int mulher = 0;  // numero de mulheres
 
void entra_homem(int k){
 printf("Homem %d: Entrei!\n",k);
// sleep(1);
}
 
void entra_mulher(int k){
 printf("Mulher %d: Entrei!\n",k);
 //sleep(1);
}
 
void sai_homem(int k){
 printf("Homem %d: Sai!\n",k);
}
 
void sai_mulher(int k){
 printf("Mulher %d: Sai!\n",k);
}
 
void * homem_quer_entrar(void *a)
{
 int k = *(int *)a;
 
 while(1)
  {
    pthread_mutex_lock(&mutex_homem);                  // Obtem acesso exclusivo a homem
    homem++;                                           // Mais um homem
    if(homem==1) pthread_mutex_lock(&mutex_banheiro);  // Se for o primeiro homem obtem acesso exclusivo a banheiro
    pthread_mutex_unlock(&mutex_homem);                // Libera acesso exclusivo a homem
    entra_homem(k);                                       // acessa dados em região critica
    usleep(1000000);
    // Homem quer sair
    pthread_mutex_lock(&mutex_homem);                  // Obtem acesso exclusivo a homem
    homem--;                                           // Menos um homem
    sai_homem(k); 
    if(homem==0) pthread_mutex_unlock(&mutex_banheiro);// Se for o ultimo homem libera acesso exclusivo a banheiro
    pthread_mutex_unlock(&mutex_homem);                // Libera acesso exclusivo a homem
  }
}
 
void * mulher_quer_entrar(void *a)
{
 int k = *(int *)a;
 
 while(1)
  {
    pthread_mutex_lock(&mutex_mulher);                  // Obtem acesso exclusivo a mulher
    mulher++;                                           // Mais uma mulher
    if(mulher==1) pthread_mutex_lock(&mutex_banheiro);   // Se for a primeira mulher
    pthread_mutex_unlock(&mutex_mulher);                // Libera acesso exclusivo a mulher
    entra_mulher(k);                                        // acessa dados em região critica
    usleep(300000);
    // Mulher quer sair
    pthread_mutex_lock(&mutex_mulher);                  // Obtem acesso exclusivo a mulher
    mulher--;                                           // Menos uma mulher
    sai_mulher(k);
    if(mulher==0) pthread_mutex_unlock(&mutex_banheiro); // Se for a ultima mulher
    pthread_mutex_unlock(&mutex_mulher);                // Libera acesso exclusivo a mulher
  }
}
 
int main(){
   pthread_mutex_init(&mutex_homem,NULL);
   pthread_mutex_init(&mutex_mulher,NULL);
   pthread_mutex_init(&mutex_banheiro,NULL);
   int mulher[] = {1, 2, 3, 4, 5};
   int homem[] = {1, 2, 3};
   srand(time(NULL)); 
 
   pthread_t mulheres[5];
   pthread_t homens[3];
   int j;
   for(j=0;j<3;j++)
     {
    pthread_create(&homens[j],NULL,homem_quer_entrar,(void*)&homem[j]);
     }
 
   for(j=0;j<5;j++)
     {
    pthread_create(&mulheres[j],NULL,mulher_quer_entrar,(void*)&mulher[j]);
     }
 
   pthread_join(mulheres[0],NULL);  // A main espera leitores[0] terminar antes de finalizar.
 
return 0;
}

Um resultado obtido para essa implementação é mostrado abaixo:

Homem 1: Entrei!
Homem 2: Entrei!
Homem 3: Entrei!
Homem 1: Sai!
Homem 1: Entrei!
Homem 2: Sai!
Homem 2: Entrei!
Homem 3: Sai!
Homem 3: Entrei!
Homem 2: Sai!
Homem 1: Sai!
Homem 1: Entrei!
Homem 2: Entrei!
Homem 3: Sai!
Homem 3: Entrei!
Homem 2: Sai!
Homem 2: Entrei!
Homem 1: Sai!
Homem 3: Sai!
Homem 3: Entrei!
Homem 1: Entrei!
Homem 2: Sai!
Homem 3: Sai!
Homem 1: Sai!
Mulher 5: Entrei!
Mulher 4: Entrei!
Mulher 3: Entrei!
Mulher 2: Entrei!
Mulher 1: Entrei!
Mulher 3: Sai!
Mulher 2: Sai!
Mulher 2: Entrei!
Mulher 1: Sai!
Mulher 1: Entrei!
Mulher 3: Entrei!
Mulher 4: Sai!
Mulher 4: Entrei!
Mulher 5: Sai!
Mulher 5: Entrei!
Mulher 3: Sai!
Mulher 3: Entrei!

Exercicio 7

A implementação do exercício 7 da prova foi feita de duas maneiras diferentes. A primeira, com apenas um sender e um receiver é mostrada abaixo. Em seguida, é mostrada a segunda solução, com M senders e N receivers, atuando sobre um mesmo buffer.

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
#define N 100
 
void produz_mensagem(void);
void insere_mensagem(void);
void retira_mensagem(void);
void le_mensagem(void);
void * sender(void *a);
void * receiver(void *a);
 
int inicio_fila=0;
int fim_fila=0;
int fila[N];
 
int mensagem;
int mail_box;
sem_t mutex, empty, full;
 
void produz_mensagem(void){
  srand(time(NULL));
  mensagem = rand()%1000;
}
 
void insere_mensagem(void){
  fila[fim_fila] = mensagem;
  fim_fila = (fim_fila+1)%N;
  printf("inseri %d\n",mensagem);
}
 
void retira_mensagem(void){
  mail_box = fila[inicio_fila];
  inicio_fila = (inicio_fila+1)%N;
}
 
void le_mensagem(void){
  printf("Caixa de Entrada: %d\n",mail_box);
}
 
void * sender(void *a)
{
   while (1)
    {
    produz_mensagem();
    sem_wait(&empty);
    sem_wait(&mutex);
    insere_mensagem();
    sem_post(&mutex);
    sem_post(&full);
        srand(time(NULL));
      sleep(rand()%2+1);
    }
}
 
void * receiver(void *a)
{
   while (1)
    {
    sem_wait(&full);
    sem_wait(&mutex);
    retira_mensagem();
    sem_post(&mutex);
    sem_post(&empty);
    le_mensagem();
        srand(time(NULL));
      sleep(rand()%3+1);   
    }
}
 
int main()
{
    sem_init(&mutex,0,1);
    sem_init(&full,0,0);
    sem_init(&empty,0,N);
 
    pthread_t* senders;
       pthread_t* receivers;
 
    senders = (pthread_t*) malloc(sizeof(pthread_t));
    receivers = (pthread_t*) malloc(sizeof(pthread_t));
  int j;
    pthread_create(senders,NULL,sender,NULL);
    pthread_create(receivers,NULL,receiver,NULL);
 
   pthread_join(*senders,NULL);  // A main espera a thread sender terminar antes de finalizar.
 
return 0;
}

Um resultado obtido para a execução foi:

alexandre@alexandre-laptop:~$ ./exercicio7
inseri 487
Caixa de Entrada: 487
inseri 171
Caixa de Entrada: 171
inseri 958
Caixa de Entrada: 958
inseri 243
Caixa de Entrada: 243
inseri 347
Caixa de Entrada: 347
inseri 746
inseri 82
Caixa de Entrada: 746
inseri 88
Caixa de Entrada: 82
inseri 24
inseri 595
Caixa de Entrada: 88
inseri 277
inseri 832
Caixa de Entrada: 24
inseri 684
Caixa de Entrada: 595
inseri 201
Caixa de Entrada: 277
Caixa de Entrada: 832
inseri 39
Caixa de Entrada: 684
inseri 128
inseri 761
Caixa de Entrada: 201
inseri 403
Caixa de Entrada: 39

A segunda solução é mostrada abaixo:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <math.h>
#define N 100
 
void produz_mensagem(int);
void insere_mensagem(int);
void retira_mensagem(int);
void le_mensagem(int);
void * sender(void *a);
void * receiver(void *a);
 
int inicio_fila=0;
int fim_fila=0;
int fila[N];
 
int mensagem[7];
int mail_box[6];
sem_t mutex, empty, full;
 
void produz_mensagem(int i){
 mensagem[i] = 10000*i + 1 + mensagem[i]%10;
}
 
void insere_mensagem(int i){
  fila[fim_fila] = mensagem[i];
  fim_fila = (fim_fila+1)%N;
  printf("Sender %d insere: %d\n",i,mensagem[i]);
}
 
void retira_mensagem(int i){
  mail_box[i] = fila[inicio_fila];
  fila[inicio_fila] = -1;
  inicio_fila = (inicio_fila+1)%N;
  printf("Receiver %d recebe: %d\n",i,mail_box[i]);
}
 
void le_mensagem(int k){
  // Le mensagem
}
 
void * sender(void *a)
{
 int k = *(int *)a;
   while (1)
    {
    produz_mensagem(k);
    sem_wait(&empty);
    sem_wait(&mutex);
    insere_mensagem(k);
     sem_post(&mutex);
    sem_post(&full);
        sleep(rand()%3+1);
    }
}
 
void * receiver(void *a)
{
 int k = *(int *)a;
   while (1)
    {
    sem_wait(&full);
    sem_wait(&mutex);
    retira_mensagem(k);
      sem_post(&mutex);
    sem_post(&empty);
    le_mensagem(k);
    sleep(rand()%3+1);   
 
    }
}
 
int main()
{
    srand(time(NULL));
    sem_init(&mutex,0,1);
    sem_init(&full,0,0);
    sem_init(&empty,0,N);
 
    int envia[] = {0, 1, 2, 3, 4, 5, 6};
    int recebe[] = {0, 1, 2, 3, 4, 5};
 
    pthread_t senders[7];
       pthread_t receivers[6];
 
  int j;
   for(j=0;j<7;j++)
     {
    pthread_create(&senders[j],NULL,sender,(void*)&envia[j]);
     }
 
   for(j=0;j<6;j++)
     {
    pthread_create(&receivers[j],NULL,receiver,(void*)&recebe[j]);
     }
 
   pthread_join(*senders,NULL);  // A main espera a thread sender[0] terminar antes de finalizar.
 
return 0;
}

Um resultado obtido para a segunda execução é mostrado abaixo:
Sender 0 insere: 1
Sender 1 insere: 10001
Sender 2 insere: 20001
Sender 3 insere: 30001
Sender 4 insere: 40001
Sender 5 insere: 50001
Sender 6 insere: 60001
Receiver 0 recebe: 1
Receiver 1 recebe: 10001
Receiver 2 recebe: 20001
Receiver 3 recebe: 30001
Receiver 4 recebe: 40001
Receiver 5 recebe: 50001
Sender 0 insere: 2
Sender 3 insere: 30002
Sender 6 insere: 60002
Receiver 2 recebe: 60001
Receiver 5 recebe: 2
Sender 1 insere: 10002
Sender 5 insere: 50002
Receiver 4 recebe: 30002
Receiver 5 recebe: 60002
Sender 2 insere: 20002
Sender 1 insere: 10003
Sender 4 insere: 40002
Sender 0 insere: 3
Sender 6 insere: 60003
Receiver 1 recebe: 10002
Receiver 0 recebe: 50002
Receiver 3 recebe: 20002
Receiver 2 recebe: 10003
Sender 3 insere: 30003
Sender 0 insere: 4
Sender 6 insere: 60004
Receiver 2 recebe: 40002
Receiver 4 recebe: 3
Receiver 5 recebe: 60003
Sender 5 insere: 50003
Sender 0 insere: 5
Sender 1 insere: 10004
Receiver 1 recebe: 30003
Receiver 0 recebe: 4
Receiver 5 recebe: 60004

O resultado acima mostra a mensagem que é criada por cada um dos Senders e como ela é recebida pelos Receivers, na ordem da fila.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License