2

Безопасно ли передавать указатели функций через MPI как способ сообщить другому узлу о вызове функции? Кто-то может сказать, что передача каких-либо указателей через 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; 
} 

Вот результат:

12 
12 
12 
12 
12 
12 
12 
12 
12 

Я побежал через MVAPICH, и он работает хорошо. Но я просто не понимаю, почему, поскольку отдельные адресные пространства означают, что значение указателя БЕСПЛАТНО в любом процессе, отличном от того, который сгенерировал его.

P.S. вот мой hostfile

blade11:1 
blade12:1 
blade13:1 
blade14:1 
blade15:1 
blade16:1 
blade17:1 
blade18:2 
blade19:1 

и я побежал mpiexec -n 10 -f hostfile ./test, и он был скомпилирован с помощью C++ 11

ответ

7

Вам повезло в том смысле, что среда кластера является однородной и не адресным пространством рандомизации для обычных исполняемых файлов не находится в место. Как следствие, все изображения загружаются с одним базовым адресом и выкладываются аналогично в памяти, поэтому функции имеют одинаковые виртуальные адреса во всех ранги 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> 

Различные уровни результата оптимизации в коде функции разного размера в test_O0 и test_O2. Следовательно, f2 больше не будет иметь тот же виртуальный адрес во всех рядах. Ранги, которые запускают тот же исполняемый файл, что и ранг 0, будут печатать 12, а остальные будут segfault.

2

Безопасно ли передавать указатели функций через MPI как способ сообщить другому узлу о вызове функции?

Нет, это не так. Адресное пространство не разделяется между процессами.

Однако MPI процессы, которые являются результатом программ, построенных из того же источника, могут быть организованы для вызова конкретной функции при получении определенного сообщения:

char data = 0; 
MPI_Recv(data, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &state); 

if (data == 255) { 
    f2(10); /* and so forth */ 
} 
0

No.

Однако есть трюк с участием макросов, которые отображают определенную кодификацию функции локальному указателю/обратному вызову функции, который может быть распознан во всех процессах равномерно. Например, это используется в HPX http://stellar.cct.lsu.edu/files/hpx_0.9.5/html/HPX_PLAIN_ACTION.html для запуска функции через неоднородные системы.