MPI - использовать несколько потоков для прослушивания входящих сообщений

Я работаю над проектом, который использует процедуры MPI и несколько потоков для отправки и получения сообщений. Я хотел бы, чтобы каждый принимающий поток сосредоточился на другом входящем сообщении, а не на двух или более, пытающихся получить одно и то же. Есть ли способ добиться этого?

Я не знаю, помогает ли это, но в настоящее время я использую Iprobe() для проверки входящих сообщений и Irecv() с Test(), чтобы проверить, получил ли поток все сообщение.


person GeorgeG    schedule 21.08.2015    source источник


Ответы (2)


Начиная с версии 3 стандарта, MPI позволяет удалять совпадающие сообщения из очереди сообщений, чтобы они больше не были видны последующим запросам/получениям. Это делается с помощью так называемых совпадающих зондов. Просто замените MPI_Iprobe на MPI_Improbe, что является неблокирующей операцией сопоставленного зонда:

int flag;
MPI_Status status;
MPI_Message msg;

MPI_Improbe(source, tag, comm, &flag, &msg, &status);

Как только MPI_Improbe возвращает 1 в flag, приходит сообщение, соответствующее (source, tag, comm). Дескриптор сообщения сохраняется в msg, и сообщение удаляется из очереди. Последующие запросы или приемы с совпадающим триплетом (источник, тег, связь) — в том же потоке или в другом — не увидят это же сообщение снова и, следовательно, не будут мешать его приему потоком, который совпал с ним изначально.

Чтобы получить соответствующее сообщение, используйте MPI_Imrecv (или блокировку MPI_Mrecv):

MPI_Request req;
MPI_Imrecv(buffer, count, dtype, &msg, &req);
do
{
   ...
   MPI_Test(&req, &flag, &status);
}
while (!flag);

Версии MPI до 3.0 не предоставляют подобных функций. Но, если я вас правильно понял, вам нужно только гарантировать, что ни один соответствующий зонд не будет отправлен до того, как MPI_Irecv получит возможность удалить сообщение из очереди (что и предназначено для предотвращения совпадающего зонда + получения). Если вы исследуете основной поток, а затем отправляете сообщения в разные потоки, вы можете использовать семафор, чтобы отложить выполнение следующего зонда основным потоком до тех пор, пока рабочий не выдаст MPI_Irecv. Если у вас есть несколько потоков, выполняющих probe+receive, вы можете просто выполнить вызов MPI_Irecv в том же критическом разделе (или любом другом примитиве синхронизации, который вы используете для сериализации вызовов MPI в соответствии с требованиями MPI_THREAD_SERIALIZED) как MPI_Iprobe после того, как проверка завершится. успешный:

// Worker thread
CRITICAL(mpi)
{
  MPI_Iprobe(source, tag, comm, &flag, &status);
  if (flag)
    MPI_Irecv(buffer, count, dtype, status.MPI_SOURCE, status.MPI_TAG, comm, &req);
}

Замените нотацию CRITICAL(name) { ... } любыми примитивами, которые предоставляет ваша среда программирования.

person Hristo Iliev    schedule 21.08.2015
comment
Прошу прощения, потому что я думаю, что не очень ясно изложил свой вопрос. Отправляющие потоки не должны знать о количестве принимающих потоков или их идентификаторах в принимающем процессе. Ранга принимающего процесса должно быть достаточно. Что я действительно хочу, так это знать, есть ли способ для принимающих процессов определить, начал ли один из них получать входящее сообщение (что дает ему состояние занятости), чтобы остальные (которые находятся в свободном состоянии) могли справиться с остальные входящие сообщения. - person GeorgeG; 21.08.2015
comment
Кстати, я использую уровень поддержки MPI_THREAD_SERIALIZED, потому что я прочитал в документации OpenMPI, что MPI_THREAD_MULTIPLE не был тщательно протестирован, но спасибо за предложение. - person GeorgeG; 21.08.2015
comment
Понятно, тогда вам действительно следует использовать неблокирующие согласованные зонды MPI-3 (MPI_Improbe) в сочетании с (неблокирующими) согласованными приемами (MPI_(I)mrecv). Сопоставленные операции скрывают сообщение из очереди сообщений после того, как оно было сопоставлено. Я обновлю ответ соответственно. - person Hristo Iliev; 22.08.2015
comment
Спасибо, это должно быть именно то, что я искал. Да, пожалуйста, обновите свой ответ, чтобы я мог его принять. И еще: я могу использовать совпадающие операции, но вы сказали, что они были в MPI-3, и я хотел бы предоставить код, который работает и с предыдущими версиями. Знаете ли вы какие-либо способы достижения этого с помощью подпрограмм pre-MPI3? - person GeorgeG; 22.08.2015
comment
@GeorgeG, ну вот, я заменил весь ответ тем, что вам, вероятно, нужно. - person Hristo Iliev; 22.08.2015

Если я вас правильно понял, дело не в том, как вы получаете сообщения, а в том, как вы их отправляете. Как вы можете видеть ниже, функция MPI_Send имеет параметр destination, который определяет, в какой поток будет отправлено это сообщение.

MPI_Send(
    void* data,
    int count,
    MPI_Datatype datatype,
    int destination,
    int tag,
    MPI_Comm communicator)

Поэтому, если вы хотите, чтобы определенные потоки получали определенные сообщения, вы должны отправлять эти сообщения только этому потоку.

person Glapa    schedule 21.08.2015
comment
Но место назначения — это ранг процесса MPI для получения сообщения, а не потока в этом процессе, верно? - person GeorgeG; 21.08.2015
comment
Насколько помните, процессы MPI выполняются в одном потоке, если это возможно. Таким образом, в двухъядерной среде у вас будет два процесса в отдельных потоках. Проблема начинается, когда у вас больше процессов, чем потоков, и тогда некоторые из них будут совместно использовать потоки друг с другом. - person Glapa; 21.08.2015