Pthreads-如何解决此并发问题

时间:2019-04-20 16:00:03

标签: c

该程序包含一个称为循环缓冲区的单独文件,该文件的头和线程测试。该程序应该执行的操作是,创建一个具有所需大小的缓冲区,然后告诉他从该缓冲区中添加/删除数字。例如,。/ program 3 2 1将创建一个大小为3的缓冲区,并将向缓冲区中添加2个元素并删除1。问题是我无法控制并发性,就像我在运行程序时那样将添加1->删除1->添加1。我希望它添加/删除在切换到下一部分之前询问的次数。

我尝试了其他选项,例如添加互斥锁或变量,但是我做错了什么。我将在下面添加需要更改的代码部分:

//THIS IS THE HEADER OF BUFFER_CIRCULAR.h
#ifndef _BUFFER
#define _BUFFER
// Definición de la estructura búfer 
// El búfer no tiene tamaño fijo
struct Buffer_Circular {
    long *Buff; // Puntero al bloque de memoria dónde se almacenan los item
    int Nelementos; // Número máximo de elementos que se pueden almacenar
    int Extrae; // Indica la posición del próximo item a extraer
    int Inserta;    // Indica dónde se insertará el próximo item a almacenar
    int Pendientes_Consumir;    // Indica el número de items que aún no han sido extraídos
};

// Función de creación del búfer circular
// Parámetro de entrada:
//  Capacidad: número máximo de elementos que pueden ser almacenados
// Devuelve
//  Si no hay error retorna valor cero, en caso contrario devuelve un valor negativo
int Crea_Buffer(int Capacidad);

// Función que inserta un item en el búfer
// Parámetros de entrada:
//  Nuevo item a almacenar en el búfer
void *Inserta_Item(void *item);

// Función que extrae un item del búfer
// Parámetros de entrada:
//  Puntero que almacenará el item a extraer
void *Extrae_Item(void *item);

// Función que retorna el número de ítems pendientes de consumir
int Num_Pendientes_Consumir();

// Función que retorna la capacidad máxima del búfer
int Capacidad_Buffer();
#endif

// THIS IS CIRCULAR_BUFER DOC

#include <stdlib.h> // Requerido para malloc
#include <unistd.h>  // Requerido para Sleep  
#include <stdio.h>   // Requerido para lecturas y escrituras en los canales de entrada/salida


// Se incluye fichero cabecera en el que se declara los tipos y funciones de manejo del buffer circular
#include "Buffer_Circular.h"

// Puntero a una estructura de tipo Buffer_Circular
struct Buffer_Circular *Buffer=NULL;

// Función de creación del búfer circular
int Crea_Buffer(int Capacidad)
{
    long *p0;   
    struct Buffer_Circular *p1;
    int i;

    if (Capacidad <= 0) return -1;
    p0 = malloc( sizeof(long) * Capacidad);
    p1 = malloc(sizeof(struct Buffer_Circular));
    if ( (p0 != NULL) && (p1 != NULL) ) {
        Buffer = p1;
        Buffer->Buff = p0;
        Buffer->Inserta = 0;
        Buffer->Extrae = 0;
        Buffer->Nelementos = Capacidad;
        Buffer->Pendientes_Consumir = 0;
        for(i=0;i<Capacidad;i++) Buffer->Buff[i]=-1;
        return 0;
    }
    else {
        return -1;
    }
}


// Función que retorna el número de ítems pendientes de consumir
int Num_Pendientes_Consumir(){
return Buffer->Pendientes_Consumir;
}

// Función que retorna la capacidad máxima del búfer
int Capacidad_Buffer(){
return Buffer->Nelementos;
}

// Inserta un item en el búfer y actualiza los campos de datos del búfer
void *Inserta_Item(void *item)
{
    Buffer->Buff[Buffer->Inserta] = (long)item;
    if ( (long)item % 2 )
        sleep(1);
    printf("Se ha insertado en %d el item %ld\n",Buffer->Inserta,(long)item);
    Buffer->Inserta = (Buffer->Inserta+1) % Buffer->Nelementos;
    Buffer->Pendientes_Consumir++;
}

// Extrae un elemento del búfer y actualiza los campos de datos del búfer
void *Extrae_Item(void *item)
{
    item = (void *)(Buffer->Buff[Buffer->Extrae]);
    Buffer->Buff[Buffer->Extrae] = -1;
    printf("Se extrajo de %d el item %ld\n",Buffer->Extrae,(long)item);
    Buffer->Extrae = (Buffer->Extrae+1) % Buffer->Nelementos;
    Buffer->Pendientes_Consumir--;
}
// Prueba concurrente de acceso al búfer
// Se lanzan hilos productores y consumidores
// Al no haber sincronización entre los hilos,
// el resultado es que se puede corromper el búfer

//Archivos cabecera del sistema
#include <stdlib.h> // Requerido para atoi
#include <stdio.h> // Requerido para printf
#include <errno.h>
#include <pthread.h>
#include "Buffer_Circular.h"

// Función que comprueba y captura los parámetros pasados por línea de órdenes
void Comprobar_Argumentos(int argc, char *argv[], int *dim, int *np, int *nc);

// Hilo Productor: inserta un item en el búfer
void *Productor(void *item);

// Hilo Consumidor: extrae un item del búfer
void *Consumidor(void *item);

// Rutina que lanza los hilos productores y consumidores
void test_recurso_hilos(int np, int nc);


// Función que comprueba y captura los parámetros pasados por línea de órdenes
void Comprobar_Argumentos(int argc, char *argv[], int *dim, int *np, int *nc){
    if (argc != 4) {
        fprintf(stderr,"Invocación incorrecta: ./fich_ejec dim_buff num_prod num_cons\n");      
        exit(-1);
    }

    *dim = atoi(argv[1]);
    if (*dim<1) {
        fprintf(stderr,"Invocación incorrecta. La dimensión del búfer debe ser >0: ./fich_ejec dim_buff num_prod num_cons\n");
        exit(-1);
    }

    *np = atoi( argv[2] );
    if ( *np < 0 ) {
        fprintf(stderr,"Invocación incorrecta. El número de hilos productores debe ser >0: ./fich_ejec dim_buff num_prod num_cons\n");
        exit(-1);
    }

    *nc = atoi( argv[3] );
    if ( *nc < 0 ) {
        fprintf(stderr,"Invocación incorrecta. El número de hilos consumidores debe ser >0: ./fich_ejec dim_buff num_prod num_cons\n");
        exit(-1);
    }   
}

// this is the part from the tests that needs to be changed
//Num_Pendientes_Consumir() returns the number of how many are left to consume
//Capacidad_Buffer() returns the size of the buffer

// Producer thread: adds item to buffer. 
void *Productor(void *item){
    while (Num_Pendientes_Consumir() == Capacidad_Buffer()) ;

    Inserta_Item(item);
    pthread_exit(NULL);
}

// Extracting thread: extracts item from buffer
void *Consumidor(void *item)
{
    while (Num_Pendientes_Consumir() == 0) ;
    Extrae_Item(item);
    pthread_exit(NULL);
}

// Rutina que lanza los hilos productores y consumidores
void test_recurso_hilos(int np, int nc)
{
  pthread_t *productores;
  pthread_t *consumidores;
  int ret;
  long int i;
  void* dummy;

  productores=malloc(np*sizeof(pthread_t));
  if (productores==NULL) {
    fprintf(stderr,"Error en la petición de memoria para pthread_t productores\n");
    exit(-1);
  }

  consumidores=malloc(nc*sizeof(pthread_t));
  if (consumidores==NULL) {
    fprintf(stderr,"Error en la petición de memoria para pthread_t consumidores\n");
    exit(-1);
  }

  for(i=0; i<np; i++) {
    ret = pthread_create(&productores[i], NULL, Productor, (void *)i);
    if (ret) {
    errno=ret;
    fprintf(stderr,"error %d: %s\n",errno,strerror(errno));
        exit(-1);
    }
  }

  for (i=0; i<nc; i++) {
    ret=pthread_create(&consumidores[i], NULL, Consumidor, (void *)i);
    if (ret) {
    errno=ret;
    fprintf(stderr,"error %d: %s\n",errno,strerror(errno));
        exit(-1);
    }
  }

  for(i=0;i<np;i++) {
    ret=pthread_join(productores[i],&dummy);
    if (ret) {
    errno=ret;
    fprintf(stderr,"Error %d en el join del hilo productor %d: %s\n",errno,i,strerror(errno));
    exit(-1);
    }
  }

  for(i=0;i<nc;i++) {
    ret=pthread_join(consumidores[i],&dummy);
    if (ret) {
    errno=ret;
    fprintf(stderr,"Erro %d en el join del hilo consumidor %d: %s\n",errno,i,strerror(errno));
    exit(-1);
    }
  }
}

// Función main:
// Invocación:
//  # ./fich_ejec dim_buff num_prod num_cons
//  fich_ejec: nombre del archivo que contiene el código ejecutable
//  dim_buff: dimensión del búfer (>0)
//  num_prod: número de hilos productores (>=0)
//  num_cons: número de hilos consumidores (>=0)
//
int main(int argc, char *argv[]) {
  int dim,np,nc;

  printf("»»» Comienza la prueba del búfer...\n");
  Comprobar_Argumentos(argc, argv,&dim,&np,&nc);
  if (Crea_Buffer(dim) < 0) {
    fprintf(stderr,"Error al crear buffer\n");
    exit(-1);
  }
  test_recurso_hilos(np,nc);
  printf("»»» Fin de la prueba del búfer\n");
  exit(0);
}

0 个答案:

没有答案