亲宝软件园·资讯

展开

C++进程链接工具之通信器详解

无水先生 人气:0

一、传播者

本章中的所有示例仅使用一个连接所有进程的通信器。但是,可以创建更多的通信器来链接进程的子集。这对于不需要由所有进程执行的集体操作特别有用。

二、示例和代码

示例 47.15。使用多个通信器

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <string>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  boost::mpi::communicator local = world.split(world.rank() < 2 ? 99 : 100);
  std::string s;
  if (world.rank() == 0)
    s = "Hello, world!";
  boost::mpi::broadcast(local, s, 0);
  std::cout << world.rank() << ": " << s << '\n';
}

Example47.15

示例 47.15 使用函数 boost::mpi::broadcast()。此函数发送字符串“Hello, world!”从等级为 0 的进程到链接到本地​​通信器的所有进程。等级为 0 的进程也必须链接到该通信器。

本地通信器是通过调用 split() 创建的。 split() 是在全局通信器世界上调用的成员函数。 split() 需要一个整数来将进程链接在一起。将相同整数传递给 split() 的所有进程都链接到相同的通信器。传递给 split() 的整数值无关紧要。重要的是应该由特定通信器链接的所有进程都传递相同的值。

在示例 47.15 中,等级为 0 和 1 的两个进程将 99 传递给 split()。如果程序启动时有两个以上的进程,则额外的进程会传递 100。这意味着前两个进程有一个本地通信器,所有其他进程都有另一个本地通信器。每个进程都链接到 split() 返回的通信器。是否有其他进程链接到同一个通信器取决于其他进程是否将相同的整数传递给 split()。

请注意,等级始终与传播者有关。最低等级始终为 0。在示例 47.15 中,相对于全局通信器具有等级 0 的进程相对于其本地通信器也具有等级 0。相对于全局通信器具有等级 2 的进程相对于其本地通信器具有等级 0。

如果您使用两个或更多进程启动示例 47.15,您好,世界!将显示两次 - 每次由相对于全局通信器的等级为 0 和 1 的进程显示一次。因为 s 设置为“Hello, world!”仅在全局等级为 0 的进程中,此字符串仅通过通信器发送到链接到同一通信器的那些进程。这只是具有全局排名 1 的进程,这是唯一将 99 传递给 split() 的其他进程。

示例 47.16。使用组对流程进行分组

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <boost/range/irange.hpp>
#include <boost/optional.hpp>
#include <string>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  boost::mpi::group local = world.group();
  boost::integer_range<int> r = boost::irange(0, 1);
  boost::mpi::group subgroup = local.exclude(r.begin(), r.end());
  boost::mpi::communicator others{world, subgroup};
  std::string s;
  boost::optional<int> rank = subgroup.rank();
  if (rank)
  {
    if (rank == 0)
      s = "Hello, world!";
    boost::mpi::broadcast(others, s, 0);
  }
  std::cout << world.rank() << ": " << s << '\n';
}

MPI 支持分组进程。这是在类 boost::mpi::group 的帮助下完成的。如果您在通信器上调用成员函数 group(),则链接到通信器的所有进程都将在类型为 boost::mpi::group 的对象中返回。您不能使用此对象进行通信。它只能用于形成一组新的进程,然后可以从中创建通信器。

boost::mpi::group 提供成员函数,如 include() 和 exclude()。您传递迭代器以包含或排除进程。 include() 和 exclude() 返回一个类型为 boost::mpi::group 的新组。

示例 47.16 将两个迭代器传递给 exclude(),它们引用类型为 boost::integer_range 的对象。该对象表示一个整数范围。它是在函数 boost::irange() 的帮助下创建的,它需要一个下限和上限。上限是一个不属于该范围的整数。在此示例中,这意味着 r 仅包含整数 0。

调用 exclude() 会导致创建子组,其中包含除等级为 0 的进程之外的所有进程。然后使用该组创建一个新的通信器 others。这是通过将全局通信器世界和子组传递给 boost::mpi::communicator 的构造函数来完成的。

请注意,others 是一个 communicator,它在 rank 0 的进程中是空的。rank 0 的进程没有链接到这个 communicator,但是变量 others 仍然存在于这个进程中。您必须注意不要在此过程中使用其他人。示例 47.16 通过在子组上调用 rank() 来防止这种情况。成员函数在不属于该组的进程中返回一个类型为 boost::optional 的空对象。其他进程接收它们相对于该组的等级。

如果 rank() 返回排名并且没有类型为 boost::optional 的空对象,则调用 boost::mpi::broadcast()。等级为 0 的进程发送字符串“Hello, world!”链接到其他通信器的所有进程。请注意,等级是相对于那个传播者的。相对于其他进程排名为 0 的进程相对于全球通信者世界排名为 1。

如果您使用两个以上的进程运行示例 47.16,则全局等级大于 0 的所有进程都将显示 Hello, world!。

加载全部内容

相关教程
猜你喜欢
用户评论