C ++: MPI communicator as a global variable
I need an MPI world communicator to access the functions / functions of a class. But by design / convention of the environment, MPI and communicators are always defined and initialized at the beginning int main()
.
The only simple solution I can think of is using a global pointer to the communicator.
Does anyone know a better way? Is it dangerous to use a global pointer solution?
This problem applies equally well to barebone MPI and Boost :: MPI (which I use below)
An example of my suggested solution (untested):
//globals.h
extern boost::mpi::communicator * my_MPI_world_ptr;
and
//main.cpp
...
int main(int argc, char* argv[])
{
boost::mpi::environment my_boost_mpi_env(argc, argv);
boost::mpi::communicator my_MPI_world;
my_MPI_world_ptr = &my_MPI_world;
my_MPI_rank = my_MPI_world_ptr->rank();
size_MPI_WORLD = my_MPI_world_ptr->size();
my_class an_Object;
an_Object.member_function_that_uses__MPI_world();
...
}
source to share
Do you mean the actual MPI communicator MPI_COMM_WORLD
(or its Boost wrapper)? This is already global. If you are using a different communicator to share communication from the library you are writing, it would be best not to use a global variable at all. In this case, you can just pass it (or a pointer to it) and store it in the classes it needs.
source to share
I don't like globals in general: who is responsible for deleting them? How do you ensure that the pointer is not available before the object is created or after the object is destroyed?
I would be tempted to wrap a pointer and its access in a class. (Warning: the following was not seen by the compiler, so all sorts of problems can occur and I am not familiar with MPI)
class CMPIwrapper
{
public:
CMPIwrapper(boost::mpi::communicator& myMPIworld):myMPIworld_(myMPIworld){}
rank_type GetRank()const
{
return( my_MPI_world_ptr->rank() );
}
private:
boost::mpi::communicator& myMPIworld_;
};
int main(int argc, char* argv[])
{
boost::mpi::environment my_boost_mpi_env(argc, argv);
boost::mpi::communicator my_MPI_world;
CMPIwrapper my_MPI_wrapper(my_MPI_world);
my_MPI_rank = CMPIwrapper.GetRank();
}
Your own objects you used to use the pointer might work the same: their constructor might be passed a reference to your boost :: mpi :: communator, or if the set of operations on your boost :: mpi :: communator is well defined, they might be passed a reference on the wrapper.
source to share
-
To increase the mpi, the default configured (i.e. empty initializer) communicator matches
MPI_COMM_WORLD
, so you can just define anothermpi::communicator world;
inside your function, use it as if it were listed outside.
-
MPI_INIT
called at buildmpi::environment
. So while this is at the beginning of your main program, you can define the globalmpi::communicator
elsewhere. There is no need to use a pointer. (In fact, you can even postMPI_INIT
elsewhere, see below). -
For MPI with blue bones, I tested that calling
MPI_INIT
elsewhere than the main one is also allowed. For example, you can define the following wrapper for the global worker in the header file,class MpiWorker_t { public: int NumberOfWorkers, WorkerId, NameLen; char HostName[MPI_MAX_PROCESSOR_NAME]; MpiWorker_t() { MPI_Init(NULL, NULL); MPI_Comm_size(MPI_COMM_WORLD,&NumberOfWorkers); MPI_Comm_rank(MPI_COMM_WORLD,&WorkerId); MPI_Get_processor_name(HostName, &NameLen); } ~MpiWorker_t() { MPI_Finalize(); } } extern MpiWorker_t GlobalWorker;
and in your source file define a global instance anywhere outside
main()
:MpiWorker_t GlobalWorker;
The construction and destruction of a global variable must be able to take care of initialization and completion
MPI
before and after any function callMPI
.
source to share