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 所期望的。