В многопоточной среде MPI вызовы MPI должны быть защищены мьютексом (или другим механизмом блокировки потока), когда мы инициализируем MPI_Init_thread с MPI_THREAD_SERIALIZED (проверьте этот ответ ).Это не требуется для MPI_THREAD_MULTIPLE , но это поддерживается не всеми реализациями MPI.
Мой вопрос заключается в том, является ли блокировка абсолютно необходимой для некоторых функций MPI, особенно для MPI_Test , MPI_Wait и MPI_Get_count .Я знаю, что блокировка требуется для всех вызовов MPI "со связью" (например, MPI_Gather , MPI_Bcast , MPI_Send , MPI_Recv , MPI_Isend , MPI_Irecv и т. Д.), Но я подозреваю, что эта блокировка не требуется для других функций, таких как MPI_Get_count , то есть локальной функции.Мне нужно знать, требуется ли эта блокировка для таких функций, как MPI_Test , MPI_Wait , MPI_Get_count , MPI_Probe и MPI_Iprobe (я не знаю, какие из них являются локальными функциями, а какие нет).Эта зависимость блокировки определена в стандарте MPI или определяется реализацией?
Я занимаюсь разработкой библиотеки распараллеливания с неблокирующими вызовами MPI, смешанными с потоками C ++ 11, и мне нужно использовать MPI_THREAD_SERIALIZED для поддержки большинства реализаций MPI. MPI_THREAD_MULTIPLE также реализован (в большинстве случаев более высокая производительность) в библиотеке, но также требуется поддержка MPI_THREAD_SERIALIZED .
В следующем простом примере кода требуетсяблокировка перед вызовом MPI_Test ?
#include <mutex>
#include <vector>
#include <thread>
#include <iostream>
#include <mpi.h>
static std::mutex mutex;
const static int numThreads = 4;
static int rank;
static int nprocs;
static void rthread(const int thrId) {
int recv_buff[2];
int send_buff[2];
MPI_Request recv_request;
{
std::lock_guard<std::mutex> lck(mutex); // <-- this lock is required
MPI_Irecv(recv_buff, 2, MPI_INT, ((rank>0) ? rank-1 : nprocs-1), thrId, MPI_COMM_WORLD, &recv_request);
}
send_buff[0] = thrId;
send_buff[1] = rank;
{
std::lock_guard<std::mutex> lck(mutex); // <-- this lock is required
MPI_Send(send_buff, 2, MPI_BYTE, ((rank+1<nprocs) ? rank+1 : 0), thrId, MPI_COMM_WORLD);
}
int flag = 0;
while (!flag) {
std::lock_guard<std::mutex> lck(mutex); // <-- is this lock required?
MPI_Test(&recv_request, &flag, MPI_STATUS_IGNORE);
//... do other stuff
}
std::cout << "[Rank " << rank << "][Thread " << thrId << "] Received a msg from thread " << recv_buff[0] << " from rank " << recv_buff[1] << std::endl;
}
int main(int argc, char **argv) {
int provided;
MPI_Init_thread(&(argc), &(argv), MPI_THREAD_SERIALIZED, &provided);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
std::vector<std::thread> threads;
for(int threadId = 0; threadId < numThreads; threadId++) {
threads.push_back(std::thread(rthread, threadId));
}
for(int threadId = 0; threadId < numThreads; threadId++) {
threads[threadId].join();
}
MPI_Finalize();
}
В своих тестах я выполнил код без блокировок при вызовах MPI_Test и MPI_Get_count , ничегослучилось что-то плохое и производительность улучшилась, но я не знаю, нормально это или нет.