В связанный вопрос Я узнал, что выполнение request = Isend(...); Recv(...); request.Wait();
является не гарантированно работать, как Isend
может ничего не делать, пока request.Wait()
отсюда тупик Recv(...)
(см. оригинальный вопрос для деталей).
Но что если Isend() / Wait()
выполняется в другом потоке, чем Recv
? Меня сейчас напрямую не интересуют гарантии безопасности по стандарту. Это связано с тем, что стандарт утверждает безопасность потоков, только если Init_thread
Метод вызывается и возвращает правильный уровень. С моей конфигурацией openMPI это не так. Однако я не вижу причины, по которой реализация фактически ограничивает вызовы только из потока, который вызвал Init_thread
(фактическое сравнение для идентификатора потока будет необходимо). Я рассуждаю так: если я сериализую все посылки и все записи, mpi никогда не сможет заметить, что я использую более одного потока.
Итак, мой упрощенный код такой:
#include <cassert>
#include <thread>
#include "mpi.h"
void send(int rank, int& item)
{
MPI::Request request = MPI::COMM_WORLD.Isend(&item, sizeof(int), MPI::BYTE, rank, 0);
request.Wait();
}
void recv(int rank, int& item)
{
MPI::COMM_WORLD.Recv(&item, sizeof(int), MPI::BYTE, rank, 0);
}
int main()
{
MPI::Init();
int ns[] = {-1, -1};
int rank = MPI::COMM_WORLD.Get_rank();
ns[rank] = rank;
auto t_0 = std::thread(send, 1 - rank, std::ref(ns[rank])); // send rank to partner (i.e. 1 - rank)
auto t_1 = std::thread(recv, 1 - rank, std::ref(ns[1 - rank])); // receive partner rank from partner
t_0.join();
t_1.join();
assert( ns[0] == 0 );
assert( ns[1] == 1 );
MPI::Finalize();
}
Объяснение кода: два потока выполняются на каждом процессоре. Один пытается Isend
некоторые данные для партнера и ждет, пока это не будет сделано, другой получает некоторые данные от партнера.
Вопрос: Могу ли я с уверенностью предположить, что большинство реализаций MPI не засоряют этот кусок кода?
(Отказ от ответственности: этот фрагмент кода не предназначен для того, чтобы быть исключительным или особенно красивым. Он предназначен только для демонстрационных целей)
Вопрос: Могу ли я с уверенностью предположить, что большинство реализаций MPI не засоряют этот кусок кода?
На практике — да, если вы добавляете синхронизацию (чего нет в вашем коде); в теории — нет. Хотя возможно, что некоторые реализации допускают сериализованные вызовы из разных потоков на MPI_THREAD_SINGLE
уровень (с таким открытым Open MPI — см. Вот), стандарт MPI требует, чтобы библиотека была инициализирована на MPI_THREAD_SERIALIZED
уровень. Если вы намереваетесь сделать ваше программное обеспечение переносимым и иметь возможность компилировать и корректно работать с другими реализациями MPI, вам не следует полагаться на какое-то конкретное поведение Open MPI.
Тем не менее, Open MPI может быть настроен для поддержки многопоточности (MPI_THREAD_MULTIPLE
) когда библиотека построена. По умолчанию поддержка MT не включено по причинам производительности. Вы можете проверить состояние вашей конкретной установки, используя ompi_info
:
$ ompi_info | grep MPI_THREAD_MULTIPLE
Thread support: poxis (MPI_THREAD_MULTIPLE: no, progress: no)
^^^^^^^^^^^^^^^^^^^^^^^
Эта конкретная сборка не поддерживает многопоточность и всегда возвращает MPI_THREAD_SINGLE
в provided
выходной аргумент MPI_Init_thread
,
Других решений пока нет …