这可能看起来微不足道,但实际上,在像MPI这样的分布式内存模型中,您所要求的内容非常复杂...
在共享内存环境中,例如OpenMP,可以通过定义一个由所有线程原子地递增的共享计数器来轻松解决这个问题,并在之后检查它的值是否与线程数相对应。如果是这样,那么就意味着所有线程都通过了该点,并且当前线程是最后一个,他将负责打印。
在分布式环境中,定义和更新这样的共享变量非常复杂,因为每个进程都可能在远程机器上运行。为了仍然允许这样做,MPI自MPI-2.0以来提出了内存窗口和单边通信。然而,即使有了这些,也无法正确地实现原子计数器递增并可靠地获取其值。只有MPI 3.0引入了MPI_Fetch_and_op()函数,才能实现这一点。以下是一个实现示例:
#include <mpi.h>
#include <iostream>
int main( int argc, char *argv[] ) {
MPI_Init( &argc, &argv);
int rank, size;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
int *addr = 0, winSz = 0;
if ( rank == 0 ) {
winSz = sizeof( int );
MPI_Alloc_mem( winSz, MPI_INFO_NULL, &addr );
*addr = 1;
}
MPI_Win win;
MPI_Win_create( addr, winSz, sizeof( int ), MPI_INFO_NULL, MPI_COMM_WORLD, &win );
int counter, one = 1;
MPI_Win_lock( MPI_LOCK_EXCLUSIVE, 0, 0, win );
MPI_Fetch_and_op( &one, &counter, MPI_INT, 0, 0, MPI_SUM, win );
MPI_Win_unlock( 0, win );
if ( counter == size ) {
std::cout << "Process #" << rank << " did the last update" << std::endl;
}
MPI_Win_free( &win );
if ( rank == 0 ) {
MPI_Free_mem( addr );
}
MPI_Finalize();
return 0;
}
您可以看到,对于这样一个微不足道的请求来说,这是相当冗长和复杂的。而且,这需要MPI 3.0支持。
不幸的是,Boost.MPI似乎是您的目标,但只“支持MPI 1.1中的大部分功能”。因此,如果您真的想要获得这个功能,您将不得不使用一些纯MPI编程。
std::cout
循环之后放置一个MPI_Barrier
,并在屏障之后立即使用if(rank == 0) { std::cout << std::endl; }
。只有在绝对必要时才这样做,因为不必要地引入同步块是确保代码不可扩展的好方法。 - R_Kapp