Salve a tutti ragazzi , sto facendo un esercizio molto standard in cui ho un buffer con un solo campo e ho 5 processi produttori e 5 processi consumatori che si sincronizzano mediante un monitor di tipo signal and return : prima deve produrre un produttore , poi può consumare un consumatore e così via di seguito fino alla fine .
Io ho creato i file main.cpp,body.cpp,header.h,Makefile mentre quelli relativi al monitor mi sono stati già dati corretti e funzionanti. Il problema è che ottengo sempre l'errore "Errore di segmentazione (core dump creato)"
Il progetto prevede i seguenti file :
main.cpp :
[SPOILER]
codice:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "monitor.h"
#include "header.h"
using namespace std;
int main(){
//******PARTE DICHIARATIVA*******
pid_t pid;
key_t shmkey;
int shmid;
int stato;
int num_proc,num_cons,num_prod;
p_c_monitor* m;
//******PARTE ESECUTIVA**********
//inizializzo il numero di processi , di consumatori e di produttori
num_cons = 5 ;
num_prod = 5 ;
num_proc = num_cons + num_prod;
//inizializzo il monitor
init_monitor( &(m->M), NUMCOND );
//inizializzo il valore della chiave della shm che ospiterà la struct p_c_monitor
shmkey = IPC_PRIVATE;
//genero tale shm
shmid = shmget(shmkey, sizeof(p_c_monitor),IPC_CREAT|0664);
//attacco la shm
m = (p_c_monitor*) (shmat(shmid,0,0));
//inizializzo le variabili condition della mia struttura
m->ok_prod=1;
m->ok_cons=0;
//genero num_proc processi figli , metà produttori e metà consumatori
for(int i=0; i < num_proc ; i++){
if(pid==0){
if( (i%2)==0 ){ //Processo Conumatore
cout<<"sono il processo consumatore numero: "<<getpid()<<endl;
sleep(1);
consumazione(m);
}
else{ //Processo Produttore
cout<<"sono il processo produttore numero: "<<getpid()<<endl;
sleep(1);
produzione(m);
}
exit(0);
}
}
//attendo la terminazione dei figli
for(int i=0; i < num_proc ; i++){
pid = wait(&stato);
if(pid==-1)
cout<<"Errore\n";
else
cout<<"Il figlio numero: "<<pid<<" è terminato con stato: "<<stato<<endl;
}
//Rimuovo le strutture
shmctl(shmid,IPC_RMID,0);
remove_monitor( &(m->M) );
return 0;
}
[/SPOILER]
header.h
[SPOILER]
codice:
/*Si vuole realizzare il classico problema produttore consumatore con un unico buffer attraverso un'applicazione multiprocesso dove n processi sono produttori ed m processi sono consumatori e si vuole usare il costrutto monitor implementato come signal_and_return*/
//Definisco IL NUMERO delle variabili condition che mi servirà per la monitor_init e gli id che voglio usare per essi
#define NUMCOND 2
#define OK_PROD 0
#define OK_CONS 1
//definisco il monitor includendovi anche il buffer e l'implementazione di monitor già fatta e definisco il tipo di messaggio
typedef long msg;
typedef struct{
//variabili condition:
int ok_prod;
int ok_cons;
//buffer:
msg messaggio;
//monitor da usare già implementato:
Monitor M;
} p_c_monitor;
//definisco le funzioni
void produzione(p_c_monitor*);
void inizio_produzione(p_c_monitor*);
void fine_produzione(p_c_monitor*);
void consumazione(p_c_monitor*);
void inizio_consumazione(p_c_monitor*);
void fine_consumazione(p_c_monitor*);
[/SPOILER]
body.cpp
[SPOILER]
codice:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "monitor.h"
#include "header.h"
#include <sys/time.h>
using namespace std;
void produzione(p_c_monitor* m){
inizio_produzione(m);
struct timeval t1;
struct timezone t2;
gettimeofday(&t1,&t2);
m->messaggio = t1.tv_usec;
cout<<"Valore prodotto : "<<m->messaggio<<endl;
fine_produzione(m);
}
void inizio_produzione(p_c_monitor* m){
enter_monitor(&(m->M));
if( !(m->ok_prod) ) //se ok_prod non è verificata , è falsa , quindi non posso produrre, mi devo sospendere su questa condizione
wait_condition(&(m->M),OK_PROD);
}
void fine_produzione(p_c_monitor* m){
//aggiorno i valori delle variabili logiche stabilendo che il buffer è pieno e non si può più produrre ma si può consumare
m->ok_prod = 0;
m->ok_cons = 1;
//faccio una signal per sbloccare i consumatori in coda
signal_condition( &(m->M),OK_CONS);
//esco dal monitor
leave_monitor(&(m->M));
}
void consumazione(p_c_monitor* m){
inizio_consumazione(m);
cout<<"Il messaggio consumato è: "<<m->messaggio<<endl;
fine_consumazione(m);
}
void inizio_consumazione(p_c_monitor* m){
enter_monitor(&(m->M));
if(!(m->ok_cons))
wait_condition( &(m->M),OK_CONS);
}
void fine_consumazione(p_c_monitor* m){
m->ok_prod = 1;
m->ok_cons = 0;
signal_condition( &(m->M) , OK_PROD);
leave_monitor(&(m->M));
}
[/SPOILER]
monitor.h
[SPOILER]
codice:
/***PROTOTIPI DELLE PROCEDURE PER LA REALIZZAZIONE DEL COSTRUTTO MONITOR***/
typedef struct {
int mutex;
int num_var_cond;
//id del gruppo sem associati alle var.cond
int id_conds;
//array delle variabili condition_count
int *cond_counts;
//identificativo memoria condivisa
int id_shared;
} Monitor;
//monitor e numero di variabili condition
void init_monitor (Monitor*, int);
void enter_monitor(Monitor*);
void leave_monitor(Monitor*);
void remove_monitor(Monitor*);
void wait_condition(Monitor*,int);
void signal_condition(Monitor*,int);
[/SPOILER]
monitor.cpp
[SPOILER]
codice:
/*************************************Monitor*************************************************/
// Implementazione di un Monitor
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#include "monitor.h"
//Funzioni di utilita' private alla libreria Monitor
static void Wait_Sem(int, int);
static void Signal_Sem (int,int);
static int Queue_Sem (int,int); //restituisce il num di processi in attesa su un semaforo
/********************IMPLEMENTAZIONE DELLE PROCEDURE***********************/
void init_monitor (Monitor *M,int num_var){
int i;
M->num_var_cond=num_var;
M->mutex=semget(IPC_PRIVATE,1,IPC_CREAT|0664);
M->id_conds=semget(IPC_PRIVATE,num_var,IPC_CREAT|0664);
semctl(M->mutex,0,SETVAL,1);
for (i=0;i<num_var;i++)
semctl(M->id_conds,i,SETVAL,0);
M->id_shared=shmget(IPC_PRIVATE,num_var*sizeof(int),IPC_CREAT|0664);
M->cond_counts=(int*) (shmat(M->id_shared,0,0));
for (i=0;i<num_var;i++)
M->cond_counts[i]=0;
#ifdef DEBUG_
printf("Monitor inizializzato con %d condition variables. Buona Fortuna ! \n",num_var);
#endif
}
void enter_monitor(Monitor * M){
#ifdef DEBUG_
printf("<%d> Tentativo di ingresso nel monitor... \t",getpid() );
#endif
Wait_Sem(M->mutex,0);
#ifdef DEBUG_
printf("<%d> Entrato nel monitor \n",getpid() );
#endif
}
void leave_monitor(Monitor* M){
#ifdef DEBUG_
printf("<%d> Uscito dal monitor \n", getpid());
#endif
Signal_Sem(M->mutex,0);
}
void remove_monitor(Monitor* M){
semctl(M->mutex,0,IPC_RMID,0);
semctl(M->id_conds,M->num_var_cond,IPC_RMID,0);
shmctl(M->id_shared,IPC_RMID,0);
#ifdef DEBUG_
printf(" \n Il Monitor è stato rimosso ! Arrivederci \n", getpid());
#endif
}
void wait_condition(Monitor* M,int id_var){
#ifdef DEBUG_
printf("<%d> -Monitor- invocata la wait sulla condition numero %d\n", getpid(), id_var);
#endif
M->cond_counts[id_var]=M->cond_counts[id_var]+1;
Signal_Sem(M->mutex,0);
Wait_Sem(M->id_conds,id_var);
M->cond_counts[id_var]=M->cond_counts[id_var]-1;
}
void signal_condition(Monitor* M,int id_var){
#ifdef DEBUG_
printf("<%d> -Monitor- tentativo di signal; n.ro proc. in attesa sulla cond. n. %d = %d\n", getpid(), id_var,M->cond_counts[id_var]);
#endif
if(M->cond_counts[id_var]>0) {
Signal_Sem(M->id_conds,id_var);
#ifdef DEBUG_
printf("<%d> -Monitor- invocata la signal sulla condition numero %d\n", getpid(), id_var);
#endif
} else {
Signal_Sem(M->mutex,0);
#ifdef DEBUG_
printf("<%d> -Monitor- invocata la signal sul mutex \n", getpid());
#endif
}
}
/********************IMPLEMENTAZIONE DELLE PROCEDURE SEMAFORICHE***********************/
void Wait_Sem(int id_sem, int numsem) {
struct sembuf sem_buf;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_op=-1;
semop(id_sem,&sem_buf,1); //semaforo rosso
}
// restituisce il numero di processi in attesa sul semaforo
int Queue_Sem(int id_sem, int numsem) {
return (semctl(id_sem,numsem,GETNCNT,NULL));
}
void Signal_Sem (int id_sem,int numsem) {
struct sembuf sem_buf;
sem_buf.sem_num=numsem;
sem_buf.sem_flg=0;
sem_buf.sem_op=1;
semop(id_sem,&sem_buf,1); //semaforo verde
}
[/SPOILER]
Makefile
[SPOILER]
codice:
start: main.o body.o monitor.o
g++ -o start main.o body.o monitor.o
main.o: main.cpp header.h
g++ -c main.cpp
body.o: body.cpp header.h
g++ -c body.cpp
monitor.o: monitor.h monitor.cpp
g++ -c monitor.cpp
clean:
rm -f *.o
rm -f ./start
rm -f *~
[/SPOILER]
Ho già individuato la parte critica , ossia :
codice:
init_monitor( &(m->M), NUMCOND );
in main.cpp, infatti commentando quell'unica riga di codice , non ricevo più l'errore " Errore di segmentazione (core dump creato) " ,
Grazie mille in anticipo a chiunque possa aiutarmi.