Compartiendo para dos mundos

Hablando de programación paralela.
Tutoriales en: https://www.youtube.com/user/jambrizgdl
Twitter: @dogoteacher

Buscar este blog

domingo, 20 de diciembre de 2009

Critical sections and semaphores examples on pacman game, language C

Introduction
The threads with common resources have some problems , but there are too how to resolve them.the programer could use critical sections or semaphores for controling how many threads are using a resource.

Problem: Pacman game
Pacman game has many "objects" in the labyrinth: Ghosts, points and its own. These objects have common access to structure: the labyrinth ( one matrix of characters ).

In the first program is possible that one thread overwrite a symbol of other thread. These procedures "iniciarPacman", "iniciarFantasmas" and "iniciarPuntos" are used for finding a free position and then write a symbol there.

Original code
#include < stdio.h >
#include < conio.h >
#include < windows.h >
#include < stdlib.h >

#define COLUMNAS 10
#define RENGLONES 10
#define CANT_FANTASMAS 5
#define CANT_PUNTOS 20
#define CANTIDAD_HILOS 3

struct t_fantasma
{
int col;
int ren;
};

struct t_puntos
{
int col;
int ren;
};

typedef struct t_fantasma TFANTASMA;
typedef struct t_puntos TPUNTOS;


void leerTablero( void );
void mostrarTablero( void );
void iniciarFantasmas(void);
DWORD WINAPI metodo1(LPVOID param);
DWORD WINAPI metodo2(LPVOID param);
DWORD WINAPI metodo3(LPVOID param);
void iniciarPacman(void);
void iniciarPuntos(void);
void verificarPartesTablero(void);

char tablero[ RENGLONES ][ COLUMNAS ]; //10x10 character matrix

TFANTASMA fantasmas[ CANT_FANTASMAS ]; //ghosts
TPUNTOS puntos[ CANT_PUNTOS ]; //points for pacman

void main()
{
HANDLE hilos[ CANTIDAD_HILOS ];
clrscr();
randomize();
leerTablero();
hilos[2] = CreateThread( NULL, 0, metodo3, NULL, 0, NULL); //put down points
hilos[1] = CreateThread( NULL, 0, metodo2, NULL, 0, NULL); //put down gost
hilos[0]= CreateThread( NULL, 0, metodo1, NULL, 0, NULL ); //put down pacman
WaitForMultipleObjects(2, hilos, 1, INFINITE );
printf("\n");
mostrarTablero();
verificarPartesTablero();
}

void verificarPartesTablero()
{
int c,r;
int contPacman=0, contFantasmas=0, contPuntos=0;
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
switch ( tablero[r][c] )
{
case '#': contFantasmas+=1; break;
case '.': contPuntos+=1; break;
case '@': contPacman+=1; break;
}
}
}
printf("\n%i,%i,%i", contPacman, contFantasmas, contPuntos );
}

void iniciarPacman()
{
int col, ren;
do
{
col= random( COLUMNAS );
ren= random( RENGLONES );
} while ( tablero[ ren ] [ col ] != ' ' );
tablero[ ren ][ col ]= '@';
}

void iniciarFantasmas()
{
int i;
for(i=0; i< CANT_FANTASMAS ; i+=1 )
{
do
{
fantasmas[i].col= random( COLUMNAS );
fantasmas[i].ren= random( RENGLONES );
} while ( tablero[ fantasmas[i].ren ] [ fantasmas[i].col ] != ' ' );

tablero[ fantasmas[i].ren ] [ fantasmas[i].col ]='#';
}
}

void iniciarPuntos()
{
int i;
for(i=0; i< CANT_PUNTOS ; i+=1 )
{
do
{
puntos[i].col= random( COLUMNAS );
puntos[i].ren= random( RENGLONES );
} while ( tablero[ puntos[i].ren ] [ puntos[i].col ] != ' ' );

tablero[ puntos[i].ren ] [ puntos[i].col ]='.';
}
}

void leerTablero()
{
int c, r;
FILE *archivo;
archivo= fopen("tablero.txt","rt");
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
fscanf(archivo, "%c", &tablero[ r ][ c ] );
tablero[ r ][ c ]= (tablero[ r ][ c ]=='1'?' ':tablero[ r ][ c ]);
//printf("%c", tablero[ r ][ c ] );
}
fscanf(archivo, "\n", NULL );
//printf("\n");
}
fclose( archivo );
}

void mostrarTablero()
{
int c, r;
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
printf("%c", tablero[ r ][ c ] );
}
printf("\n");
}
}

DWORD WINAPI metodo1(LPVOID param)
{
iniciarPacman();
return 0;
}

DWORD WINAPI metodo2(LPVOID param)
{
iniciarFantasmas();
return 0;
}

DWORD WINAPI metodo3(LPVOID param)
{
iniciarPuntos();
return 0;
}


Critical section
The next code define three critical sections in the procedures "iniciarPacman", "iniciarFantasmas" and "iniciarPuntos"

#include < stdio.h >
#include < conio.h >
#include < windows.h >
#include < stdlib.h >

#define COLUMNAS 10
#define RENGLONES 10
#define CANT_FANTASMAS 5
#define CANT_PUNTOS 20
#define CANTIDAD_HILOS 3

struct t_fantasma
{
int col;
int ren;
};

struct t_puntos
{
int col;
int ren;
};

typedef struct t_fantasma TFANTASMA;
typedef struct t_puntos TPUNTOS;


void leerTablero( void );
void mostrarTablero( void );
void iniciarFantasmas(void);
DWORD WINAPI metodo1(LPVOID param);
DWORD WINAPI metodo2(LPVOID param);
DWORD WINAPI metodo3(LPVOID param);
void iniciarPacman(void);
void iniciarPuntos(void);
int verificarPartesTablero(void);

char tablero[ RENGLONES ][ COLUMNAS ]; //el tablero es una matriz de 10x10 caracteres

TFANTASMA fantasmas[ CANT_FANTASMAS ]; //conjunto de fantasmas
TPUNTOS puntos[ CANT_PUNTOS ];

CRITICAL_SECTION sc1;
CRITICAL_SECTION sc2;
CRITICAL_SECTION sc3;

void main()
{
HANDLE hilos[ CANTIDAD_HILOS ];
clrscr();
randomize();
leerTablero();
InitializeCriticalSection( &sc1 ); // critical section begin
InitializeCriticalSection( &sc2 ); // critical section begin
InitializeCriticalSection( &sc3 ); // critical section begin
hilos[2] = CreateThread( NULL, 0, metodo3, NULL, 0, NULL); //put down points
hilos[1] = CreateThread( NULL, 0, metodo2, NULL, 0, NULL); //put down gost
hilos[0]= CreateThread( NULL, 0, metodo1, NULL, 0, NULL ); //put down pacman
WaitForMultipleObjects(CANTIDAD_HILOS, hilos, 1, INFINITE );
DeleteCriticalSection( &sc1 ); // critical section end
DeleteCriticalSection( &sc2 ); // critical section end
DeleteCriticalSection( &sc3 ); // critical section end
mostrarTablero();
}

void iniciarPacman()
{
int col, ren;
EnterCriticalSection( &sc1 );
do
{
col= random( COLUMNAS );
ren= random( RENGLONES );
} while ( tablero[ ren ] [ col ] != ' ' );
tablero[ ren ][ col ]= '@';
LeaveCriticalSection( &sc1 );
}

void iniciarFantasmas()
{
int i;
for(i=0; i< CANT_FANTASMAS ; i+=1 )
{
EnterCriticalSection( &sc2 );
do
{
fantasmas[i].col= random( COLUMNAS );
fantasmas[i].ren= random( RENGLONES );
} while ( tablero[ fantasmas[i].ren ] [ fantasmas[i].col ] != ' ' );
tablero[ fantasmas[i].ren ] [ fantasmas[i].col ]='#';
LeaveCriticalSection( &sc2 );
}
}

void iniciarPuntos()
{
int i;
for(i=0; i< CANT_PUNTOS ; i+=1 )
{
EnterCriticalSection( &sc3 );
do
{
puntos[i].col= random( COLUMNAS );
puntos[i].ren= random( RENGLONES );
} while ( tablero[ puntos[i].ren ] [ puntos[i].col ] != ' ' );
tablero[ puntos[i].ren ] [ puntos[i].col ]='.';
LeaveCriticalSection( &sc3 );
}
}

void leerTablero()
{
int c, r;
FILE *archivo;
archivo= fopen("tablero.txt","rt");
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
fscanf(archivo, "%c", &tablero[ r ][ c ] );
tablero[ r ][ c ]= (tablero[ r ][ c ]=='1'?' ':tablero[ r ][ c ]);
//printf("%c", tablero[ r ][ c ] );
}
fscanf(archivo, "\n", NULL );
//printf("\n");
}
fclose( archivo );
}

void mostrarTablero()
{
int c, r;
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
printf("%c", tablero[ r ][ c ] );
}
printf("\n");
}
}

DWORD WINAPI metodo1(LPVOID param)
{
iniciarPacman();
return 0;
}

DWORD WINAPI metodo2(LPVOID param)
{
iniciarFantasmas();
return 0;
}

DWORD WINAPI metodo3(LPVOID param)
{
iniciarPuntos();
return 0;
}


Semaphores
The next code define one binary semaphore for controling access to labyrinth in the same procedures.

#include < stdio.h >
#include < conio.h >
#include < windows.h >
#include < stdlib.h >

#define COLUMNAS 10
#define RENGLONES 10
#define CANT_FANTASMAS 5
#define CANT_PUNTOS 20
#define CANTIDAD_HILOS 3

struct t_fantasma
{
int col;
int ren;
};

struct t_puntos
{
int col;
int ren;
};

typedef struct t_fantasma TFANTASMA;
typedef struct t_puntos TPUNTOS;


void leerTablero( void );
void mostrarTablero( void );
void iniciarFantasmas(void);
DWORD WINAPI metodo1(LPVOID param);
DWORD WINAPI metodo2(LPVOID param);
DWORD WINAPI metodo3(LPVOID param);
void iniciarPacman(void);
void iniciarPuntos(void);
int verificarPartesTablero(void);

char tablero[ RENGLONES ][ COLUMNAS ]; //el tablero es una matriz de 10x10 caracteres

TFANTASMA fantasmas[ CANT_FANTASMAS ]; //conjunto de fantasmas
TPUNTOS puntos[ CANT_PUNTOS ];

HANDLE semaforo;

void main()
{
HANDLE hilos[ CANTIDAD_HILOS ];
clrscr();
randomize();
leerTablero();

//definir semaphore
semaforo= CreateSemaphore( NULL, 1,1, NULL );

hilos[2] = CreateThread( NULL, 0, metodo3, NULL, 0, NULL); //put down points
hilos[1] = CreateThread( NULL, 0, metodo2, NULL, 0, NULL); //put down gost
hilos[0]= CreateThread( NULL, 0, metodo1, NULL, 0, NULL ); //put down pacman
WaitForMultipleObjects(CANTIDAD_HILOS, hilos, 1, INFINITE );
mostrarTablero();
}

void iniciarPacman()
{
int col, ren;
WaitForSingleObject( semaforo, INFINITE );
do
{
col= random( COLUMNAS );
ren= random( RENGLONES );
} while ( tablero[ ren ] [ col ] != ' ' );
tablero[ ren ][ col ]= '@';
ReleaseSemaphore( semaforo, 1, NULL );
}

void iniciarFantasmas()
{
int i;
for(i=0; i< CANT_FANTASMAS ; i+=1 )
{
WaitForSingleObject( semaforo, INFINITE );
do
{
fantasmas[i].col= random( COLUMNAS );
fantasmas[i].ren= random( RENGLONES );
} while ( tablero[ fantasmas[i].ren ] [ fantasmas[i].col ] != ' ' );
tablero[ fantasmas[i].ren ] [ fantasmas[i].col ]='#';
ReleaseSemaphore( semaforo, 1, NULL );
}
}

void iniciarPuntos()
{
int i;
for(i=0; i< CANT_PUNTOS ; i+=1 )
{
WaitForSingleObject( semaforo, INFINITE );
do
{
puntos[i].col= random( COLUMNAS );
puntos[i].ren= random( RENGLONES );
} while ( tablero[ puntos[i].ren ] [ puntos[i].col ] != ' ' );
tablero[ puntos[i].ren ] [ puntos[i].col ]='.';
ReleaseSemaphore( semaforo, 1, NULL );
}
}

void leerTablero()
{
int c, r;
FILE *archivo;
archivo= fopen("tablero.txt","rt");
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
fscanf(archivo, "%c", &tablero[ r ][ c ] );
tablero[ r ][ c ]= (tablero[ r ][ c ]=='1'?' ':tablero[ r ][ c ]);
//printf("%c", tablero[ r ][ c ] );
}
fscanf(archivo, "\n", NULL );
//printf("\n");
}
fclose( archivo );
}

void mostrarTablero()
{
int c, r;
for(r=0; r< RENGLONES ; r+=1 )
{
for( c=0; c< COLUMNAS ; c+=1 )
{
printf("%c", tablero[ r ][ c ] );
}
printf("\n");
}
}

DWORD WINAPI metodo1(LPVOID param)
{
iniciarPacman();
return 0;
}

DWORD WINAPI metodo2(LPVOID param)
{
iniciarFantasmas();
return 0;
}

DWORD WINAPI metodo3(LPVOID param)
{
iniciarPuntos();
return 0;
}


Conclusions
The use of semaphores and critical sections is simple and usefull. We have to use them when many threads use the same resources.

References
[3] Borland C++ Compiler version 5.5 Free Download. Embarcadero developer network. http://edn.embarcadero.com/article/20633
[4] Intel Software Network, Parallel Programming and Multi-Core. Multi - core Programming for Academia ( spanish version ). Programango Hilos en Windows. http://software.intel.com/en-us/articles/multi-core-programing-for-academia-spanish-version-1/28/oct/2008

No hay comentarios:

Publicar un comentario

Are you ready?