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 <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 );
		void iniciar();
		void mover();

	private:
		int col;
		int ren;
		char simbolo;
		int sentido;
		void borrar();
};


**********************
asterisco.cpp
**********************

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#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 <conio.h >
#include <windows.h >
#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 <conio.h >
#include <windows.h >
#include <stdio.h >
#include <stdlib.h >
#include "asterisco.h"


const int CANTIDAD_ASTERISCOS= 3;

void main()
{
	Asterisco *obj[ CANTIDAD_ASTERISCOS ];
	int i;
	clrscr();
	randomize();
	for(i=0; i<CANTIDAD_ASTERISCOS ; i+=1 )
	{
		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 <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 );
		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 <stdio.h >
#include <conio.h >
#include <windows.h >
#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 <conio.h>
#include <windows.h>
#include <stdio.h>
#include "asterisco.h"
#include <stdlib.h>

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
For more complete information about compiler optimizations, see our Optimization Notice.
Categories: