如何使用 C++ 仅为 Open/Microsoft MPI 中的某些进程创建临界区?
How to create a critical section only for some processes in Open/Microsoft MPI using C++?
我是 MPI 的新手,想知道如何为 运行 进程中的少数进程创建临界区。我知道我可以为所有进程创建一个这样的进程:
for (int i = 0; i < 1000; ++i)
{
MPI_Barrier(MPI_COMM_WORLD);
std::cout << "RANK " << rank << " PRINTS " << i << std::endl;
}
然而,如果至少有一个进程不会触发 MPI_Barrier(),这将不起作用。假设我这样做了:
if(rank > 0)
for (int i = 0; i < 1000; ++i)
{
MPI_Barrier(MPI_COMM_WORLD);
std::cout << "RANK " << rank << " PRINTS " << i << std::endl;
}
这会崩溃,因为第 0 个进程会跳过循环。那么我如何让所有其他进程同步打印并对第 0 个进程执行其他操作(假设所有打印结束时等待消息)?
正如 @Gilles Gouaillardet 指出的那样,您可以使用 MPI_Comm_split
创建一个没有等级 0 的通信器。 MPI_Barrier
可以用这个新的通信器调用同步其余进程。 Rank 0,完成它的操作后可以在 COMM_WORLD
上调用 barrier 并等待其余进程调用它。
其余进程,比如 1 到 N,可以通过使用 for loop
迭代 1
到 N
来顺序执行代码区域(顺便说一句,不是 MPI 方法)和一个 if
块,它基于 rank
和 MPI_Barrier
执行代码区域,如下例所示。
MPI_Comm_split(MPI_COMM_WORLD,color,key,newcomm) // create new comm without rank 0
if(rank>0) {
for (int i = 1; i < size; ++i)
{
if(rank == i) { // Critical region. Only one rank can enter here at a time. Here it enters sequentially from 0 to size
std::cout << "RANK " << rank << " PRINTS " << i << std::endl; // After calling Critical Session Part, call barrier to signal other processes.
MPI_Barrier(newcomm);
} else {
MPI_Barrier(newcomm); // all other proesses (except rank == i) should wait and do not enter the critical region
}
}
MPI_Barrier(MPI_COMM_WORLD);// This barrier will be called with rank 0
} else {
//do some work for rank 0
// wait for the rest of the processes
MPI_Barrier(MPI_COMM_WORLD);
}
另一种方法(无需创建新的通信器)是您可以使用环形发送消息(环形广播)的概念。
if (rank == 0) {
value = 1;
MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );
// Do something useful
}
else {
MPI_Recv( &value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,
&status );
if (rank < size - 1){
//criticalregion
MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );
}
}
MPI_Barrier(MPI_COMM_WORLD);
在这里,rank 0
将消息发送给 rank 1
,后者又发送给 rank 2
,依此类推。这样,进程收到消息后,可以顺序执行代码(临界区),然后将消息发送到更高级别并触发执行。
我是 MPI 的新手,想知道如何为 运行 进程中的少数进程创建临界区。我知道我可以为所有进程创建一个这样的进程:
for (int i = 0; i < 1000; ++i)
{
MPI_Barrier(MPI_COMM_WORLD);
std::cout << "RANK " << rank << " PRINTS " << i << std::endl;
}
然而,如果至少有一个进程不会触发 MPI_Barrier(),这将不起作用。假设我这样做了:
if(rank > 0)
for (int i = 0; i < 1000; ++i)
{
MPI_Barrier(MPI_COMM_WORLD);
std::cout << "RANK " << rank << " PRINTS " << i << std::endl;
}
这会崩溃,因为第 0 个进程会跳过循环。那么我如何让所有其他进程同步打印并对第 0 个进程执行其他操作(假设所有打印结束时等待消息)?
正如 @Gilles Gouaillardet 指出的那样,您可以使用 MPI_Comm_split
创建一个没有等级 0 的通信器。 MPI_Barrier
可以用这个新的通信器调用同步其余进程。 Rank 0,完成它的操作后可以在 COMM_WORLD
上调用 barrier 并等待其余进程调用它。
其余进程,比如 1 到 N,可以通过使用 for loop
迭代 1
到 N
来顺序执行代码区域(顺便说一句,不是 MPI 方法)和一个 if
块,它基于 rank
和 MPI_Barrier
执行代码区域,如下例所示。
MPI_Comm_split(MPI_COMM_WORLD,color,key,newcomm) // create new comm without rank 0
if(rank>0) {
for (int i = 1; i < size; ++i)
{
if(rank == i) { // Critical region. Only one rank can enter here at a time. Here it enters sequentially from 0 to size
std::cout << "RANK " << rank << " PRINTS " << i << std::endl; // After calling Critical Session Part, call barrier to signal other processes.
MPI_Barrier(newcomm);
} else {
MPI_Barrier(newcomm); // all other proesses (except rank == i) should wait and do not enter the critical region
}
}
MPI_Barrier(MPI_COMM_WORLD);// This barrier will be called with rank 0
} else {
//do some work for rank 0
// wait for the rest of the processes
MPI_Barrier(MPI_COMM_WORLD);
}
另一种方法(无需创建新的通信器)是您可以使用环形发送消息(环形广播)的概念。
if (rank == 0) {
value = 1;
MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );
// Do something useful
}
else {
MPI_Recv( &value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,
&status );
if (rank < size - 1){
//criticalregion
MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );
}
}
MPI_Barrier(MPI_COMM_WORLD);
在这里,rank 0
将消息发送给 rank 1
,后者又发送给 rank 2
,依此类推。这样,进程收到消息后,可以顺序执行代码(临界区),然后将消息发送到更高级别并触发执行。