lunes, 30 de abril de 2012

Implementación con pthread

Después de comentarlo con algún que otro entendido del irc, me comentaron que lo mejor era encapsular todo lo referente a mutex y condiciones dentro de la propia estructura de datos de la lista:


#ifndef SYNCLIST_H
#define SYNCLIST_H

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

struct synclist
{
  int max_size;
  int max_string_size;
  char **element;
  pthread_mutex_t mutex;
  pthread_cond_t read_done,write_done;
  int size;
};

void synclist_init(struct synclist *o,
           int max_size,int max_string_size)
{
  int i;
  pthread_mutex_init(&o->mutex,NULL);
  pthread_cond_init(&o->read_done,NULL);
  pthread_cond_init(&o->write_done,NULL);
  o->max_size = max_size;
  o->max_string_size = max_string_size;
  o->element = (char **)malloc(o->max_size*sizeof(char *));
  for(i=0;i<o->max_size;i++) {
    o->element[i] = (char *)malloc(o->max_string_size*sizeof(char));
  }
  o->size = 0;
}

void synclist_destroy(struct synclist *o)
{
  int i;
  pthread_mutex_lock(&o->mutex);
  pthread_mutex_destroy(&o->mutex);
  pthread_cond_destroy(&o->read_done);
  pthread_cond_destroy(&o->write_done);
  for(i=0;i<o->max_size;i++) {
    free(o->element[i]);
  }
  free(o->element);
}

void synclist_push(struct synclist *o,char *element)
{
  pthread_mutex_lock(&o->mutex);
  while ( o->size >= (o->max_size) ) {
    /* List is full, waiting for read_done */
    pthread_cond_wait(&o->read_done,&o->mutex);
  }
  /* Write and unlock */
  strncpy(o->element[o->size],element,o->max_string_size);
  o->size++;
  pthread_cond_signal(&o->write_done);
  pthread_mutex_unlock(&o->mutex);
}

void synclist_pop(struct synclist *o,char *element)
{
  pthread_mutex_lock(&o->mutex);
  while ( o->size <= 0 ) {
    /* Empty list, waiting for write_done */
    pthread_cond_wait(&o->write_done,&o->mutex);
  }
  /* Read and unlock */
  strncpy(element,o->element[o->size-1],o->max_string_size);
  o->size--;
  pthread_cond_signal(&o->read_done);
  pthread_mutex_unlock(&o->mutex);
}

#endif

A su vez, meterlo todo en la cabecera synclist.h y a continuación emplearla desde por ejemplo:


#include "synclist.h"
#include <stdio.h>

#define LIST_SIZE 10
#define BUFFER_SIZE 1024
#define READERS 5

void *writer(void *mysl)
{
  int counter = 0;
  char msg[BUFFER_SIZE];
  struct synclist *sl;
  sl = (struct synclist *)mysl;
  while ( 1 ) {
    sprintf(msg,"message #%d",counter);
    counter++;
    synclist_push(sl,msg);
    printf("Writing msg %s (list size %d) (thread id %d)\n",
            msg,sl->size,abs((unsigned int)pthread_self()));
    fflush(stdout);
  }
}

void *reader(void *mysl)
{
  char msg[BUFFER_SIZE];
  struct synclist *sl;
  sl = (struct synclist *)mysl;
  while ( 1 ) {
    synclist_pop(sl,msg);
    printf("Reading msg %s (list size %d) (thread id %d)\n",
       msg,sl->size,abs((unsigned int)pthread_self()));
    fflush(stdout);
  }
}

int main(int argc,char *argv[])
{
  struct synclist sl;
  char buffer[BUFFER_SIZE];
  pthread_t t[READERS+1];
  int i;
  synclist_init(&sl,LIST_SIZE,BUFFER_SIZE);
  pthread_create(&t[0],NULL,writer,(void *)&sl);
  for(i=0;i<READERS;i++) {
    pthread_create(&t[i+1],NULL,reader,(void *)&sl);
  }
  while ( 1 ) {
    continue;
  }
  synclist_destroy(&sl);
  return 0;
}


No hay comentarios:

Publicar un comentario