该程序包含一个称为循环缓冲区的单独文件,该文件的头和线程测试。该程序应该执行的操作是,创建一个具有所需大小的缓冲区,然后告诉他从该缓冲区中添加/删除数字。例如,。/ 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);
}