Laboratorio 4

Neste laboratorio a tarefa foi implementar o problema dos leitores e escritores utilizando threads e sincronizacao por semaforos no Linux.

Inicialmente e pedido o numero de escritores e leitores. Inicia-se uma thread para cada leitor e escritor. Conforme um intervalo de tempo aleatorio os escritores geram novos dados e os leitores tentam ler dados.

A solucao apresentada possui a opcao de finalizar o programa, setando uma variavel de controle protegida por sincronizacao e aguardando pelo termino das threads.

Apresento abaixo o codigo da solucao.

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
 
typedef struct
{
    int n[6];
} dados;
 
//globais
sem_t s_db, s_continua, s_mutex; 
int v_continua = 1;
int rc = 0;
//buffer em que cada leitor escreve numa posicao
dados* buffer;
int n_escritores, n_leitores;
 
//funcoes de manipulacao dos semaforos
void down(sem_t* semaphore)
{
    sem_wait(semaphore);    
}
 
void up(sem_t* semaphore)
{
    sem_post(semaphore);    
} 
 
int continua()
{
    int ret;
    down(&s_continua);
    ret = v_continua;
    up(&s_continua);
    return ret;
}
 
void seta_continua(int v)
{
    down(&s_continua);
    v_continua = v;    
    up(&s_continua);
}
 
dados gera_dados()
{
    dados d;
    int i;
    //espera um tempo para ter dados
    sleep(random() % 10);    
    for (i = 0; i < 6; i++)
    {
        d.n[i] = random() % 100;
    }
    return d;
} 
 
void escreve_dados(dados d, int index)
{
    printf("Escritor %d: Escreve dados\n", index);    
    buffer[index] = d;
}
 
void* escritor(void* arg)
{
    int index = *((int*)arg);
    dados d;
    while (continua())
    {
        d = gera_dados();
        down(&s_db);    
        escreve_dados(d, index);
        up(&s_db);
    }
}
 
dados le_dado()
{
    //retorna uma posicao aleatorio
    return buffer[random() % n_escritores];
}
 
void mostra_dados(dados d)
{
    int i;
    printf("Dados lidos:\n\t");
    for (i = 0; i < 6; i++)
    {
        printf("N%d:%d ", i + 1, d.n[i]);
    }
    printf("\n");
}
 
void* leitor(void* arg)
{
    int index = *((int*)arg);
    dados d;
    while (continua())
    {
        //aguarda um tempo para ler
        sleep(random() % 10);
        down(&s_mutex);    
        rc++;
        if (rc == 1) down(&s_db);
        up(&s_mutex);
        d = le_dado();        
        down(&s_mutex);
        rc--;    
        if (rc == 0) up(&s_db);
        up(&s_mutex);
        printf("Leitor %d: ", index);    
        mostra_dados(d);
    }
}
 
int main()
{
 
    pthread_t* threads;
    void* thread_ret;
    srand(time(0));
    printf("Numero de escritores: ");
    scanf("%d", &n_escritores);
    printf("Numero de leitores: ");
    scanf("%d", &n_leitores);
    //aloca buffer de dados
    if ((buffer = malloc(sizeof(dados) * n_escritores)) == 0)
    {
        printf("Erro ao alocar memoria para os dados\nSaindo ...\n");
        return -1;
    }    
    //inicia semaforos
    if (sem_init(&s_db, 0, 1) != 0)
    {
        printf("Erro ao iniciar semaforo de dados\nSaindo...\n");
        return -1;
    }
    if (sem_init(&s_continua, 0, 1) != 0)
    {
        printf("Erro ao iniciar semaforo de controle\nSaindo...\n");
        return -1;
    }
    if (sem_init(&s_mutex, 0, 1) != 0)
    {
        printf("Erro ao iniciar semaforo de exclusao mutua\nSaindo...\n");
        return -1;
    }
    //aloca memoria para os identificadores das threads dos clientes
    if ((threads = malloc(sizeof(pthread_t) * (n_escritores + n_leitores))) == 0)
    {
        printf("Erro ao alocar memoria para os identificadores das threads\nSaindo...\n");
        return -1;
    }
    //cria threads
    int i, threads_criadas;
    int* index;    
    printf(">>>>>>>>>> 's' para sair <<<<<<<<<<<<<\n");
    for (i = 0; i < n_escritores + n_leitores; i++)
    {
        if (i < n_escritores)
        {
            index = malloc(sizeof(int));
            *index = i;
            if (pthread_create(&threads[i], 0, escritor, index) != 0)
            {
                printf("Erro ao criar thread para escritor\nSaindo...\n");
                seta_continua(0);
                break;
            }            
        }
        else
        {
            index = malloc(sizeof(int));
            *index = i - n_escritores;
            if (pthread_create(&threads[i], 0, leitor, index) != 0)
            {
                printf("Erro ao criar thread para leitor\nSaindo...\n");
                seta_continua(0);
                break;
            }            
        }
    }
    threads_criadas = i;
    if (continua())
    {
        char op;
        do
        {
            scanf("%c", &op);
        } while (op != 's' && op != 'S');
        //seta fim do programa
        seta_continua(0);
    }    
    //espera pelas threads
    printf("Aguardando termino das threads\n");
    for (i = 0; i < threads_criadas; i++)
    {
        if (pthread_join(threads[i], &thread_ret) != 0)
        {
            printf("Erro ao executar join com thread\nSaindo ...\n");
            return -1;
        }
    }
    //libera memoria alocada
    free(threads);
    free(buffer);
    return 0;
}

Apresento abaixo a execucao do programa

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