/**
\file mpiExample2.cpp
\brief MPI programming example #2.
\author george j. grevera, ph.d.
This program is a skeleton of a parallel MPI application using the one
manager/many workers framework. The process with an MPI rank of 0 is
considered to be the manager; processes with MPI ranks of 1..mpiSize-1
are workers. Messages are defined and are sent from the manager to the
workers.
compile: mpic++ -g -o mpiExample2.exe mpiExample2.cpp # debug version
mpic++ -O3 -o mpiExample2.exe mpiExample2.cpp # optimized version
run : lamboot -v # to start lam mpi
mpirun -np 4 ./mpiExample2.exe # run in parallel w/ 4 processes
lamhalt # to stop lam mpi
*/
#include
#include
#include
#include
static char mpiName[ 1024 ]; ///< host computer name
static int mpiRank; ///< number of this process (0..n-1)
static int mpiSize; ///< total number of processes (n)
static int myPID; ///< process id
/** \brief format of messages sent between manager and worker processes for
example 2.
\todo define parameters for OP_WORK.
\todo define parameters for OP_RESULT.
*/
struct Message {
enum {
OP_WORK, ///< manager to worker - here's your work assignment
OP_EXIT, ///< manager to worker - time to exit
OP_RESULT ///< worker to manager - here's the result
};
int operation; ///< one of the above
/** \todo define operation specific parameters here. */
};
//----------------------------------------------------------------------
/** \brief manager code for example 2.
*/
static void manager ( void ) {
printf( "manager: my rank=%d, size=%d, pid=%d. \n",
mpiRank, mpiSize, myPID );
/** \todo insert manager code here. */
//as an example, send an empty work message to each worker
struct Message m;
m.operation = m.OP_WORK;
assert( mpiSize>3 );
MPI_Send( &m, sizeof( m ), MPI_UNSIGNED_CHAR, 1, m.operation,
MPI_COMM_WORLD );
MPI_Send( &m, sizeof( m ), MPI_UNSIGNED_CHAR, 2, m.operation,
MPI_COMM_WORLD );
MPI_Send( &m, sizeof( m ), MPI_UNSIGNED_CHAR, 3, m.operation,
MPI_COMM_WORLD );
}
//----------------------------------------------------------------------
/** \brief worker code for example 2.
*/
static void worker ( void ) {
printf( "worker: my rank=%d, size=%d, pid=%d. \n",
mpiRank, mpiSize, myPID );
/** \todo insert worker code here. */
//as an example, receive a message
MPI_Status status;
struct Message m;
MPI_Recv( &m, sizeof( m ), MPI_UNSIGNED_CHAR, MPI_ANY_SOURCE,
MPI_ANY_TAG, MPI_COMM_WORLD, &status );
printf( "worker %d (%d): received message. \n", mpiRank, myPID );
}
//----------------------------------------------------------------------
/** \brief main program entry point for example 2. execution begins here.
\param argc count of command line arguments.
\param argv array of command line arguments.
\returns 0 is always returned.
*/
int main ( int argc, char* argv[] ) { //not const because MPI_Init may change
if (MPI_Init( &argc, &argv ) != MPI_SUCCESS) {
//actually, we'll never get here but it is a good idea to check.
// if MPI_Init fails, mpi will exit with an error message.
puts( "mpi init failed." );
return 0;
}
//get the name of this computer
gethostname( mpiName, sizeof( mpiName ) );
//determine rank
MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
//determine the total number of processes
MPI_Comm_size( MPI_COMM_WORLD, &mpiSize );
//get the process id
myPID = getpid();
printf( "mpi initialized. my rank=%d, size=%d, pid=%d. \n",
mpiRank, mpiSize, myPID );
if (mpiSize<2) {
puts("this example requires at least 1 manager and 1 worker process.");
MPI_Finalize();
return 0;
}
if (mpiRank==0) manager();
else worker();
MPI_Finalize();
return 0;
}
//----------------------------------------------------------------------