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

Beging the study about parallel programming step by step

Intel is supporting parallel programming training because his processors are multicore

Your first step could be read the web page about developer training.

(1)
http://software.intel.com/en-us/developertraining/
Developer Training

I like the first article because explain the basic concepts and is simple for understand.

(2)
http://software.intel.com/en-us/articles/8-simple-rules-for-designing-threaded-applications/
8 Simple Rules for Designing Threaded Applications


There are some presentations on Ms Power Point that you must to read. I think they are a good step if you clicked the link named "Academic Courseware content site"

(3)
http://software.intel.com/en-us/articles/courseware-access/
Technology Curriculum

This page have three sections
(a) Multi Core Courseware from Intel
(b) Multi COre Courseware from faculty
(c) Intel Higher Ed Curriculum

Please choose the first option ( this material had been made for Intel people ).

(4)
http://software.intel.com/en-us/articles/multi-core-courseware-content-from-intel-1/
Multi Core Couseware from Intel

This page show you a menu, choose the option "4.a Multi core Programming for academia" and click over "Multicore programming for academia".

(5)
http://software.intel.com/en-us/articles/multi-core-programming-for-academia/
Multicore programming for academia

I believe this course is the best by his structure, if you know basic concepts you must to go to the second day. With this material you could think some exercises on C, C++, C#, JAVA, VB, so on

Paso por paso en el web de Intel sobre programación paralela para principantes

Iniciando paso por paso en la programación paralela

Intel está apoyando la capacitación en programación paralela ya que sus procesadores se han vuelto "multinucleo".

Puedes iniciar revisando la página dedicada al entrenamiento para desarrolladores:

(1)
http://software.intel.com/en-us/developertraining/
Developer Training

En lo personal puedo recomendar el artículo que ellos también recomiendan, ya que inicia con conceptos básicos y creo que el orden de exposición y la sencillez son buenos.

(2)
http://software.intel.com/en-us/articles/8-simple-rules-for-designing-threaded-applications/
8 Simple Rules for Designing Threaded Applications

Para iniciar con una serie de presentaciones en Ms Power Point
que van desde el conocimiento bàsico hasta uno medianamente
avanzado, creo que una buena recomendaciòn que puedo darte es
posterior a leer el paso 2, regresar a la pàgina (1) y oprimir
el enlace hacia "Academic Courseware content site"

(3)
http://software.intel.com/en-us/articles/courseware-access/
Technology Curriculum

En esta pàgina aparecen tres grandes divisiones:
(a) Multi Core Courseware from Intel
(b) Multi COre Courseware from faculty
(c) Intel Higher Ed Curriculum

Por favor escoge la primera opciòn, donde veras material
desarrolado por personal de Intel.

(4) Multi Core Couseware from Intel
http://software.intel.com/en-us/articles/multi-core-courseware-content-from-intel-1/

Nuevamente se vuelve a dividir en muchas opciones, mostràndose
un menu. Por favor escoge la opciòn "4.a Multi core Programming for Academia"
Una vez hecho esto solo se recorrerà al final de la pàgina, en ese momento
debes oprimir el enlace con el tìtulo " Multicore programming for academia".

(5)
http://software.intel.com/en-us/articles/multi-core-programming-for-academia/
Multicore programming for academia

Creo que este curso es el que mejor está estructurado. si conoces conceptos básicos
salta al dìa 2. Este material te darà muchas ideas en que pensar para comenzar a
practicar la programaciòn con hilos usando C, C++, C#, JAVA, VB, etc.

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

Example of threads on JAVA

Introduction
Using threads on Java is very simple. There are many tutorial sites (only write in goole +tutorial +thread ). In this article shown an example of a "serial" program that is converted on "parallel" program. In this case the autor divide datas and assign to each thread.

"serial" code
Generated 100 names with 2 arrays.
public class hilo__1
{
private String[] nombres= new String[10];
private String[] apellidos= new String[10];

public hilo__1()
{
nombres[0]= "jesus";
nombres[1]= "antonio";
nombres[2]= "claudia";
nombres[3]= "Pilar";
nombres[4]= "Magdalena";
nombres[5]= "Roberto";
nombres[6]= "Elias";
nombres[7]= "Ana";
nombres[8]= "Mario";
nombres[9]= "Maria";

apellidos[0]= "perez";
apellidos[1]= "rivera";
apellidos[2]= "marte";
apellidos[3]= "lopez";
apellidos[4]= "Liz";
apellidos[5]= "Cabrera";
apellidos[6]= "Macias";
apellidos[7]= "Rodriguez";
apellidos[8]= "Mares";
apellidos[9]= "Limon";
}

public void mostrar()
{
int i, j;
for(i=0; i< 10 ; i+=1)
{
for(j=0; j<10; j+=1 )
{
System.out.println(nombres[i] + " " + apellidos[j] );
}
}
}

public static void main(String[] args)
{
hilo__1 obj= new hilo__1();
obj.mostrar();
}

}

"Parallel" code
Using inherintance of thread class
public class hilo__2 extends Thread
{
private String[] nombres= new String[10];
private String[] apellidos= new String[10];
private int inicio;
private int termino;
private String name;

public hilo__2(int i, int j, String n)
{
inicio= i;
termino= j;
name= n;

nombres[0]= "jesus";
nombres[1]= "antonio";
nombres[2]= "claudia";
nombres[3]= "Pilar";
nombres[4]= "Magdalena";
nombres[5]= "Roberto";
nombres[6]= "Elias";
nombres[7]= "Ana";
nombres[8]= "Mario";
nombres[9]= "Maria";

apellidos[0]= "perez";
apellidos[1]= "rivera";
apellidos[2]= "marte";
apellidos[3]= "lopez";
apellidos[4]= "Liz";
apellidos[5]= "Cabrera";
apellidos[6]= "Macias";
apellidos[7]= "Rodriguez";
apellidos[8]= "Mares";
apellidos[9]= "Limon";
}

public void mostrar()
{
int i, j;
for(i=inicio; i< termino; i+=1)
{
for(j=0; j<10; j+=1 )
{
System.out.println(name + " -> " + nombres[i] + " " + apellidos[j] );
}
}
}

public void run()
{
this.mostrar();
}

public static void main(String[] args)
{
hilo__2 obj1= new hilo__2(0,5,"1");
hilo__2 obj2= new hilo__2(5,10,"2");
obj1.start();
obj2.start();
}

}
"Parallel" code
Using inherintance of Runnable interface
public class hilo_run implements Runnable
{

private String[] nombres= new String[10];
private String[] apellidos= new String[10];
private int inicio;
private int termino;
private String name;


public hilo_run(int i, int j, String n)
{
inicio= i;
termino= j;
name= n;

nombres[0]= "jesus";
nombres[1]= "antonio";
nombres[2]= "claudia";
nombres[3]= "Pilar";
nombres[4]= "Magdalena";
nombres[5]= "Roberto";
nombres[6]= "Elias";
nombres[7]= "Ana";
nombres[8]= "Mario";
nombres[9]= "Maria";

apellidos[0]= "perez";
apellidos[1]= "rivera";
apellidos[2]= "marte";
apellidos[3]= "lopez";
apellidos[4]= "Liz";
apellidos[5]= "Cabrera";
apellidos[6]= "Macias";
apellidos[7]= "Rodriguez";
apellidos[8]= "Mares";
apellidos[9]= "Limon";
}

public void mostrar()
{
int i, j;
for(i=inicio; i< termino; i+=1)
{
for(j=0; j<10; j+=1 )
{
System.out.println(name + " -> " + nombres[i] + " " + apellidos[j] );
}
}
}

public void run()
{
this.mostrar();
}

public static void main(String[] args)
{
hilo_run obj1= new hilo_run(0,5,"1");
hilo_run obj2= new hilo_run(5,10,"2");
Thread hilo1 = new Thread (obj1);
Thread hilo2 = new Thread (obj2);
hilo1.start();
hilo2.start();
System.out.println("fin");
}

}

Introduction to parallel programming with examples

Introduction

How do you convert one "serial" program to parallel programming?.In this article try to show a didactical example for this convertion.The example program was made on the paradigm object oriented programming ( OOP ) using c++.

The program on OOP "serial"
On the first class of programming logic at University Autonomous of Guadalajara[1] ( UAG ) this example is used. Make a program on Ms Windows using its real mode[2] that show an asterisk bouncing on diagonal shape on the screen ( when crash with the borders ). The end is when is pressed any key.
 
**********************
asterisco.h
**********************
 
#include
 
class Asterisco
{
 public:
  Asterisco();
  int getCol();
  int getRen();
  void setCol( int valor );
  void setRen( int valor );
  void mostrar();
  int getSentido();
  void setSentido( int valor );
  void iniciar();
  void mover();
 private:
  int col;
  int ren;
  char simbolo;
  int sentido;
  void borrar();
};
 
**********************
asterisco.cpp
**********************

#include
#include
#include
#include "asterisco.h"
Asterisco::Asterisco()
{
 simbolo='*';
 sentido=0;
}
int Asterisco::getCol()
{
 return col;
}
int Asterisco::getSentido()
{
 return sentido;
}
int Asterisco::getRen()
{
 return ren;
}
void Asterisco::setCol( int valor )
{
 col= valor;
}
void Asterisco::setSentido( int valor )
{
 sentido=valor;
}
void Asterisco::setRen( int valor )
{
 ren= valor;
}
void Asterisco::mostrar()
{
 gotoxy( getCol(), getRen() );
 printf("%c", simbolo, ren );
}
void Asterisco::borrar()
{
 gotoxy( getCol(), getRen() );
 printf(" " );
}

void Asterisco::mover()
{
 borrar();
 switch ( sentido )
 {
  case 0: //rigth upper
   if ( ren>1)
   {
    if (col < 79 )
    {
     ren-=1;
     col+=1;
    }
    else
     sentido= 1;
   }
   else
    sentido=2;
   break;
  case 1: //left upper
   if ( ren>1 )
   {
    if ( col>1 )
    {
     ren-=1;
     col-=1;
    }
    else
     sentido= 0;
   }
   else
    sentido= 3;
   break;
  case 2: //right down
   if ( ren<24 )
   {
    if ( col< 80 )
    {
     ren+=1;
     col+=1;
    }
    else
     sentido= 3;
   }
   else
    sentido= 0;
   break;
  case 3: //left down
   if ( ren< 24 )
   {
    if ( col > 1 )
    {
     ren+=1;
     col-=1;
    }
    else
     sentido= 2;
   }
   else
    sentido= 1;
   break;
 }
 mostrar();
}
 
**********************
inicio.cpp
**********************
#include
#include
#include "asterisco.h"
void main()
{
 Asterisco *obj= new Asterisco();
 clrscr();
 obj->setCol( 20 );
 obj->setRen( 18 );
 obj->setSentido( 0 );
 obj->mostrar();
 do
 {
  Sleep( 200 );
  obj->mover();
 } while ( !kbhit() );
}

For compiling the program using the free compiler of Borland version 5.5[3] :
 
bcc32 asterisco.cpp inicio.cpp
 
The program on OOP "parallel
After this exercise, the teacher ask for one modification on the program: Show many asterisks independents bouncing at the screen maybe on differents directions. The program use the function random for initial position and direction. The response could be an objects array and with iterations move each object one position. In this case the user believe that all asterisks are moving on the same time.This is the code:
 
********************
asterisco.h
********************

#include < windows.h >
class Asterisco
{
 public:
  Asterisco();
  int getCol();
  int getRen();
  void setCol( int valor );
  void setRen( int valor );
  void mostrar();
  int getSentido();
  void setSentido( int valor );
  int getTermino();
  void setTermino( int valor );
  void mover();
 private:
  int col;
  int ren;
  char simbolo;
  int sentido;
  char termino;
  
  void borrar();
};

********************
asterisco.cpp
********************
#include < stdio.h >
#include < conio.h >
#include < windows.h >
#include "asterisco.h"
Asterisco::Asterisco()
{
 simbolo='*';
 sentido=0;
 termino='a';
}
int Asterisco::getCol()
{
 return col;
}
int Asterisco::getSentido()
{
 return sentido;
}
int Asterisco::getRen()
{
 return ren;
}
void Asterisco::setCol( int valor )
{
 col= valor;
}
void Asterisco::setSentido( int valor )
{
 sentido=valor;
}
void Asterisco::setRen( int valor )
{
 ren= valor;
}
void Asterisco::mostrar()
{
 gotoxy( getCol(), getRen() );
 printf("%c", simbolo, ren );
}
void Asterisco::borrar()
{
 gotoxy( getCol(), getRen() );
 printf(" " );
}
void Asterisco::mover()
{
 borrar();
 switch ( sentido )
 {
  case 0: //rigth upper
   if ( ren>1)
   {
    if (col < 79 )
    {
     ren-=1;
     col+=1;
    }
    else
     sentido= 1;
   }
   else
    sentido=2;
   break;
  case 1: //left upper
   if ( ren>1 )
   {
    if ( col>1 )
    {
     ren-=1;
     col-=1;
    }
    else
     sentido= 0;
   }
   else
    sentido= 3;
   break;
  case 2: //right down
   if ( ren<24 )
   {
    if ( col< 80 )
    {
     ren+=1;
     col+=1;
    }
    else
     sentido= 3;
   }
   else
    sentido= 0;
   break;
  case 3: //left down
   if ( ren< 24 )
   {
    if ( col > 1 )
    {
     ren+=1;
     col-=1;
    }
    else
     sentido= 2;
   }
   else
    sentido= 1;
   break;
 }
 mostrar();
}
int Asterisco::getTermino()
{
 return termino;
}
void Asterisco::setTermino( int valor )
{
 termino= valor;
}

********************
inicio.cpp
********************
#include
#include
#include
#include
#include "asterisco.h"

const int CANTIDAD_ASTERISCOS= 3;
void main()
{
 Asterisco *obj[ CANTIDAD_ASTERISCOS ];
 int i;
 clrscr();
 randomize();
 for(i=0; i {
  obj[i]= new Asterisco();
  obj[i]->setCol( random( 80 ) );
  obj[i]->setRen( random( 24 ) );
  obj[i]->setSentido( random( 4 ) );
  obj[i]->mostrar();
 }
 i=0;
 do
 {
  Sleep( 250);
  obj[i++]->mover();
  i= ( i>= CANTIDAD_ASTERISCOS ? 0 : i );
 } while ( !kbhit() );
}
The change was made in the main. On this moment is very easy and simple introducing the parallel programming using one thread for each asterisk and there are few changes.
 
********************
asterisco.h
********************
#include
class Asterisco
{
 public:
  Asterisco();
  int getCol();
  int getRen();
  void setCol( int valor );
  void setRen( int valor );
  void mostrar();
  int getSentido();
  void setSentido( int valor );
  void iniciar();                  //new method
  int getTermino();
  void setTermino( int valor );
 private:
  int col;
  int ren;
  char simbolo;
  int sentido;
  char termino;
  
  void borrar();
  void mover();                    //now is privated
};
 
********************
asterisco.cpp
********************
#include
#include
#include
#include "asterisco.h"
Asterisco::Asterisco()
{
 simbolo='*';
 sentido=0;
 termino='p';
}
int Asterisco::getCol()
{
 return col;
}
int Asterisco::getSentido()
{
 return sentido;
}
int Asterisco::getRen()
{
 return ren;
}
void Asterisco::setCol( int valor )
{
 col= valor;
}
void Asterisco::setSentido( int valor )
{
 sentido=valor;
}
void Asterisco::setRen( int valor )
{
 ren= valor;
}
void Asterisco::mostrar()
{
 gotoxy( getCol(), getRen() );
 printf("%c", simbolo );
}
void Asterisco::borrar()
{
 gotoxy( getCol(), getRen() );
 printf(" " );
}
void Asterisco::iniciar()  //has the code that was used on main
{
 termino='a';
 do
 {
  Sleep( 200 );
  mover();
 } while ( !kbhit() );
 termino='f';
}
void Asterisco::mover()
{
 borrar();
 switch ( sentido )
 {
  case 0: //rigth upper
    if ( ren > 1)
    {
     if (col < 79 )
     {
      ren-=1;
      col+=1;
     }
     else
      sentido= 1;
    }
    else
     sentido=2;
    break;
  case 1: //left upper
    if ( ren > 1 )
    {
     if ( col > 1 )
     {
      ren-=1;
      col-=1;
     }
     else
      sentido= 0;
    }
    else
     sentido= 3;
    break;
  case 2: //rigth down
    if ( ren < 24 )
    {
     if ( col < 80 )
     {
      ren+=1;
      col+=1;
     }
     else
      sentido= 3;
    }
    else
     sentido= 0;
    break;
  case 3: //left down
    if ( ren < 24 )
    {
     if ( col > 1 )
     {
      ren+=1;
      col-=1;
     }
     else
      sentido= 2;
    }
    else
     sentido= 1;
    break;
 }
 mostrar();
}
int Asterisco::getTermino()
{
 return termino;
}
void Asterisco::setTermino( int valor )
{
 termino= valor;
}

********************
inicio.cpp
********************
#include
#include
#include
#include "asterisco.h"
#include
DWORD WINAPI iniciarAsterisco(LPVOID param);
const int CANTIDAD_HILOS = 3;
Asterisco *obj[ CANTIDAD_HILOS ];
void main()
{
 HANDLE hilos[ CANTIDAD_HILOS ];
 int i;
 int *valorEntero;
 void *parametroVoid= NULL;
 randomize();
 clrscr();
 for( i=0; i < CANTIDAD_HILOS ;i += 1 )
 {
  obj[ i ] = new Asterisco();
  obj[ i ] -> setCol( random(80) );
  obj[ i ] -> setRen( random(24) );
  obj[ i ] -> setSentido( random(5) );
  obj[ i ] -> mostrar();
 }
 parametroVoid= malloc( sizeof(int ) );
 valorEntero= (int *) parametroVoid;
 for( i=0; i< CANTIDAD_HILOS ;i += 1 )
 {
  *valorEntero= i;
  if ( ( hilos[i]= CreateThread( NULL, 0, iniciarAsterisco, parametroVoid, 0, NULL )) == NULL )
   printf("error en hilo 0");
  Sleep( 500 );
 }
 WaitForMultipleObjects( CANTIDAD_HILOS, hilos, true, INFINITE );
}
DWORD WINAPI iniciarAsterisco(LPVOID param)
{
 int *i= (int *) param;
 obj[ (*i) ]->iniciar();
 return 0;
}
 
Note: Some times the screen showed more asterisk by memory errors.
 
The instruction CreateThread is studied on many coursewares, in this article don't try to explain it.
 
Future improvements
Graphic user interface.
Don't use the function Sleep for stop the principal flow between each definition thread.
 
References
[1] Universidad Autónoma de Guadalajara. http://www.uag.mx
[2] Real Mode of Ms Windows.  Wikipedia. http://en.wikipedia.org/wiki/Real_mode
[3] Borland C++ Compiler version 5.5 Free Download. Embarcadero developer network. http://edn.embarcadero.com/article/20633

sábado, 19 de diciembre de 2009

Ejemplo para introducción al paralelismo

Introduccion

Algunos alumnos dificilmente visualizan como se puede convertir un programa "en serie" en "paralelo". A continuación se presenta el caso de un programa hecho usando el paradigma de programacion orientada a objetos ( por sus siglas POO ) en C++ que es convertido a la programación paralela siguiendo el mismo paradigma de programación.

El programa en POO "serial"

En las primeras clases de lógica de programación en la Universidad Autónoma de Guadalajara [1] ( por sus siglas UAG ) se utiliza el siguiente ejercicio:

Realiza un programa para ejecutarse sobre Ms Windows usando el "símbolo del sistema" - modo real o virtual del Ms Windows[2] - que muestre un asterisco rebotando en forma diagonal por la pantalla (al chocar con sus bordes ). El programa termina cuando se presiona cualquier tecla.

**********************

asterisco.h

**********************

#include

class Asterisco

{

public:

Asterisco();

int getCol();

int getRen();

void setCol( int valor );

void setRen( int valor );

void mostrar();

int getSentido();

void setSentido( int valor );

void mover();

private:

int col;

int ren;

char simbolo;

int sentido;

void borrar();

};

**********************

asterisco.cpp

**********************

#include

#include

#include

#include "asterisco.h"

Asterisco::Asterisco()

{

simbolo='*';

sentido=0;

}

int Asterisco::getCol()

{

return col;

}

int Asterisco::getSentido()

{

return sentido;

}

int Asterisco::getRen()

{

return ren;

}

void Asterisco::setCol( int valor )

{

col= valor;

}

void Asterisco::setSentido( int valor )

{

sentido=valor;

}

void Asterisco::setRen( int valor )

{

ren= valor;

}

void Asterisco::mostrar()

{

gotoxy( getCol(), getRen() );

printf("%c", simbolo, ren );

}

void Asterisco::borrar()

{

gotoxy( getCol(), getRen() );

printf(" " );

}

void Asterisco::mover()

{

borrar();

switch ( sentido )

{

case 0: //superior derecha

if ( ren>1)

{

if (col <>

{

ren-=1;

col+=1;

}

else

sentido= 1;

}

else

sentido=2;

break;

case 1: //superior izquierda

if ( ren>1 )

{

if ( col>1 )

{

ren-=1;

col-=1;

}

else

sentido= 0;

}

else

sentido= 3;

break;

case 2: //inferior derecha

if ( ren<24>

{

if ( col<>

{

ren+=1;

col+=1;

}

else

sentido= 3;

}

else

sentido= 0;

break;

case 3: //inferior izquierda

if ( ren<>

{

if ( col > 1 )

{

ren+=1;

col-=1;

}

else

sentido= 2;

}

else

sentido= 1;

break;

}

mostrar();

}

**********************

inicio.cpp

**********************

#include

#include

#include "asterisco.h"

void main()

{

Asterisco *obj= new Asterisco();

clrscr();

obj->setCol( 20 );

obj->setRen( 18 );

obj->setSentido( 0 );

obj->mostrar();

do

{

Sleep( 200 );

obj->mover();

} while ( !kbhit() );

}

El programa usará el compilador gratuito de Borland en su version 5.5[3] de la siguiente forma:

bcc32 asterisco.cpp inicio.cpp

El programa POO paralelo

Posteriormente se solicita a los alumnos que modifiquen el anterior programa para generar varios asteriscos y que cada uno vaya rebotando en la pantalla en direcciones distintas ( el programa coloca posiciones iniciales aleatorias con un sentido inicial aleatorio ). Una posible solución es usar un arreglo de objetos de la clase asterisco. Por medio de un ciclo recorrer constantemente todos los objetos y mover un asterisco a la vez para dar la impresión al usuario que se mueven todos los asteriscos al mismo tiempo. El código es el siguiente:

********************

asterisco.h

********************

#include <>

class Asterisco

{

public:

Asterisco();

int getCol();

int getRen();

void setCol( int valor );

void setRen( int valor );

void mostrar();

int getSentido();

void setSentido( int valor );

int getTermino();

void setTermino( int valor );

void mover();

private:

int col;

int ren;

char simbolo;

int sentido;

char termino;

void borrar();

};

********************

asterisco.cpp

********************

#include <>

#include <>

#include <>

#include "asterisco.h"

Asterisco::Asterisco()

{

simbolo='*';

sentido=0;

termino='a';

}

int Asterisco::getCol()

{

return col;

}

int Asterisco::getSentido()

{

return sentido;

}

int Asterisco::getRen()

{

return ren;

}

void Asterisco::setCol( int valor )

{

col= valor;

}

void Asterisco::setSentido( int valor )

{

sentido=valor;

}

void Asterisco::setRen( int valor )

{

ren= valor;

}

void Asterisco::mostrar()

{

gotoxy( getCol(), getRen() );

printf("%c", simbolo, ren );

}

void Asterisco::borrar()

{

gotoxy( getCol(), getRen() );

printf(" " );

}

void Asterisco::mover()

{

borrar();

switch ( sentido )

{

case 0: //superior derecha

if ( ren>1)

{

if (col <>

{

ren-=1;

col+=1;

}

else

sentido= 1;

}

else

sentido=2;

break;

case 1: //superior izquierda

if ( ren>1 )

{

if ( col>1 )

{

ren-=1;

col-=1;

}

else

sentido= 0;

}

else

sentido= 3;

break;

case 2: //inferior derecha

if ( ren<24>

{

if ( col<>

{

ren+=1;

col+=1;

}

else

sentido= 3;

}

else

sentido= 0;

break;

case 3: //inferior izquierda

if ( ren<>

{

if ( col > 1 )

{

ren+=1;

col-=1;

}

else

sentido= 2;

}

else

sentido= 1;

break;

}

mostrar();

}

int Asterisco::getTermino()

{

return termino;

}

void Asterisco::setTermino( int valor )

{

termino= valor;

}

********************

inicio.cpp

********************

#include

#include

#include

#include

#include "asterisco.h"

const int CANTIDAD_ASTERISCOS= 3;

void main()

{

Asterisco *obj[ CANTIDAD_ASTERISCOS ];

int i;

clrscr();

randomize();

for(i=0; i

{

obj[i]= new Asterisco();

obj[i]->setCol( random( 80 ) );

obj[i]->setRen( random( 24 ) );

obj[i]->setSentido( random( 4 ) );

obj[i]->mostrar();

}

i=0;

do

{

Sleep( 250);

obj[i++]->mover();

i= ( i>= CANTIDAD_ASTERISCOS ? 0 : i );

} while ( !kbhit() );

}

El único cambio ocurrio en el código que contenia al main. En este momento es donde más fácilmente se puede introducir la programación paralela y la ventaja de los hilos; al controlar cada uno un asterisco. El código que se genera solo se modifica en pocos lugares.

********************

asterisco.h

********************

#include

class Asterisco

{

public:

Asterisco();

int getCol();

int getRen();

void setCol( int valor );

void setRen( int valor );

void mostrar();

int getSentido();

void setSentido( int valor );

void iniciar(); //nuevo método

int getTermino();

void setTermino( int valor );

private:

int col;

int ren;

char simbolo;

int sentido;

char termino;

void borrar();

void mover(); //ahora es privado

};

********************

asterisco.cpp

********************

#include

#include

#include

#include "asterisco.h"

Asterisco::Asterisco()

{

simbolo='*';

sentido=0;

termino='p';

}

int Asterisco::getCol()

{

return col;

}

int Asterisco::getSentido()

{

return sentido;

}

int Asterisco::getRen()

{

return ren;

}

void Asterisco::setCol( int valor )

{

col= valor;

}

void Asterisco::setSentido( int valor )

{

sentido=valor;

}

void Asterisco::setRen( int valor )

{

ren= valor;

}

void Asterisco::mostrar()

{

gotoxy( getCol(), getRen() );

printf("%c", simbolo );

}

void Asterisco::borrar()

{

gotoxy( getCol(), getRen() );

printf(" " );

}

void Asterisco::iniciar() //contiene el ciclo que antes estaba en el main

{

termino='a';

do

{

Sleep( 200 );

mover();

} while ( !kbhit() );

termino='f';

}

void Asterisco::mover()

{

borrar();

switch ( sentido )

{

case 0: //superior derecha

if ( ren > 1)

{

if (col <>

{

ren-=1;

col+=1;

}

else

sentido= 1;

}

else

sentido=2;

break;

case 1: //superior izquierda

if ( ren > 1 )

{

if ( col > 1 )

{

ren-=1;

col-=1;

}

else

sentido= 0;

}

else

sentido= 3;

break;

case 2: //inferior derecha

if ( ren <>

{

if ( col <>

{

ren+=1;

col+=1;

}

else

sentido= 3;

}

else

sentido= 0;

break;

case 3: //inferior izquierda

if ( ren <>

{

if ( col > 1 )

{

ren+=1;

col-=1;

}

else

sentido= 2;

}

else

sentido= 1;

break;

}

mostrar();

}

int Asterisco::getTermino()

{

return termino;

}

void Asterisco::setTermino( int valor )

{

termino= valor;

}

********************

inicio.cpp

********************

#include

#include

#include

#include "asterisco.h"

#include

DWORD WINAPI iniciarAsterisco(LPVOID param);

const int CANTIDAD_HILOS = 3;

Asterisco *obj[ CANTIDAD_HILOS ];

void main()

{

HANDLE hilos[ CANTIDAD_HILOS ];

int i;

int *valorEntero;

void *parametroVoid= NULL;

randomize();

clrscr();

for( i=0; i <>

{

obj[ i ] = new Asterisco();

obj[ i ] -> setCol( random(80) );

obj[ i ] -> setRen( random(24) );

obj[ i ] -> setSentido( random(5) );

obj[ i ] -> mostrar();

}

parametroVoid= malloc( sizeof(int ) );

valorEntero= (int *) parametroVoid;

for( i=0; i<>

{

*valorEntero= i;

if ( ( hilos[i]= CreateThread( NULL, 0, iniciarAsterisco, parametroVoid, 0, NULL ))

        == NULL )

printf("error en hilo 0");

Sleep( 500 );

}

WaitForMultipleObjects( CANTIDAD_HILOS, hilos, true, INFINITE );

}

DWORD WINAPI iniciarAsterisco(LPVOID param)

{

int *i= (int *) param;

obj[ (*i) ]->iniciar();

return 0;

}

Nota: En algunas computadoras se generan más asteriscos de los esperados por errores en el manejo de la memoria.

La instrucción CreateThread se utiliza en un ciclo para generar 3 hilos, uno para cada asterisco. Hay muchas otras diapositivas y artículos donde se habla de esta instrucción por eso se no consideró oportuno hablar de ella.

Trabajos futuros

Este código evidencía el uso del tipo de dato "void" . Posteriormente en otros ejemplos se profundizará su estudio.

  • En esta ocasión se usó un arreglo de hilos que manejaban objetos de la misma clase, pero cuando estos sean diferentes ¿qué cambios habrá?
  • Realizar este juego usando una interface gráfica de windows.
  • En el ejemplo se utiliza la función Sleep para detener el flujo principal ( el main del programa ) entre cada generación de hilo, esto es por la variable compartida que se pasa como parámetro para inicializar cada hilo. De no hacerlo ¿qué sucede?

Este es un ejercicio que hará reflexionar a los estudiantes sobre la forma de trabajar de los hilos y que es tratada en varios de los cursos en línea ubicados en el sitio de Intel [4]

Referencias

[1] Universidad Autónoma de Guadalajara. http://www.uag.mx

[2] Real Mode of Ms Windows. Wikipedia. http://en.wikipedia.org/wiki/Real_mode

[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


sábado, 9 de agosto de 2008

China vista por Newsweek

La revista newsweek en español del 4 de agosto del2008, contiene un artículo titulado "Perspectiva juegos olímpicos LA AGONIA DE LA DERROTA" escrito por Orville Schell.

Al termina de leer este artículo me quedo la impresión de que este artículo forma parte de una campaña contra la gran popularidad de los juegos olímpicos organizados por China. Ya que termine con la fuerte impresión de que el autor insiste en demostrar que los chinos estan traumados por su pasado de "humillación" y que estos juegos olímpicos serán vistos por ellos como su oportunidad para derrotar a los occidentales.

Auque aparentemente está bien documentado, es de mi parecer que la tesis principal que presenta este artículo es incorrecta. Los chinos ya le ha demostrado al mundo desde hace varios años de su capacidad, no estoy de acuerdo con la existencia de ese trauma de forma generalizada en el pueblo chino ( quizas si existe en varias o muchas personas conocidas por el autor, pero no creo que sea una generalización nacional) . Desde su incorporación en el consejo de seguridad permanente de las naciones unidas China a se ha ganado un lugar de respeto en el "concierto universal" a pesar de los gritos de protesta de intereses com HongKong que se sintió traicinado por EUA al aceptar su imcorporación.

Además, su historia confirma el caracter luchador del pueblo chino; fuera de su ideología social ( que no comparto) los chinos no se hicieron comunistas Stalinistas sino que formaron su propio concepto de comunismo.