Buffer Limitato

From Sistemi Operativi
Jump to navigation Jump to search
Esercizio di programmazione concorrente:
Il programma genera 2 thread.
Il primo di questi, detto producer, prende i valori da stdin e li scrive su un buffer.
Il secondo, detto consumer, legge i valori dal buffer e li scrive su un file.
Requisiti:
- Il buffer è usato come array circolare
- Producer non deve scrivere su valori non ancora letti
- Consumer deve leggere i valori in ordine e senza ripetizioni

Soluzione di MV, usando i semafori

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define DIM_BUF 10
#define THREAD_SHARED 0

char buffer[DIM_BUF];
int next_write = 0, next_read = 0;	// indici sul buffer
sem_t empty;	// semaforo: consumer si blocca su di esso quando il buffer è vuoto
sem_t full;		// semaforo: producer si blocca su di esso quando il buffer è pieno

void* producer_routine(void *arg)
{
	char c;
	while(scanf("%c",&c) != EOF)	// legge ("produce") un carattere da stdin
	{
		if(sem_wait(&full) != 0)	// si blocca se il buffer è pieno
		{
			printf("Error %i in producer: %s",errno,strerror(errno));
			break;
		}
		
		buffer[next_write] = c;
		next_write = (next_write+1)%DIM_BUF;
	
		if(sem_post(&empty) != 0)	// segnala un nuovo carattere non letto sul buffer
		{
			printf("Error %i in producer: %s",errno,strerror(errno));
			break;
		}
	}
}

void* consumer_routine(void * arg)
{
	FILE *file;
	
	if( (file = fopen("./consumed.txt","a")) == NULL)
	{
		printf("Error %i in consumer: %s",errno,strerror(errno));
		return NULL;
	}
	
	while(1)
	{
		char c;
		
		if(sem_wait(&empty) != 0)	// se il buffer è vuoto si blocca
		{
			printf("Error %i in consumer: %s",errno,strerror(errno));
			break;
		}
		
		fprintf(file,"%c",buffer[next_read]);
		next_read = (next_read+1)%DIM_BUF;
		
		if(sem_post(&full) != 0)	// segnala che si è liberato un posto sul buffer
		{
			printf("Error %i in consumer: %s",errno,strerror(errno));
			break;
		}
	}
	close(file);
}

int main(int argc, char* argv[])
{
	pthread_t producer, consumer;
	int *error, i;
	
	for(i=0; i< DIM_BUF; i++)
		buffer[i] = 0;
	
	if(sem_init(&empty,THREAD_SHARED,0) != 0)	// inizializzato a 0 perchè il buffer è vuoto
		return errno;
	if(sem_init(&full,THREAD_SHARED,DIM_BUF) != 0)	// servono DIM_BUF scritture per riempirlo
		return errno;
	
	pthread_create(&producer,NULL,&producer_routine,NULL);
	pthread_create(&consumer,NULL,&consumer_routine,NULL);
	
	pthread_join(producer, (void**)&error);	// aspetta la terminazione di producer
	printf("End.\n");
	
	return 0;
}