Punto informatico Network
Login Esegui login | Non sei registrato? Iscriviti ora (è gratuito!)
Username: Password:
  • Annuncio Pubblicitario

[C]linux: programma didattico comunicazione tra thread

Il forum per tutti i developer. Leggere attentamente il regolamento di sezione prima di postare.

[C]linux: programma didattico comunicazione tra thread

Messaggioda caralu » ven lug 07, 2006 5:06 pm

Salve ragazzi! Avevo già postato un errore precedente, adesso sono andato molto più avanti ma mi sono bloccato su alcuni problemi.
Sto implementando un programmino didattico: sarebbe una emulazione del gioco di space invaders (ma molto grezzo!),con grafica scarna.
Il programma è quasi analogo al classico problema dei "produttori-consumatori": creo dei processi con relativi thread, che accedono ad un buffer condiviso (protetto da semafori), basandomi sulle librerie lpthread e lncurses.
Il problema in cui mi sono impantanato adesso è relativo forse alla sincronizzazione che non funziona: gli alieni ad un certo punto si bloccano e le bombe che lancia la mia nave con il tasto INVIO non capisco come mai non vengono bloccate (homesso un controllo per fare sparare due bombe per volta ma non lo rispetta). Non capisco se il problema sono i semafori!
Qualcuno può darmi una mano? Vi allego il codice:
Codice: Seleziona tutto
/*
Autori: Carlo Buttu, Giovanni Bussu.
Versione Beta 0.1
Codice rilasciato su licenza GPL ( http://www.gnu.org/licenses/gpl-howto.html).
*/

#include <stdio.h>
#include <curses.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define NUM_MAX_RIGHE 5
#define SINISTRA 68
#define DESTRA 67
#define N_INIZIALE_ALIENI 10
#define SPAZIO 2
#define SPAZIO_RIGHE 1
#define PASSO_X 2
#define PASSO_Y 1
#define MAX_BOMBE_NAVE 2
#define MAX_BOMBE_ALIENO N_INIZIALE_ALIENI * 2
#define DIM_BUFFER N_INIZIALE_ALIENI


struct pos {
char *c;
int x;
int y;
int xPrec;
int yPrec;
int index;
int id;
};

struct pos alieni[N_INIZIALE_ALIENI];
struct pos info_nave;
struct pos bombe_nave[MAX_BOMBE_NAVE];
struct pos bombe_alieno[MAX_BOMBE_ALIENO];
struct pos *info_elementi[DIM_BUFFER];

void *alieno(void *);
void *nave(void *);
void *controllo(void *);
void *sparaBomba(void *);
void bomba(struct pos, struct pos *);

pthread_t array_alieni[N_INIZIALE_ALIENI];
pthread_t threadNave;
pthread_t bombaNave[MAX_BOMBE_NAVE];
pthread_t bombaAlieno[MAX_BOMBE_ALIENO];

pthread_mutex_t semaforo = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexBombeAlieni = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexBombeNave = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexAlieni = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexNave = PTHREAD_MUTEX_INITIALIZER;

sem_t vuoto, pieno;
int dimAlieni, bufferScrittura, bufferLettura, nBombeNaveResidue, nBombeAlienoResidue, posDisponibileAlieno, posDisponibileNave;

int main() {
int i = 0, j = 1, k, nAlieniRiga;
initscr();
noecho();
curs_set(0);
bufferScrittura = 0;
bufferLettura = 0;
posDisponibileAlieno = 0;
posDisponibileNave = 0;
nBombeNaveResidue = MAX_BOMBE_NAVE;
nBombeAlienoResidue = MAX_BOMBE_ALIENO;
dimAlieni = 1;
nAlieniRiga = COLS / (dimAlieni + SPAZIO);
sem_init(&vuoto, 0, DIM_BUFFER);
sem_init(&pieno, 0, 0);

for (k = 0; k < N_INIZIALE_ALIENI; k++){
   i = k % nAlieniRiga;
   j =  (k / nAlieniRiga) + 1;
   
   alieni[k].x = i * (SPAZIO + 1);
   alieni[k].y =  j * (SPAZIO_RIGHE + 1);
   alieni[k].c = "#";
   alieni[k].index = k;
   pthread_create(&array_alieni[k], NULL, &alieno, &alieni[k]);
}

pthread_create(&threadNave, NULL, &nave, NULL);
controllo(NULL);
getchar();
endwin();
exit(0);
}

void *nave(void *args)
{
struct pos pos_nave;
struct pos pos_bomba;
pos_nave.c = "^";
pos_nave.x = COLS / 2;
pos_nave.yPrec = pos_nave.y = LINES - 1;
pos_nave.index = N_INIZIALE_ALIENI; //per ora è inutile...
sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
info_elementi[bufferScrittura] = &pos_nave;
bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
info_nave = pos_nave;
pthread_mutex_unlock(&semaforo);
sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
while(1)
   {
   pos_nave.xPrec = pos_nave.x;
   char c;
   switch(c = getch())
      {
      case SINISTRA: if(pos_nave.x > 1) pos_nave.x -= 1;
      break;
      case DESTRA: if(pos_nave.x < COLS - 1) pos_nave.x += 1;
      break;
      case ' ':
         pos_bomba.x = pos_bomba.xPrec = pos_nave.x;
         pos_bomba.y = LINES - 2;
         pos_bomba.c = "o";
         pthread_mutex_lock(&mutexBombeNave);
         if(nBombeNaveResidue > 0)
            {
            pthread_mutex_lock(&mutexNave);
            pthread_create(&bombaNave[posDisponibileNave], NULL, &sparaBomba, &pos_bomba);
            pthread_mutex_unlock(&mutexNave);
            }
         pthread_mutex_unlock(&mutexBombeNave);
      }
   if (c == DESTRA || c == SINISTRA)
      {
      sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
      pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
      info_elementi[bufferScrittura] = &pos_nave;
      bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
      info_nave = pos_nave;
      pthread_mutex_unlock(&semaforo);
      sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
      }
   }
}

void *alieno(void *args)
{
struct pos pos_alieno = *(struct pos*) args;
pos_alieno.id = pthread_self();
int dir = 1, dx, dy;
srand((int) pos_alieno.id);
while(1)
   {
   pos_alieno.yPrec = pos_alieno.y;
   pos_alieno.xPrec = pos_alieno.x;
   dx = PASSO_X * dir;
   dy = 0;
   if (pos_alieno.x + dx >= COLS -1 || pos_alieno.x + dx <= 0)
      {
      if(dir > 0)
         pos_alieno.x = COLS - 1;
      else
         pos_alieno.x = 0;
      dir = -dir;
      dx = PASSO_X * dir;
      dy = PASSO_Y;
      }
   pos_alieno.x += dx;
   pos_alieno.y += dy;
   sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
   pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
   info_elementi[bufferScrittura] = &pos_alieno;
   bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
   alieni[pos_alieno.index] = pos_alieno;
   pthread_mutex_unlock(&semaforo);
   sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
   int t = clock();
   if((rand() % 100) >= 65 - 1) // 1 qui equivale al livello....da aggiornare!
   {
      struct pos pos_bomba;
      pos_bomba.x = pos_bomba.xPrec = pos_alieno.x;
      pos_bomba.y = pos_alieno.y + 1;
      pos_bomba.c = "!";
      pthread_mutex_lock(&mutexBombeAlieni);
      if(nBombeAlienoResidue > 0)
         {
         pthread_mutex_lock(&mutexAlieni);
         pthread_create(&bombaAlieno[posDisponibileAlieno], NULL, &sparaBomba, &pos_bomba);
         pthread_mutex_unlock(&mutexAlieni);
         }
      pthread_mutex_unlock(&mutexBombeAlieni);
   }
   t = 1 - clock() - t;
   sleep((int)t);
   }
}
 
void *controllo(void *args)
{
struct pos valore_letto;
int index;
do {
   sem_wait(&pieno); //Segnala che è stata letta una posizione dal buffer
   pthread_mutex_lock(&semaforo);
   valore_letto = *info_elementi[bufferLettura];
   bufferLettura = (bufferLettura + 1) % DIM_BUFFER;
   pthread_mutex_unlock(&semaforo);
   sem_post(&vuoto);
   move(valore_letto.yPrec, valore_letto.xPrec);
   printw(" ");
   move(valore_letto.y, valore_letto.x);
   printw("%s",valore_letto.c);
   move(0,0);
   printw("Bombe nave %d",nBombeNaveResidue);
   //move(1,0);
   //printw("Bombe alieno %d",nBombeAlienoResidue);
   refresh();
   }
while (true);
}

void *sparaBomba(void *args)
{
struct pos pos_bomba = *(struct pos*) args;
struct pos *posizione;
pos_bomba.id = pthread_self();
if(pos_bomba.c == "!") // è un alieno?
   {
   pthread_mutex_lock(&mutexBombeAlieni);
   if(nBombeAlienoResidue > 0)
      {
      nBombeAlienoResidue--;
      pos_bomba.index = posDisponibileAlieno; // per ora è inutile...
      posDisponibileAlieno = (posDisponibileAlieno + 1) % MAX_BOMBE_ALIENO;
      posizione = &bombe_alieno[posDisponibileAlieno];
      pthread_mutex_unlock(&mutexBombeAlieni);
      bomba(pos_bomba, posizione);
      pthread_mutex_lock(&mutexBombeAlieni);
      nBombeAlienoResidue++;
      posDisponibileAlieno = (posDisponibileAlieno - 1) % MAX_BOMBE_ALIENO;
      }
   pthread_mutex_unlock(&mutexBombeAlieni);
   }
   else
      if(pos_bomba.c == "o") //è una nave?
         {
         pthread_mutex_lock(&mutexBombeNave);
         if(nBombeNaveResidue > 0)
            {
            nBombeNaveResidue--;
            pos_bomba.index = posDisponibileNave; //per ora è inutile...
            posDisponibileNave = (posDisponibileNave + 1) % MAX_BOMBE_NAVE;
            posizione = &bombe_nave[posDisponibileNave];
            pthread_mutex_unlock(&mutexBombeNave);
            bomba(pos_bomba, posizione);
            pthread_mutex_lock(&mutexBombeNave);
            nBombeNaveResidue++;
            posDisponibileNave = (posDisponibileNave - 1) % MAX_BOMBE_NAVE;
            }
         pthread_mutex_unlock(&mutexBombeNave);
         }
}

void bomba(struct pos pos_bomba, struct pos *posizione)
{
int limite = (pos_bomba.c == "!") ? LINES - 1 : 0;
int dir = (pos_bomba.c == "!") ? 1 : -1;
   sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
   pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
   info_elementi[bufferScrittura] = &pos_bomba;
   bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
   *posizione = pos_bomba;
   pthread_mutex_unlock(&semaforo);
   sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
while(pos_bomba.y != limite)
   {
   usleep(100000);
   pos_bomba.yPrec = pos_bomba.y;
   pos_bomba.y += dir;
   sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
   pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
   info_elementi[bufferScrittura] = &pos_bomba;
   bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
   *posizione = pos_bomba;
   pthread_mutex_unlock(&semaforo);
   sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
   }
pos_bomba.c = " ";
sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1
info_elementi[bufferScrittura] = &pos_bomba;
bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
*posizione = pos_bomba;
pthread_mutex_unlock(&semaforo);
sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
}



P.S. Compilare con le opzioni -lpthread & -lncurses, es:
gcc -o alieni alienThread.c -lncurses -lpthread
Avatar utente
caralu
Aficionado
Aficionado
 
Messaggi: 43
Iscritto il: mer dic 28, 2005 4:13 pm

Messaggioda caralu » mer lug 12, 2006 5:26 pm

Ho modificato il mio programma e ho corretto diversi errori ma il deadlock rimane..Il fatto è che il deadlock avviene solo in certe distribuzioni linux (slackware, ubuntu..) mentre in altre no (ad esempio mandriva...). Come mai??
Avatar utente
caralu
Aficionado
Aficionado
 
Messaggi: 43
Iscritto il: mer dic 28, 2005 4:13 pm

Messaggioda caralu » sab lug 15, 2006 10:29 am

Ho corretto il progetto eliminando 2 mutex (avevo una gestione troppo appesantita che portava ad un deadlock) ed inoltre c'era anche un'errore di inizializzazione del generatore di numeri pseudo-casuali (avevo inizializzato srand() all'interno di una funzione mentre è buona norma inizializzarlo nel main ).
Grazie a chiunque abbia dato un'occhiata al codice!
Avatar utente
caralu
Aficionado
Aficionado
 
Messaggi: 43
Iscritto il: mer dic 28, 2005 4:13 pm


Torna a Programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 0 ospiti

Powered by phpBB © 2002, 2005, 2007, 2008 phpBB Group
Traduzione Italiana phpBB.it

megalab.it: testata telematica quotidiana registrata al Tribunale di Cosenza n. 22/09 del 13.08.2009, editore Master New Media S.r.l.; © Copyright 2008 Master New Media S.r.l. a socio unico - P.I. 02947530784. GRUPPO EDIZIONI MASTER Spa Tutti i diritti sono riservati. Per la pubblicità: Master Advertising