gpt4 book ai didi

c++ - boost::mpi 作为模板类的静态成员

转载 作者:行者123 更新时间:2023-12-01 14:42:54 34 4
gpt4 key购买 nike

我想用 boost::mpi我类的沟通者,因为我希望我的类(class)负责所有 MPI 调用。我使用这种风格使它们成为我类(class)的静态成员。

// works.cpp
// mpic++ -o works works.cpp -lboost_mpi
#include <boost/mpi.hpp>
#include <iostream>

class Example {
static boost::mpi::environment env;
static boost::mpi::communicator world;
public:
Example() {
std::cout << world.rank() << std::endl;
}
};

boost::mpi::environment Example::env;
boost::mpi::communicator Example::world;

int main() {
auto e = Example();
}

这工作得很好,例如, mpirun -n 4 ./works按预期打印数字 0 到 3。后来我想为我的类(class)模板。起初我很担心如何初始化我的静态成员变量,但阅读了这篇 answer ,这表明一切都很好
// fails.cpp
// mpic++ -o fails fails.cpp -lboost_mpi
#include <boost/mpi.hpp>
#include <iostream>

template<typename T>
class Example {
static boost::mpi::environment env;
static boost::mpi::communicator world;
public:
Example() {
std::cout << world.rank() << std::endl;
}
};

template <typename T>
boost::mpi::environment Example<T>::env;

template <typename T>
boost::mpi::communicator Example<T>::world;

int main() {
auto e = Example<double>();
}

然而,这实际上给了我
$ mpirun -n 4 ./fails
*** The MPI_Comm_rank() function was called before MPI_INIT was invoked.
*** This is disallowed by the MPI standard.
*** Your MPI job will now abort.
...

这里出了点问题,但是什么?为什么?我想我在这里误解了一些事情。

最佳答案

您需要 boost::mpi::environment 的任何特殊原因在你的类(class)中实例?它只是 MPI 当前单例性质的一个可怕的 OO 包装器 - 您可以通过调用 MPI_Init() 来初始化 MPI 一次。然后通过调用 MPI_Finalize() 完成一次(至少,在 MPI session 使其成为标准的 future 版本之前)。如果您在 MPI_Init() 之前尝试做任何与 MPI 相关的事情,你会得到一个错误(除了少数有效的信息查询调用)。如果您在 MPI_Finalize() 之后尝试做任何与 MPI 相关的事情,你得到一个错误。如果单个等级退出而不调用 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 的实例) .

您甚至不需要 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

关于c++ - boost::mpi 作为模板类的静态成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61653255/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com