Ex2 Fabio Imada

retornar

Implementação do send() e receive()

Introdução

Este problema foi proposto para que se analizasse a implementação dos métodos send() e receive() de mensagens para uma caixa de tamanho limitado.
Isto implica que:

  • Só é possível enviar mensagens se a caixa não estiver cheia, nesse caso o remetente deve aguardar até que haja espaço na caixa para enviar as mensagens.
  • Quando a caixa de mensagens estiver vazia, o destinatário fica aguardando a chegada de alguma mensagem.

Foi criada uma solução para comunicação de duas threads através de uma "caixa de mensagens" compartilhada. Como o foco era a verificação do funcionamento correto dos métodos de send e receive, foram utilizados apenas um consumidor e um produtor.
Para implementar a caixa de mensagens foi considerado que as mensagens seriam inteiros e a caixa, uma fila de inteiros.

A limitação do tamanho da caixa foi feita através dos semáforo. Portanto, apesar de ter-se utilizado uma fila "infinita", caso a fila tivesse tamanho limitado, não haveria diferença no funcionamento do programa.

Desenvolvimento

O método equivalente ao send() é o método envio_seguro(), enquanto o equivalente ao receive() é o recebimento_seguro().
Para implementaćão dos métodos, foi utilizada uma fila como caixa de mensagens para que as primeiras mensagens enviadas fossem as primeiras recebidas. Depois disso, o problema era com relaćão à protećão da caixa, isto é, como garantir que quando ela estivesse cheia não seriam enviadas mais nenhuma mensagens, ou quando estivesse vazia, nenhuma mensagem seria "retirada". Para isso, protegeu-se com um mutex o acesso à caixa e antes de ganhar o acesso à caixa, colocou-se um semáforo, para que nada fosse enviado quando a caixa estivesse cheia e nada recebido quando estivesse vazia.
Além disso, simulou-se um tempo de processamento da mensagem para que as mensagens não fossem enviadas "simultaneamente" e nem recebidas imediatamente.

Conteúdo do arquivo mensagens.c

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
 
#define N    6    /* Capacidade da caixa de mensagens */
#define TRUE    1
#define FALSE    0
 
/* Caixa de mensagem */
typedef struct msg {
    int valor;
    struct msg *link;
} msg;
 
typedef struct {
    msg *primeiro;
    msg *ultimo;
} caixa_msg;
 
void envia(caixa_msg *q, int valor) {
    msg *mensagem;
    mensagem = malloc(sizeof(msg));
    if (mensagem == NULL)
        exit(EXIT_FAILURE);
    mensagem->valor = valor;
    mensagem->link = NULL;
    if (q->primeiro == NULL)
        q->primeiro = mensagem;
    else
        q->ultimo->link = mensagem;
    q->ultimo = mensagem;
}
 
int recebe(caixa_msg *q) {
    int result;
    msg *mensagem;
    mensagem = q->primeiro;
    if (mensagem == NULL) {
        printf("Erro: a fila esta vazia");
        exit(EXIT_FAILURE);
    }
    result = mensagem->valor;
    q->primeiro = mensagem->link;
    free(mensagem);
    return result;
}
/* Fim da caixa */
 
caixa_msg caixa;
sem_t cheio, vazio, mutex;
 
void envio_seguro(caixa_msg* destinatario, int mensagem) {
    sem_wait(&cheio);
    sem_wait(&mutex);
    envia(destinatario, mensagem);
    sem_post(&mutex);
    sem_post(&vazio);
}
 
int recebimento_seguro(caixa_msg* remetente) {
    int mensagem;
    sem_wait(&vazio);
    sem_wait(&mutex);
    mensagem = recebe(remetente);
    sem_post(&mutex);
    sem_post(&cheio);
    return mensagem;
}
 
void prod() {
    printf("Produtor Inicializado\n");
    int i, ultima = 3*N, msg;
    for (i = 1; i != 0 && i <= ultima; i++) {
        usleep(rand() % 200000);
        msg = i;
        if(i == ultima) msg = 0;
        envio_seguro(&caixa, msg);
        printf("Enviado: mensagem #%d\n", msg);
    }
    printf("Utima mensagem enviada!\n");
    pthread_exit("Produtor terminado\n");
}
 
void cons() {
    printf("Consumidor Inicializado\n");
    int continua = TRUE , i = 0;
    int mensagem;
    while (continua) {
        usleep(rand() % 600000);
        mensagem = recebimento_seguro(&caixa);
        printf("Recebido: mensagem #%d\n", mensagem);
        if(mensagem == 0) continua = FALSE;
    }
    pthread_exit("Consumidor terminado\n");
}
 
int main() {
    pthread_t th_consumidor, th_produtor;
    int res, res_parc;
 
    sem_init(&cheio, 0, N);
    sem_init(&vazio, 0, 0);
    sem_init(&mutex, 0, 1);
 
    /* Iniciando threads */
    res = 0;
    res_parc = pthread_create(&th_produtor, NULL, (void*) prod, NULL);
    res += res_parc;
    res_parc = pthread_create(&th_consumidor, NULL, (void*) cons, NULL);
    res += res_parc;
    if (res != 0) {
        perror("Erro em criacao de threads\n");
        exit(EXIT_FAILURE);
    }
 
    /* Juntar threads */
    res = 0;
    res_parc = pthread_join(th_produtor, NULL);
    res += res_parc;
    res_parc = pthread_join(th_consumidor, NULL);
    res += res_parc;
    if (res != 0) {
        perror("Erro em join threads\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

Screenshots

A tela abaixo apresenta o comando para compilar o programa e sua execução.

mensagens.png

retornar

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