По какой конкретной причине вам нужен экземпляр boost::mpi::environment
в ваших классах? Это просто ужасная объектно-ориентированная оболочка вокруг текущей одноэлементной природы MPI - вы можете инициализировать MPI только один раз, вызвав MPI_Init()
, и завершить его только один раз впоследствии, вызвав MPI_Finalize()
(по крайней мере, до тех пор, пока сеансы MPI не перейдут в будущее. версии стандарта). Если вы попытаетесь сделать что-нибудь, связанное с MPI до MPI_Init()
, вы получите сообщение об ошибке (за исключением нескольких работающих вызовов информационных запросов). Если вы попытаетесь сделать что-либо, связанное с MPI, после MPI_Finalize()
, вы получите сообщение об ошибке. Если один ранг выходит без вызова MPI_Finalize()
после вызова MPI_Init()
, вся работа MPI обычно завершается сбоем, поскольку программа запуска предполагает, что что-то случилось, и убивает остальные ранги.
Единственная цель boost::mpi::environment
должен гарантировать, что MPI был инициализирован, а не оставлен незавершенным, и все это контролируется временем жизни объекта. Следовательно, вы должны разместить его экземпляр там, где этот экземпляр будет предшествовать и переживет любую активность MPI в вашей программе, и лучшим местом для этого является функция main()
. Кроме того, хотя реализации MPI-2 широко распространены в настоящее время, и вы можете безопасно использовать вариант конструктора environment
без параметров, для совместимости лучше использовать тот, который принимает argc
и argv
из main()
. Если, конечно, вы не пишете библиотеку.
Обратите внимание, что environment
объекты проверяют, был ли MPI уже инициализирован к моменту их создания, и если да, они не завершат его при уничтожении, но они будут завершить его, если они должны были его инициализировать. Таким образом, у вас не должно быть двух экземпляров с неперекрывающимися сроками жизни. Следовательно, вы должны обеспечить правильный порядок вызова конструктора и деструктора при работе с глобальными экземплярами класса. Так что оставайтесь простыми и просто создайте один экземпляр в функции main()
.
Это не относится к boost::mpi::communicator
. Его конструктор по умолчанию просто обертывает дескриптор коммуникатора MPI_COMM_WORLD
, который является постоянной времени выполнения, относящейся к одноэлементному мировому коммуникатору MPI. Поскольку режим упаковки конструктора по умолчанию - comm_attach
, экземпляр не будет пытаться освободить MPI_COMM_WORLD
при уничтожении, поэтому у вас может быть столько из них, сколько вам нужно, и в любой части вашего кода. Просто имейте в виду, что большинство методов экземпляра работают только после инициализации и до завершения среды MPI, что и определяет время жизни фактического объекта мирового коммуникатора (тот, что в реализации MPI, а не экземпляр boost::mpi::communicator
). .
Вам даже не нужен статический c экземпляр communicator
, он нужен только для доступа к мировому коммуникатору. Вы сохраняете только один вызов new
и один delete
.
Я бы написал ваш код просто так:
#include <boost/mpi.hpp>
#include <iostream>
template<typename T>
class Example {
boost::mpi::communicator world;
public:
Example() {
std::cout << world.rank() << std::endl;
}
};
int main(int argc, char **argv) {
boost::mpi::environment(argc, argv);
auto e = Example<double>();
}
Он работает, как ожидалось:
$ mpic++ -o works works.cc -lboost_mpi
$ mpiexec -n 4 ./works
2
0
3
1