MPI_Barrier()是如何工作的?

MPI_Barrier()是如何工作的?,mpi,Mpi,我有以下代码: #include <cstdint> #include <mpi.h> #include <iostream> using namespace std; int main(int argc, char **argv) { MPI_Init(&argc, &argv); int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank ==

我有以下代码:

#include <cstdint>
#include <mpi.h>
#include <iostream>
using namespace std;

int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0)
        MPI_Barrier(MPI_COMM_WORLD);
    cout << "Some output\n";
    if (rank == 1)
        MPI_Barrier(MPI_COMM_WORLD);
    MPI_Barrier(MPI_COMM_WORLD);
    cout << "end\n";
    MPI_Finalize();
    return 0;
}
然而,当我以

mpiexec-n 3 MPI.exe

程序不能正常工作。我期望输出如下:

rank 3 - Some_output
rank 2 - Some output
rank 3 - End
rank 0 - Some output

在此步骤中,我希望程序停止。

您需要确保每个进程的屏障调用数相同。在您的特定情况下,当n=3时,您对秩0和秩1有两个屏障调用,但对秩2只有1个。程序将阻塞,直到秩2进程也达到障碍

以下是n=3时应发生的情况:

together:
    rank 0 will reach barrier 1 then block
    rank 1 will print "some output", reach barrier 2 then block
    rank 2 will print "some output", reach barrier 3 then block
together:
    rank 0 will print "some output", reach barrier 3 then block
    rank 1 will reach barrier 3 then block
    rank 2 will print "end" then hit finalize
让一个进程在finalize中,而其他进程被阻止将是未定义的行为


对n=2进行相同的分析:

together:
    rank 0 will reach barrier 1 then block
    rank 1 will print "some output", reach barrier 2 then block
together:
    rank 0 will print "some output", reach barrier 3 then block
    rank 1 will reach barrier 3 then block
together:
    rank 0 will print "end" then hit finalize
    rank 1 will print "end" then hit finalize
这表明输出应为:

some output
some output
end 
end
无论您得到什么:

some output
end 
some output
end
这与mpi基础设施如何缓存来自不同列组的标准输出的传输有关。如果我们引入延迟,使MPI决定应该收集结果,我们可以更好地看到行为:

#include <cstdint>
#include <unistd.h>
#include <mpi.h>
#include <iostream>
using namespace std;

int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        cout << rank << " Barrier 1\n" << flush;
        MPI_Barrier(MPI_COMM_WORLD);
    }
    cout << rank << " Some output \n" << flush;
    usleep(1000000);
    if (rank == 1) {
        cout << rank << " Barrier 2\n" << flush;
        MPI_Barrier(MPI_COMM_WORLD);
    }
    cout << rank << " Barrier 3\n" << flush;
    MPI_Barrier(MPI_COMM_WORLD);
    cout << rank << " end\n" << flush;
    usleep(1000000);
    MPI_Finalize();
    return 0;
}
或者,查看以下C++11代码中的时间戳:

#include <cstdint>
#include <chrono>
#include <mpi.h>
#include <iostream>
using namespace std;

inline unsigned long int time(void) { 
    return std::chrono::high_resolution_clock::now().time_since_epoch().count(); 
}

int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        MPI_Barrier(MPI_COMM_WORLD);
    }
    cout << rank << " " << time() << " Some output\n";
    if (rank == 1) {
        MPI_Barrier(MPI_COMM_WORLD);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    cout << rank << " " << time() << " end\n";
    MPI_Finalize();
    return 0;
}
按时间戳排序:

$ mpiexec -n 2 ./a.out 
1 1464100768220902046 Some output
0 1464100768220965374 Some output
1 1464100768221000693 end
0 1464100768221002105 end
结论是Barrier的行为符合预期,打印语句不一定会告诉您这一点


编辑:2016-05-24以显示程序行为的详细分析。

请将输出重新格式化为缩进块,以便更可读。可能重复:固定输出格式;更正了语法和单词选择。程序将阻塞,但为什么我没有从第3级输出?我希望排名3会打印“一些输出”,但这并没有发生。@van9petryk,我添加了一个更详细的分析。对于我的特定设置,在我点击Ctrl-C终止程序之前,它确实捕获了秩2的输出。如果您的mpi在等级2处于finalize且其他等级处于barrier时立即失败,则可能不需要收集等级2标准输出。
#include <cstdint>
#include <chrono>
#include <mpi.h>
#include <iostream>
using namespace std;

inline unsigned long int time(void) { 
    return std::chrono::high_resolution_clock::now().time_since_epoch().count(); 
}

int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        MPI_Barrier(MPI_COMM_WORLD);
    }
    cout << rank << " " << time() << " Some output\n";
    if (rank == 1) {
        MPI_Barrier(MPI_COMM_WORLD);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    cout << rank << " " << time() << " end\n";
    MPI_Finalize();
    return 0;
}
$ mpiexec -n 2 ./a.out 
0 1464100768220965374 Some output
0 1464100768221002105 end
1 1464100768220902046 Some output
1 1464100768221000693 end
$ mpiexec -n 2 ./a.out 
1 1464100768220902046 Some output
0 1464100768220965374 Some output
1 1464100768221000693 end
0 1464100768221002105 end