sep*_*cmk 2 parallel-processing pointers mpi virtual-address-space c++11
通过MPI传递函数指针作为告诉另一个节点调用函数的方法是否安全?有人可能会说通过MPI传递任何类型的指针都没有意义,但我写了一些代码来验证它.
//test.cpp
#include <cstdio>
#include <iostream>
#include <mpi.h>
#include <cstring>
using namespace std;
int f1(int a){return a + 1;}
int f2(int a){return a + 2;}
int f3(int a){return a + 3;}
using F=int (*)(int);
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
int rank, size;
MPI_Status state;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
//test
char data[10];
if( 0 == rank ){
*(reinterpret_cast<F*>(data))=&f2;
for(int i = 1 ; i < size ; ++i)
MPI_Send(data, 8, MPI_CHAR, i, 0, MPI_COMM_WORLD);
}else{
MPI_Recv(data, 8, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &state);
F* fp = reinterpret_cast<F*>(data);
int ans = (**fp)(10);
cout << ans << endl;
}
MPI_Finalize();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
12
12
12
12
12
12
12
12
12
Run Code Online (Sandbox Code Playgroud)
我通过MVAPICH运行它,它运行良好.但我现在不知道为什么因为单独的地址空间意味着指针值在除生成它之外的任何进程中都是USELESS.
PS这是我的主机文件
blade11:1
blade12:1
blade13:1
blade14:1
blade15:1
blade16:1
blade17:1
blade18:2
blade19:1
Run Code Online (Sandbox Code Playgroud)
然后我跑了mpiexec -n 10 -f hostfile ./test,用C++ 11编译了它
您很幸运,因为您的集群环境是同构的,并且没有适用于普通可执行文件的地址空间随机化.因此,所有图像都加载到相同的基址并在内存中类似地布局,因此函数在所有MPI等级中具有相同的虚拟地址(请注意,对于来自动态链接库的符号,这通常很少,因为这些符号通常在随机地址).
如果使用不同的编译器或使用相同的编译器但使用不同的编译器选项编译源两次,那么让一些排序运行第一个可执行文件而其余的运行第二个可执行文件,程序肯定会崩溃.
试试这个:
$ mpicxx -std=c++11 -O0 -o test_O0 test.cpp
$ mpicxx -std=c++11 -O2 -o test_O2 test.cpp
$ mpiexec -f hostfile -n 5 ./test_O0 : -n 5 ./test_O2
12
12
12
12
<crash>
Run Code Online (Sandbox Code Playgroud)
不同级别的优化导致不同大小的函数代码test_O0和test_O2.因此,f2将不再在所有等级中具有相同的虚拟地址.运行与0级相同的可执行文件的列将打印12,而其余的将是段错误.