Condividi:        

[C]linux: programma didattico comunicazione tra thread

Problemi di HTML? Di PHP, ASP, .NET, JSP, Perl, SQL, JavaScript, Visual Basic..?
Vuoi realizzare programmi in C, C++, Java, Ruby o Smalltalk, e non sai da che parte cominciare?
Entra qui e troverai le risposte!

Moderatori: Anthony47, Triumph Of Steel, archimede

[C]linux: programma didattico comunicazione tra thread

Postdi caralu » 07/07/06 17:10

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
Linux Slackware 10.2 - Kernel 2.16
caralu
Newbie
 
Post: 8
Iscritto il: 07/07/06 17:05

Sponsor
 

Postdi caralu » 12/07/06 17:22

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??
Linux Slackware 10.2 - Kernel 2.16
caralu
Newbie
 
Post: 8
Iscritto il: 07/07/06 17:05

Postdi caralu » 15/07/06 10:27

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!
Linux Slackware 10.2 - Kernel 2.16
caralu
Newbie
 
Post: 8
Iscritto il: 07/07/06 17:05


Torna a Programmazione


Topic correlati a "[C]linux: programma didattico comunicazione tra thread":


Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti