Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135

    [C]linux: programma didattico comunicazione tra thread

    Salve ragazzi!
    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.
    Riesco a creare correttamente i processi (e i thread) ma non riesco a fare altrettanto correttamente in fase di visualizzazione,gli alieni vengono sovrapposti su un'unica casella, così da sembrare che ve ne fosse solo uno, e non riesco a capirne il motivo. Per ora cerco di fare stampare solo gli alieni, in seguito implementerò le bombe e la nave del personaggio principale.
    Qualcuno può darmi una mano? Vi allego il codice:
    codice:
    #include <stdio.h>
    #include <curses.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 4
    #define SPAZIO 1
    #define SPAZIO_RIGHE 1
    #define PASSO_X 2
    #define PASSO_Y 1
    #define MAX_BOMBE_NAVE 1
    #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];
    int info_elementi[DIM_BUFFER];
    
    void *alieno(void *);
    void *controllo(void *);
    
    pthread_t array_alieni[N_INIZIALE_ALIENI];
    pthread_mutex_t semaforo = PTHREAD_MUTEX_INITIALIZER;
    sem_t vuoto, pieno;
    int dimAlieni, bufferScrittura, bufferLettura, counter;
    
    int main() {
    int i = 0, j = 1, k, nAlieniRiga;
    pthread_t nave;
    pthread_t bombaNave[MAX_BOMBE_NAVE];
    pthread_t bombaAlieno[N_INIZIALE_ALIENI];
    initscr();
    noecho();
    curs_set(0);
    bufferScrittura = 0;
    bufferLettura = 0;
    counter = 0;
    dimAlieni = 1;
    nAlieniRiga = 20 / (dimAlieni + SPAZIO); //20 è inteso come numero COLS (pechè non abbiamo inizializzato le variabili di ncurses
    sem_init(&vuoto, 0, DIM_BUFFER);
    sem_init(&pieno, 0, 0);
    
    for (k = 0; k < N_INIZIALE_ALIENI; k++){
    	//struct pos pos_alieno;
    	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]);
    }
    controllo(NULL);
    getchar();
    endwin();
    exit(0);
    }
    
    void *alieno(void *args)
    {
    struct pos pos_alieno = *(struct pos*) args;
    pos_alieno.id = pthread_self();
    int dir = 1, dx, dy;
    srand(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;
    	//sleep(rand() % 2); non funziona
    	sem_wait(&vuoto); //Segnala che è stata scritta un altra posizione nel buffer
    	pthread_mutex_lock(&semaforo); //equivale ad una wait su valore 1, che poi viene reincrementata dall'unlock che gli ri da valore 1
    	info_elementi[bufferScrittura] = pos_alieno.index;
    	bufferScrittura = (bufferScrittura + 1) % DIM_BUFFER;
    	//printf("Buffer Scrittura %d\n", bufferScrittura); //facevo un po di debug!
    	alieni[pos_alieno.index] = pos_alieno;
    	pthread_mutex_unlock(&semaforo);
    	sem_post(&pieno); //Segnala che c'è una posizione in più da leggere nel buffer
    	sleep(1);
    	}
    }
     
    void *controllo(void *args)
    {
    struct pos valore_letto;
    int index, i = 0;
    do {
    	//sleep(rand() % 2); non funziona nemmeno così
    	sem_wait(&pieno); //Segnala che è stata letta una posizione dal buffer
    	pthread_mutex_lock(&semaforo);
    	index = info_elementi[bufferLettura];
    	bufferLettura = (bufferLettura + 1) % DIM_BUFFER;
    	valore_letto = alieni[index];
    	pthread_mutex_unlock(&semaforo);
    	sem_post(&vuoto);
    	move(valore_letto.yPrec, valore_letto.xPrec);
    	printw(" "); //printw
    	move(valore_letto.y, valore_letto.x);
    	printw("%s",valore_letto.c);
    	move(index, 0);
    	//printw("%d",i); tutto questo è debug
    	//printw("Valore letto x: %d, Valore letto y: %d, Numero alieno %d,\n", valore_letto.x, valore_letto.y, valore_letto.index);
    	//move(0,15);
    	//printw("\tlivello %d",livello);
    	//move(0,27);
    	//printw("\tvite %d",nave_vita);
    	refresh();
    	i++;
    	}
    while (true);
    }
    P.S. Compilare con le opzioni -lpthread & -lncurses, es:
    gcc -o alieni alienThread.c -lncurses -lpthread
    Linux Slackware 11 - Kernel 2.6.18

  2. #2
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135

    [C]linux: programma didattico comunicazione tra thread

    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:
    /*
    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 11 - Kernel 2.6.18

  3. #3
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135
    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 11 - Kernel 2.6.18

  4. #4
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296

    Moderazione

    Ho unito le discussioni aperte. Non aprire più discussioni sullo stesso argomento.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  5. #5
    Se può esserti d'aiuto:
    http://www.gamedev.net/community/forums/
    ...dedicato appositamente al game-development.
    Rilasciata Python FTP Server library 0.5.1
    http://code.google.com/p/pyftpdlib/

    We'll be those who'll make the italian folks know how difficult can be defecating in Southern California without having the crap flying all around the house.

  6. #6
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135
    Grazie per l'aiuto, speriamo che mi diano una mano!
    Linux Slackware 11 - Kernel 2.6.18

  7. #7
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135
    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 uno sguardo al codice!
    Linux Slackware 11 - Kernel 2.6.18

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.