boost mpi 集体操作中的操作类型
Operation type in boost mpi collective operations
在boost::mpi
中,一些集体操作,例如reduce,需要将操作传递给例程。我不确定这个操作的类型到底应该是什么。
以下最小示例编译时没有警告。
#include <iostream>
#include <boost/mpi/collectives.hpp>
int mysum(int a, int b) { return a + b; }
int main()
{
boost::mpi::environment env;
boost::mpi::communicator world;
int data = world.rank() + 1;
int data_reduced;
boost::mpi::reduce(world, data, data_reduced, mysum, 0);
if (world.rank() == 0)
std::cout << data_reduced << std::endl;
return 0;
}
但是,运行 超过 1 个任务崩溃
$ mpirun -n 2 ./mpi
munmap_chunk(): invalid pointer
...
按如下方式更改代码可使程序正常运行。
#include <iostream>
#include <boost/mpi/collectives.hpp>
struct mysum {
int operator()(int a, int b) { return a + b; }
};
int main()
{
boost::mpi::environment env;
boost::mpi::communicator world;
int data = world.rank() + 1;
int data_reduced;
boost::mpi::reduce(world, data, data_reduced, mysum{}, 0);
if (world.rank() == 0)
std::cout << data_reduced << std::endl;
return 0;
}
(我知道这相当于std::plus,程序只是一个例子)
$ mpirun -n 2 ./mpi
3
有什么区别,为什么第二个版本有效?
编辑
问题也出现了,因为mysum
的两个变体都可以称为mysum(....)
,即都是callable。所以在这两种情况下,如下代码都有效。
template <class Callable, class ArgType>
auto dosomething(ArgType a, ArgType b, Callable&& L) { return L(a, b); }
auto x = dosomething(mysum, 1, 2);
(本质上等同于std::invoke)
看来这就是boost::mpi
所期望的!
如果你模仿boost/mpi/operations.h
,你的用户定义归约运算符可以这样写
template<typename T>
struct mysum
{
typedef T first_argument_type;
typedef T second_argument_type;
typedef T result_type;
const T& operator()(const T& x, const T& y) const
{
return x + y;
}
};
然后你的 reduce 调用看起来像那样
boost::mpi::reduce(world, data, data_reduced, std::plus<int>(), 0);
最重要的是,即使你的 mysum
是正确的传递给平原 C
MPI_Op_create()
,这也不是 boost::mpi
所期望的。
在boost::mpi
中,一些集体操作,例如reduce,需要将操作传递给例程。我不确定这个操作的类型到底应该是什么。
以下最小示例编译时没有警告。
#include <iostream>
#include <boost/mpi/collectives.hpp>
int mysum(int a, int b) { return a + b; }
int main()
{
boost::mpi::environment env;
boost::mpi::communicator world;
int data = world.rank() + 1;
int data_reduced;
boost::mpi::reduce(world, data, data_reduced, mysum, 0);
if (world.rank() == 0)
std::cout << data_reduced << std::endl;
return 0;
}
但是,运行 超过 1 个任务崩溃
$ mpirun -n 2 ./mpi
munmap_chunk(): invalid pointer
...
按如下方式更改代码可使程序正常运行。
#include <iostream>
#include <boost/mpi/collectives.hpp>
struct mysum {
int operator()(int a, int b) { return a + b; }
};
int main()
{
boost::mpi::environment env;
boost::mpi::communicator world;
int data = world.rank() + 1;
int data_reduced;
boost::mpi::reduce(world, data, data_reduced, mysum{}, 0);
if (world.rank() == 0)
std::cout << data_reduced << std::endl;
return 0;
}
(我知道这相当于std::plus,程序只是一个例子)
$ mpirun -n 2 ./mpi
3
有什么区别,为什么第二个版本有效?
编辑
问题也出现了,因为mysum
的两个变体都可以称为mysum(....)
,即都是callable。所以在这两种情况下,如下代码都有效。
template <class Callable, class ArgType>
auto dosomething(ArgType a, ArgType b, Callable&& L) { return L(a, b); }
auto x = dosomething(mysum, 1, 2);
(本质上等同于std::invoke)
看来这就是boost::mpi
所期望的!
如果你模仿boost/mpi/operations.h
,你的用户定义归约运算符可以这样写
template<typename T>
struct mysum
{
typedef T first_argument_type;
typedef T second_argument_type;
typedef T result_type;
const T& operator()(const T& x, const T& y) const
{
return x + y;
}
};
然后你的 reduce 调用看起来像那样
boost::mpi::reduce(world, data, data_reduced, std::plus<int>(), 0);
最重要的是,即使你的 mysum
是正确的传递给平原 C
MPI_Op_create()
,这也不是 boost::mpi
所期望的。