Ответ 1
Безопасность потоков в MPI не работает из коробки. Во-первых, вы должны убедиться, что ваша реализация фактически поддерживает несколько потоков, вызывающих вызовы MPI сразу. С некоторыми реализациями MPI, например Open MPI, это требует, чтобы библиотека была настроена со специальными параметрами во время сборки. Затем вы должны указать MPI для инициализации на соответствующем уровне поддержки потоков. В настоящее время стандарт MPI определяет четыре уровня поддержки потоков:
-
MPI_THREAD_SINGLE
- означает, что код пользователя является однопоточным. Это уровень по умолчанию, при котором MPI инициализируется, если используетсяMPI_Init()
; -
MPI_THREAD_FUNNELED
- означает, что код пользователя многопоточен, но только основной поток выполняет вызовы MPI. Основной поток - это тот, который инициализирует библиотеку MPI; -
MPI_THREAD_SERIALIZED
- означает, что код пользователя многопоточен, но вызовы в библиотеку MPI сериализуются; -
MPI_THREAD_MULTIPLE
- означает, что код пользователя многопоточен, и все потоки могут выполнять вызовы MPI в любое время без какой-либо синхронизации.
Чтобы инициализировать MPI с поддержкой потоков, нужно использовать MPI_Init_thread()
вместо MPI_Init()
:
int provided;
MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
if (provided < MPI_THREAD_MULTIPLE)
{
printf("ERROR: The MPI library does not have full thread support\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
Эквивалентный код с устаревшим (и удаленным из MPI-3) привязками С++:
int provided = MPI::Init_thread(argc, argv, MPI::THREAD_MULTIPLE);
if (provided < MPI::THREAD_MULTIPLE)
{
printf("ERROR: The MPI library does not have full thread support\n");
MPI::COMM_WORLD.Abort(1);
}
Уровни поддержки потоков упорядочены следующим образом: MPI_THREAD_SINGLE
< MPI_THREAD_FUNNELED
< MPI_THREAD_SERIALIZED
< MPI_THREAD_MULTIPLE
, поэтому любой другой предоставленный уровень, отличный от MPI_THREAD_MULTIPLE
, будет иметь меньшее числовое значение - поэтому код if (...)
, указанный выше, написан так.
MPI_Init(&argc, &argv)
эквивалентно MPI_Init_thread(&argc, &argv, MPI_THREAD_SINGLE, &provided)
. Реализации не требуются для инициализации точно на запрошенном уровне - скорее, они могут инициализироваться на любом другом уровне (выше или ниже), который возвращается в выходном аргументе provided
.
Для получения дополнительной информации см. §12.4 стандарта MPI, свободно доступный здесь.
С большинством реализаций MPI поддержка потоков на уровне MPI_THREAD_SINGLE
фактически эквивалентна поддержке на уровне MPI_THREAD_SERIALIZED
- именно то, что вы наблюдаете в своем случае.
Поскольку вы не указали, какую реализацию MPI вы используете, вот список удобных.
Я уже говорил, что Open MPI должен быть скомпилирован с соответствующими флагами, чтобы поддерживать MPI_THREAD_MULTIPLE
. Но есть еще один улов - компонент InfiniBand не является потокобезопасным, и поэтому Open MPI не будет использовать собственную связь InfiniBand при инициализации на уровне поддержки потоков.
Intel MPI поставляется в двух разных вариантах: один с одним и один без поддержки полного многопоточности. Поддержка многопоточности разрешена путем передачи опции -mt_mpi
в оболочку компилятора MPI, которая позволяет связывать с версией MT. Этот параметр также подразумевается, если включена поддержка OpenMP или включен автопараллелизатор. Я не знаю, как работает драйвер InfiniBand в IMPI, когда включена поддержка полного потока.
MPICH (2) не поддерживает InfiniBand, поэтому он является потокобезопасным, и, возможно, самые последние версии предоставляют поддержку MPI_THREAD_MULTIPLE
из коробки.
MVAPICH является основой, на которой построен Intel MPI, и поддерживает InfiniBand. Я понятия не имею, как он ведет себя на полном уровне поддержки потоков при использовании на машине с InfiniBand.
Заметка о многопоточной поддержке InfiniBand важна, поскольку в настоящее время множество вычислительных кластеров используют ткани InfiniBand. Когда компонент IB (openib
BTL в Open MPI) отключен, большинство реализаций MPI переключается на другой протокол, например TCP/IP (tcp
BTL в Open MPI), что приводит к значительно более медленной и более скрытой связи.