Ciao a tutti! Io e la mia collega abbiamo bisogno del vostro aiuto!
Dobbiamo fare una versione (molto semplificata) di Space Invaders e usare i thread per la comunicazione tra i processi..Il problema è che durante l'esecuzione, il programma si blocca o a causa della segmentation fault o perchè viene sollevata la floating point exception..Il motivo??boooh!!!Vi posto il codice..è un po' lunghetto, ma ci sono tanti commenti così potete capire cosa abbiamo fatto..Vi prego..aiutateci!!
codice:
#include <stdio.h>
#include <time.h>
#include <curses.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <semaphore.h>
#include <unistd.h>
#define PASSO 1 //entita' dello spostamento del nemico
#define SINISTRA 68 // freccia sx
#define DESTRA 67 // freccia dx
#define SGANCIA 32 // spazio
#define MAXX 80 // numero di colonne dello schermo
#define MAXY 24 // numero di righe dello schermo
#define M 2 // numero di nemici di 1° livello
#define G 4 // numero di nemici di 2° livello per gruppo
#define BUFFER_DIM 100000
//** Prototipi funzioni **//
void * astronave_func(void * arg);
void * missile_func(void * arg);
void * nemico_func(void * arg);
void * nemico2_func(void * arg);
void * bomba_func(void * arg);
void * controllo_func(void * arg);
//**Struttura per la comunicazione fra figli e padre**//
typedef struct pos
{
char c; // soggetto che invia il dato: astronave, nemico, bomba o missile
int x; // coordinata x
int y; // coordinata y
int DIRX; // direzione del nemico di 2° livello
int p; // posizione del nemico all'interno del vettore v[] che rappresenta il gruppo di nemici di primo livello
int pid; // pid del processo
int vita; // 0: il nemico è morto; 1: il nemico è vivo
int xi; // coordinata x del primo nemico di secondo livello
int xf; // coordinata x dell'ultimo nemico di secondo livello
int nem_vivi[G]; // vettore che indica lo stato di vita dei nemici di secondo livello all'interno di ciascun gruppo
int g; // rappresenta il numero del gruppo a cui appartiene il nemico di secondo livello
int n; // rappresenta il numero assegnato al nemico di 2° livello all'interno del proprio gruppo
} pos;
typedef struct argomenti // struttura per passare più argomenti ad una funzione thread
{
int x; // posizione in x (dell'astronave o del nemico)
int y; // posizione in y (dell'astronave o del nemico)
int i; // indice i
} args;
//** Inizializzazioni buffer e semafori **//
pos buffer[BUFFER_DIM]; // buffer condiviso
int IN = 0; // variabile che indica le posizioni occupate nel buffer
int OUT = 0; // variabile che indica le posizioni disponibili nel buffer
sem_t presenti, disponibili; // variabili che indicano il valore del semaforo, ovvero la presenza o meno di job disponibili
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // mutex per evitare la race condiction
main()
{
initscr(); // inizializzazione dello schermo
start_color(); // per l'utilizzazione dei colori
noecho(); // i caretteri corrispondenti ai tasti premuti non saranno visualizzati sullo schermo del terminale
curs_set(0); // nasconde il cursone
sem_init(&disponibili, 0, BUFFER_DIM); // inizializzazione semaforo disponibili
sem_init(&presenti, 0, 0); // inizializzazione semaforo presenti
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // inizializzazione mutex
srand(time(NULL));
pthread_t astronave_id, nemico_id[M], controllo_id;
int i;
//creazione dei thread
pthread_create(&astronave_id, NULL, &astronave_func, NULL);
for(i=0;i<M;i++)
pthread_create(&nemico_id[i], NULL, &nemico_func, &i);
//evita che vengano deallocati dati indispensabili ai thread alla terminazione del main
//pthread_join(astronave_id, NULL);
pthread_create(&controllo_id, NULL, &controllo_func, NULL);
pthread_join(controllo_id, NULL);
/** Siamo usciti dal controllo e si terminano i procssi figli. Ripristina il normale modo operativo dello schermo **/
endwin();
return(0);
}
/** Funzione ASTRONAVE **/
void * astronave_func(void * arg)
{
pos pos_astronave;
args pos;
pthread_t missile_id[2]; // l'astronave spara contemporaneamente due missili:uno a destra e uno a sinistra
int i;
pos_astronave.c='#';
pos_astronave.x=MAXX/2;
pos_astronave.y=MAXY-1;
pos_astronave.pid=pthread_self();
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_astronave;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
while(1)
{
char c;
switch(c=getch()) { //gestione movimento o sgancio dei missili da parte dell'astronave
case SINISTRA: if(pos_astronave.x>0){
pos_astronave.x-=1;
} // fine if(pos_astronave.x>0)
break;
case DESTRA: if(pos_astronave.x<MAXX-1){
pos_astronave.x+=1;
}
break;
case SGANCIA: for(i=0;i<2;i++){
pos.i=i;
pos.x=pos_astronave.x;
pos.y=pos_astronave.y;
pthread_create(&missile_id[i], NULL, &missile_func, &pos);
//pthread_join(missile_id[i], NULL);
}
break;
} // fine switch gestione movimento
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_astronave;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
} // fine while
} // fine Funzione Astronave
/** Funzione MISSILE **/
void * missile_func(void * arg)
{
pos pos_missile;
args * pos = (args *)arg;
int i = pos->i;
pos_missile.c='*'; /*Effettuo il primo assegnamento*/
pos_missile.pid=pthread_self();
pos_missile.p=i; // può essere 0 o 1 e indica quella che sarÃ_ la direzione del missile (dx o sx)
if(i%2) // se i è dispari
pos_missile.x=pos->x +PASSO; // vÃ_ a sinistra
else // altrimenti
pos_missile.x=pos->x -PASSO; // vÃ_ a destra
pos_missile.y=pos->y-1;
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_missile;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
if(i%2) //se i=1 il missile vÃ_ a sinistra altrimenti a destra
while(1)
{
pos_missile.x+=PASSO;
pos_missile.y-=PASSO;
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_missile;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
usleep(200000);
}
else
while(1)
{
pos_missile.x-=PASSO;
pos_missile.y-=PASSO;
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_missile;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
usleep(200000);
}
} // fine Funzione Missile
/** Funzione BOMBA **/
void * bomba_func(void * arg)
{
pos pos_bomba;
args * pos = (args *)arg;
pos_bomba.c='o'; //inizializzo: la bomba parte dalla stessa colonna del nemico una posizione in avanti
pos_bomba.x=pos->x;
pos_bomba.y=pos->y +PASSO;
pos_bomba.pid=pthread_self();
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_bomba;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
while(1)
{
pos_bomba.y+=PASSO;
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_bomba;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
usleep(300000);
}
}//fine funzione bomba
/** Funzione NEMICO **/
void * nemico_func(void * arg)
{
pos pos_nemico;
int i = *((int *)arg);
int dx,dy; // spostamenti in x e y;
int SOGLIAX; // soglia oltre la quale il nemico non può andare - può essere 1 o MAXX-1
int DIRX; // direzione in x - se dirx=1 vÃ_ a destra, se dirx=-1 va a sinistra
int time_giu=0; // contatore per far scendere il nemico
int SOGLIA_GIU=10*(0+rand()%4)+i*5; // soglia per far scendere il nemico di una riga
int time_bomb=1; // contatore per far sganciare una bomba
int SOGLIA_BOMB=30+i*(0+rand()%5); // soglia per far sganciare la bomba
args pos;
pthread_t bomba_id;
pos_nemico.c='$';
pos_nemico.p=i;
pos_nemico.pid=pthread_self();
pos_nemico.y=1; // i nemici partono tutti sulla stessa riga
pos_nemico.x=9+(i*20); // ma distanziati
if(!(i%2)) // se il numero assegnato al nemico è pari
{
DIRX=1; // vÃ_ a destra
SOGLIAX=MAXX-1; // e la soglia max in x è MAXX-1
}
else // altrimenti
{
DIRX=-1; // vÃ_ a sinistra
SOGLIAX=1; // e la soglia max in x è 1
}
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_nemico;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
while(1)
{
if(pos_nemico.x==SOGLIAX) // se il nemico sbatte contro una parete laterale
{
DIRX*=-1; // cambio la direzione
if(SOGLIAX==MAXX-1) // se la nuova direzione è destra
SOGLIAX=1; // la soglia è MAXX-1
else // altrimenti
SOGLIAX=MAXX-1; // la soglia è 1
}
if(DIRX==1) // se la direzione è destra
dx=PASSO; // il suo spostamento sarÃ_ di PASSO
else // altrimenti
dx=-PASSO; // il suo spostamento sarÃ_ di -PASSO
pos_nemico.x+=dx; // scriviamo la posizione in x del nemico
if(!(time_giu%SOGLIA_GIU)) // ad intervalli regolari
{
dy=PASSO; // il nemico avanza di PASSO verso la soglia massima in Y
time_giu=1; // riazzero il contatore
}
else
{
dy=0; // il nemico non avanza verso la soglia massima in Y
time_giu++; // aggiorno il contatore per la discesa del nemico
}
pos_nemico.y+=dy; // scriviamo la posizione in y del nemico
sem_wait(&disponibili);
pthread_mutex_lock(&mutex);
buffer[IN] = pos_nemico;
IN=(IN+1)%BUFFER_DIM;
sem_post(&presenti); // incrementa il semaforo
pthread_mutex_unlock(&mutex);
if(!(time_bomb%SOGLIA_BOMB)){ // ad intervalli regolari
pos.x = pos_nemico.x;
pos.y = pos_nemico.y;
pthread_create(&bomba_id, NULL, &bomba_func, &pos);
//pthread_join(bomba_id, NULL);
}
time_bomb++; // aggiorno il contatore per la bomba
usleep(300000);
} // fine while;
} // fine Funzione Nemico
(continua...)